OCI-Native Package Management
Introduction
For over thirty years, Linux distributions have followed a consistent architectural pattern: a central repository of packages managed by a dedicated tool such as APT (Debian/Ubuntu), DNF (Fedora/RHEL), or Pacman (Arch Linux). These tools download pre-compiled binaries from remote repositories, execute installation scripts with elevated privileges, and maintain mutable state on the target system about which packages are installed, what versions, and how they depend on one another.
StageX departs from this tradition entirely. Instead of RPM, Deb, or Pacman archives, StageX uses OCI (Open Container Initiative) container images as the native package format. Every package is an OCI image built FROM scratch, containing only the files it needs. Dependencies are resolved not through a package manager's dependency resolver, but through COPY --from=stagex/<dependency> . / directives in Containerfiles. The resulting image is identified by a cryptographic content hash (a SHA-256 digest), making every package instance immutable and verifiable by construction.
How Traditional Package Managers Work
Traditional package managers follow a pattern established in the early 1990s. A central repository hosts binary packages, each accompanied by metadata describing version, dependencies, conflicts, and maintainer information. When a user requests an installation, the package manager:
- Queries the repository index to resolve the dependency graph.
- Downloads the required binary packages and their dependencies.
- Executes pre-installation and post-installation scripts, often running as root.
- Extracts files into the system root, overwriting existing files as needed.
- Records the new state in a local database for future upgrade and removal operations.
This model introduces several security concerns:
Runtime script execution. Installation scripts run with full root privileges on the target system. A compromised package can execute arbitrary code during installation, modifying system configuration, creating user accounts, or installing additional malware. Debian's postinst scripts, RPM's %post and %pre scriptlets, and Arch's .install hooks all follow this pattern. The attack surface is substantial because these scripts are rarely audited at the level of the package source code.
Mutable system state. Traditional package managers maintain a mutable database of installed packages. This database can fall out of sync with the actual filesystem, require repair operations, and is itself a single point of failure. Rollback of a failed update is non-trivial: while some package managers support downgrades, the process is not atomic and can leave the system in an inconsistent state if interrupted.
Centralized trust in repositories. Users configure their package manager to trust one or more central repositories. While repositories often sign their package indexes with GPG keys, the signing model is typically single-key or single-server. A compromise of the signing infrastructure allows undetected distribution of malicious packages to every user. The Debian archive signing key, Fedora's per-release signing keys, and Arch's master signing keys are all examples of this single-point-of-failure pattern.
Network-dependent builds. Package builds in traditional distributions typically download dependencies from the network at build time. This introduces non-determinism (because upstream sources may change between builds) and creates an additional vector for dependency substitution attacks.
OCI-Native Architecture
StageX inverts the traditional model. Every package is an OCI image with the following properties:
FROM scratch base. Every StageX package image starts from the empty scratch base, meaning the final image contains only what is explicitly added. No shell, no package manager, no standard library unless required. A Rust HTTP server, for example, produces a final image of approximately 3 MB containing only the statically linked binary.
COPY --from= dependency composition. Instead of apt install libssl-dev, a StageX package that needs OpenSSL includes COPY --from=stagex/core-openssl . / in its Containerfile. This copies the entire OpenSSL image contents into the build environment. BuildKit handles the dependency resolution at build time by fetching the dependency's OCI layout from the local output directory.
Immutable layers. Each StageX package produces an OCI image manifest with a content-addressable digest (SHA-256). The digest uniquely and permanently identifies that specific binary artifact. Any change to the package source, dependency version, or build configuration produces a different digest. Users pin to specific digests for cryptographically verifiable, immutable references.
No runtime scripts. The build process -- compilation, dependency resolution, composition -- happens entirely during the image build. The resulting image is a static artifact that requires no further processing. Installation (image pull + extraction) involves no script execution on the target system, eliminating an entire class of supply chain attack.
Standardized distribution. Because StageX packages are OCI images, they can be distributed through any OCI-compliant registry: Docker Hub, Quay.io, or self-hosted registries. The same tooling -- Docker, Podman, containerd, skopeo -- used for application containers also handles package distribution. StageX publishes to both docker.io/stagex and quay.io/stagex.
Benefits Over Traditional Package Managers
Immutability and atomic upgrades. An OCI image digest identifies a specific, immutable artifact. Upgrading means pulling a new digest and atomically switching to it. Rollback means switching back to a previous digest. No half-installed states, no database corruption, no script failures. This is the same operational model that containerized workloads have used in production for years.
Content-addressable storage. Because every image is identified by its digest, substitution attacks are structurally impossible. An attacker cannot replace docker.io/stagex/pallet-rust@sha256:abc with a different binary and claim it is the same image -- the digest verification would fail. Compare this to traditional package managers, where a compromised repository could serve a different binary for the same version string (e.g., libssl_3.0.2-1_amd64.deb), and the user would have no cryptographic proof of the discrepancy unless they independently verified the package checksum.
No runtime script execution. As noted above, traditional package managers execute installation scripts with elevated privileges. OCI-native packaging eliminates this entirely. The image is built once, signed, and verified. At consumption time, the runtime extracts layers and configures the filesystem -- nothing more.
Standardized distribution tooling. The OCI specification is supported by every major container runtime: Docker, Podman, containerd, Buildah, Kaniko. StageX images work across all of them without modification. Traditional package formats (RPM, Deb) require distribution-specific tools and cannot be used with container orchestrators without additional tooling. As the whitepaper notes, "OCI-compliant runtimes such as Docker, Podman, and containerd each implement the specification with different architectural choices and security tradeoffs," providing runtime diversity that reduces the likelihood of shared vulnerabilities.
Runtime diversity. Because the OCI specification provides a standard interface, the same StageX image runs on Docker's centralized daemon, Podman's daemonless rootless model, and containerd's lightweight CRI runtime. Organizations can choose the runtime that best fits their threat model without changing their base images. A vulnerability in one runtime's isolation logic does not compromise the entire infrastructure when images are verified and deployed across multiple runtimes simultaneously.
Trade-offs and Limitations
No dynamic dependency resolution. Traditional package managers resolve the full dependency graph at install time, automatically handling transitive dependencies, version conflicts, and upgrade paths. StageX's OCI-native model resolves dependencies at build time. To update a dependency, the consuming package must be rebuilt against the new dependency image. This is by design -- it ensures that every artifact is a complete, self-describing unit with pinned dependencies. However, it does shift complexity from the package manager to the build system, and organizations accustomed to apt-get upgrade automatically resolving all transitive updates must adapt their workflows.
Per-image storage overhead. Each package carries its dependencies in its layer chain. While shared layers between images are cached and deduplicated by OCI runtimes, the total storage footprint of maintaining independent images for every package can be larger than a traditional shared-library model. In practice, the caching layer mitigates this significantly: if one hundred packages all depend on stagex/core-openssl, that image's layers are stored once and referenced by digest.
Steeper learning curve. The traditional package manager workflow -- apt install <package> -- is deeply familiar to system administrators. Replacing it with OCI tooling (podman pull, docker build, COPY --from= syntax) requires learning new primitives. StageX's build system (Makefile + Containerfiles + package.toml) is intentionally minimal, but it does not abstract away the underlying OCI concepts.
Smaller package ecosystem. StageX deliberately limits its package count (approximately 478 at the time of the whitepaper) to maintain the feasibility of enforcing full-source bootstrapping, mandatory reproducibility, and multi-party signing across every package. General-purpose distributions ship tens of thousands of packages. Organizations requiring niche or proprietary software may need to package it themselves or use StageX as a build base rather than a complete application platform.
Comparison: OCI-Native vs Traditional Package Management
| Dimension | OCI-Native (StageX) | Traditional (APT/DNF/Pacman) |
|---|---|---|
| Package format | OCI image (manifest + layers) | RPM / Deb / Pacman archive |
| Dependency model | Build-time via COPY --from= |
Install-time via resolver |
| Update mechanism | Atomic: pull new digest | Mutable: upgrade individual packages |
| Identity | Content-addressable digest | Version string + architecture |
| Installation scripts | None (pre-built image) | Pre/post install scripts (root) |
| Rollback | Atomic: switch digest | Non-atomic: downgrade packages |
| Distribution | OCI registry (Docker, Quay) | Distribution-specific repositories |
| Runtime requirements | OCI runtime (Docker, Podman, containerd) | Distribution-specific tools |
| Reproducibility guarantee | Digest pinning + rewrite-timestamp |
Varies by distribution |
| Attack surface at install | Image pull + layer extraction | Script execution + file manipulation |
| Trust model | Multi-sig on image digests | Single-key on repository index |
See Also
- Glossary: OCI-native definition -- terminology and related entries
- Containerfile Syntax -- build recipe patterns
- OCI Integration Guide -- practical usage with Docker, Podman, Kubernetes
- Add a Package -- how packages are defined and built
- Reproducible Builds -- how OCI-native packaging enables reproducibility