Skip to content

Project Configuration and Dependency Freezing

CYPT71 edited this page Aug 9, 2026 · 1 revision

Project configuration and dependency freezing

secure-oci discovers a declarative project manifest, freezes dependencies, creates an OCI image, and runs it as a hardened container or a microVM.

Quick start

Add .config_image.yaml, .config_image.yml, .config_img.yaml, .config_img.yml, .config_image.json, or .config_img.json, then run:

secure-oci project show
secure-oci freeze
secure-oci project build
secure-oci project run

Commands accept --config FILE and an optional starting directory. Automatic discovery walks upward and stops at the nearest supported manifest.

Manifest

version: 1
language: python
runtime: .secure-oci/deps/python/bin/python
artifact: app.py
image: example/api
tag: v1
platform: linux/amd64
entrypoint: /app/.secure-oci/deps/python/bin/python
args: [/app/app.py]
isolation: container       # container or microvm
runtime_engine: podman     # docker or podman
network: bridge
ports:
  - 127.0.0.1:8080:8080
env:
  APP_ENV: production
user: "65532:65532"
shared_deps:
  - source: Shared_deps
    destination: /app/shared_deps

Defaults are linux/amd64, container, docker, network: none, .secure-oci/image, and the project directory name as image name. Unknown fields, unsupported platforms, unsafe destinations and multiple YAML documents are rejected.

include_project defaults to true for interpreted runtimes and false for go, compiled, and custom. Extra content can be selected explicitly:

include:
  - source: config/production.json
    destination: /app/config.json

Symbolic links and special files are rejected. Files are streamed by the OCI builder, keeping memory bounded for very large dependency trees.

Shared dependencies

A root directory named shared_deps, Shared_deps, or shared-deps is automatically copied to /app/shared_deps. Explicit shared_deps entries can add several trees or choose other absolute destinations. Duplicate image destinations fail closed.

Language adapters

Language Freeze operation
Go module tidy and vendor
Node.js / JavaScript / TypeScript lock generation when needed, then npm ci
Python install into .secure-oci/deps/python, then generate requirements.lock
Java Maven or Gradle dependency preparation/locking
.NET / C# / F# locked restore
Rust Cargo lock and locked fetch
Ruby Bundler lock and cache
PHP Composer production install
compiled no package-manager step

Any other language/package manager uses explicit argument arrays; no shell is implicitly invoked:

language: custom
artifact: dist/service
freeze_command: [my-package-manager, lock, --frozen]
build_command: [my-build-tool, build, --release]
include:
  - source: vendor
    destination: /app/vendor

This supports any language able to emit a deterministic artifact or vendored dependency tree. After freezing, .secure-oci/freeze.lock.json records path, size, and SHA-256 for every selected file. The lock excludes itself and is stable across identical runs.

Container and microVM execution

For isolation: container, project run uses Docker or Podman, the hardened defaults, configured networking and every port. It transparently loads a local OCI layout when the runtime does not already contain it.

For isolation: microvm, the same command invokes the microVM lifecycle with the layout and configured ports. See MicroVM Support.

The runtime and libraries of a dynamically linked interpreter must be selected for the image. Freeze in a controlled Linux environment matching platform; macOS package-manager output is not a Linux runtime dependency set.

Clone this wiki locally