Skip to content

Architecture Decision Records

CYPT71 edited this page Aug 9, 2026 · 1 revision

Architecture Decision Records

Status: accepted. Last review: 2026-07-27. Owners: repository maintainers.

This page is the decision log for choices that materially affect security, portability, operability, or backwards compatibility. A change that reverses one of these decisions must update this page in the same pull request.

The proposed post-v1 direction is documented separately in Next-generation Architecture. Its components remain proposals until accepted by a numbered ADR and supported by code, tests, compatibility evidence and a security review.

ADR-001 — Emit OCI Image Layout directly

Decision. cmd/oci-builder writes OCI Image Layout 1.0 structures and content-addressed blobs directly, using the Go standard library.

Context. The project needs deterministic packaging without requiring a daemon or privileged socket. Calling Docker/BuildKit would expand the trusted computing base, couple builds to host configuration, and make byte-level reproducibility harder to reason about.

Consequences. Generation is daemonless, portable, auditable, and has no third-party Go dependency. The project intentionally does not interpret a Dockerfile, contact registries, produce multi-layer images, or implement every OCI extension. Registry publication remains a separate CI stage.

ADR-002 — One deterministic gzip-compressed tar layer

Decision. The payload is a single tar layer with normalized ordering, ownership, modes, timestamps, gzip header fields, and a fixed default created value.

Alternatives considered. Multiple semantic layers, zstd, and preserving host metadata. They were rejected because they add state, tool compatibility risk, or nondeterministic host input without improving this project's single-binary use case.

Consequences. Identical inputs produce identical layout bytes. Updating a large binary rewrites the whole layer, so registry delta efficiency is lower than a carefully layered application image.

ADR-003 — Minimal non-root runtime contract

Decision. The image config declares UID/GID 65532:65532, a single entrypoint, no shell, and only explicit payload files. Writable /tmp and /var/tmp mount points exist, but runtime hardening is external.

Consequences. Attack surface and accidental credential inclusion are reduced. Debugging uses ephemeral containers or nsenter. Consumers must enforce read-only root filesystems, capability dropping, seccomp, and allowPrivilegeEscalation: false; OCI image metadata cannot enforce them.

ADR-004 — Atomic, fail-closed output

Decision. Existing outputs are never overwritten. The builder writes a fresh sibling temporary directory, validates the operation, then atomically renames it into place. Unsafe paths, duplicates, non-regular inputs, and unsupported platforms fail closed.

Consequences. A failed build cannot masquerade as a complete layout. Callers must allocate a new destination or explicitly remove an old one.

ADR-005 — SHA-256 content addressing and independent verification

Decision. All blobs use SHA-256 descriptors. CI and runtime consumers use the independent Python verifier rather than trusting only the producer.

Consequences. Corruption and descriptor substitution are detectable. SHA-256 is fixed by the supported compatibility profile; algorithm agility would require a format and verifier change.

ADR-006 — Publication, signing, and admission are separate trust stages

Decision. Layout generation has no registry credentials. GitHub Actions publishes immutable digests to GHCR, uses GitHub OIDC for keyless Cosign signing, and Kubernetes admission independently verifies signer identity.

Consequences. Compromise of the builder alone cannot publish. The release and E2E workflows need narrowly scoped packages: write and id-token: write. Availability depends on GitHub, GHCR, Fulcio, Rekor, and the admission controller; production needs an outage policy.

ADR-007 — Compatibility and performance are evidence, not assertions

Decision. CI exercises Docker, containerd, and Skopeo and publishes raw compatibility evidence. Benchmarks run five samples for 1 KiB, 1 MiB, and 16 MiB payloads and publish raw, JSON, and Markdown artifacts.

Consequences. Regressions are inspectable and comparable on equivalent runners. GitHub-hosted timing is noisy, so measurements are not a latency SLA and compatibility claims apply only to tool versions recorded by the run.

Decision review checklist

  1. Does the change expand the trusted computing base or network access?
  2. Does it alter deterministic bytes, OCI media types, or runtime identity?
  3. Does it require a migration for existing consumers?
  4. Are negative tests, compatibility evidence, and residual risks updated?
  5. Can permissions be narrower, and is rollback documented?

Clone this wiki locally