Pular para conteúdo

AUR-359 — Fixar trust root do runner OCI

Documento histórico do board. Pode descrever componentes removidos; para uso atual, consulte o guia do produto.

Purpose

Pins the trust root of the OCI runner used by the board's temporary shell bootstrap: the exact digest of the pinned base image, the exact digest of .board/bin/oci-run itself, and the hardened container flags every future consumer of the trust-root-docker-v1 profile must reproduce byte-for-byte. tests/acceptance/AUR-359.sh verifies all four artifacts independently of .board/bin/oci-run — the card's own accept line runs a direct, digest-pinned docker run, never the wrapper it authorizes.

Artifacts and schema

.board/bootstrap/locks/trust-root.yml

Flat key: value document, LC_ALL=C, one pair per line, 0 < size <= 4096 bytes. Exactly these 12 keys, each declared once:

Key Value
schema bootstrap-lock-v1
card AUR-359
runner_script .board/bin/oci-run
runner_script_sha256 sha256:<64 hex> — recomputed SHA-256 of .board/bin/oci-run
runner_image bash@sha256:ae4668c2560999e65e89532cd2ad1b6688bb23298189f0bd229ef80fa4bd0831
profile_user 65532:65532
profile_network none
profile_read_only_rootfs true
profile_cap_drop ALL
profile_no_new_privileges true
engine_docker observed — Docker 29.6.1 was observed in this workspace
engine_podman not-observed — Podman is not installed; no Podman verdict is emitted

.board/oci/profiles/trust-root-docker-v1.json

Flat JSON container profile using the same 24-key schema .board/bin/oci-run's own resolve_profile requires of any registered profile (schema, version, profile, lock, lock_digest, network, user, cap_drop, cap_add, mounts, devices, pull, tmpfs, read_only_rootfs, no_new_privileges, privileged, timeout_seconds, memory_mb, cpu_millis, pids_limit, tmpfs_mb, stdout_limit_bytes, stderr_limit_bytes, max_input_files, max_input_bytes). Its hardening fields are identical to the flags in the card's accept vector: network=none, user=65532:65532, cap_drop=ALL, read_only_rootfs=true, no_new_privileges=true, privileged=false, memory_mb=128, cpu_millis=500 (--cpus=0.5), pids_limit=64. lock points at the file below by its repository-relative path; lock_digest is the recomputed SHA-256 of that file's content, never a value trusted from the file itself.

.board/locks/oci/trust-root-docker-v1.lock.json

Flat JSON image lock: schema (aurum.oci-image-lock), version (1), profile (trust-root-docker-v1), image (bash@sha256:ae4668c2560999e65e89532cd2ad1b6688bb23298189f0bd229ef80fa4bd0831). image must match ^[a-z0-9][a-z0-9._/-]*@sha256:[0-9a-f]{64}$ — a bare tag or a mutable reference (bash:latest) is refused before any other check.

Both JSON documents are registered exactly as .board/bin/oci-run expects, so a future card that runs ./.board/bin/oci-run --profile trust-root-docker-v1 --card <id> resolves the same profile this card seals — but this card's own accept never depends on that wrapper, which is the point: fixing the trust root cannot depend on the thing it authorizes.

Bounds

Bound Value
Lock/profile/oci-lock document size 4096 bytes
tests/bootstrap/locks/AUR-359/cases.tsv size 4 MiB
cases.tsv rows 256
Acceptance container wall-clock (accept vector, informational) 15 s

Codes

Typed dispositions this card's acceptance program can emit on stderr as AUR-359/AC-001/<code> (exit 1, behavioral) or AUR-359/AC-001/inconclusive/<reason> (exit 79, environment):

Code Trigger
trust_root_mismatch An owned artifact (lock, runner, profile, or oci lock) is absent, or a checked value diverges from the pinned trust root.
source_integrity_error An owned artifact is a symlink, or otherwise not a plain regular file.
invalid_lock_or_manifest An owned document is empty, malformed, missing a required field, or its declared lock_digest diverges from the recomputed content digest of the file it binds to.
input_limit_exceeded An owned document exceeds 4096 bytes.
runner_missing .board/bin/oci-run is absent (a trust_root_mismatch specialization, named separately because it identifies which artifact is missing).
runner-digest-mismatch The lock's runner_script_sha256 diverges from the recomputed SHA-256 of .board/bin/oci-run (MUT-001).
image_digest_mismatch The lock does not contain the pinned bash@sha256:... reference.
egress-guard-missing profile_network/network is not none, or read_only_rootfs is not true (MUT-002).
mutable-image The oci lock's image is not pinned by an immutable digest (MUT-003).
mutable_reference The trust-root lock itself contains a latest/branch-style reference.
fixture_sensitivity_error This program's own fixture self-test (cases.tsv) observed a disposition other than what the sealed row declares — the verifier failed to discriminate a known mutant.

Diagnostic example (synthetic)

$ ./.board/bin/oci-run --profile trust-root-docker-v1 --card AUR-999   # illustrative only
oci-run: profile trust-root-docker-v1 declares network as none, cap_drop as ALL, ...
$ docker run --rm --network=none --read-only --cap-drop=ALL \
    --security-opt=no-new-privileges --pids-limit=64 --memory=128m --cpus=0.5 \
    --user=65532:65532 -v "$PWD":/src:ro \
    bash@sha256:ae4668c2560999e65e89532cd2ad1b6688bb23298189f0bd229ef80fa4bd0831 \
    /src/tests/acceptance/AUR-359.sh
{"card":"AUR-359","scenario":"AC-001","selector":"AC-001","fixture_cases":5,"result":"pass"}

An absent lock instead produces, on stderr, exit 1:

AUR-359/AC-001/trust_root_mismatch
AUR-359/AC-001/detail expected-artifact=.board/bootstrap/locks/trust-root.yml

Offline OCI command

This is exactly the card's accept: line — a direct, digest-pinned docker run, reproducible offline once the bash@sha256:... image is present in the local image cache (no registry pull is attempted; the profile declares "pull": "never"):

docker run --rm --network=none --read-only --cap-drop=ALL \
  --security-opt=no-new-privileges --pids-limit=64 --memory=128m --cpus=0.5 \
  --user=65532:65532 -v "${PWD}":/src:ro \
  bash@sha256:ae4668c2560999e65e89532cd2ad1b6688bb23298189f0bd229ef80fa4bd0831 \
  /src/tests/acceptance/AUR-359.sh

Why the accept vector bypasses .board/bin/oci-run

.board/bin/oci-run resolves a profile's image digest from .board/locks/oci/<name>.lock.json — the very file this card produces. A card that fixes the trust root cannot prove that root by first trusting the wrapper the root is meant to authorize; a bug in oci-run's own resolve_profile could otherwise mask a divergence in the thing under test. The accept line therefore invokes Docker directly with the identical hardened flags the trust-root-docker-v1 profile declares, and tests/acceptance/AUR-359.sh re-implements the profile/lock parsing independently rather than sourcing or exec'ing oci-run.