Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Trusted Build Inputs

This inventory covers the build inputs currently trusted by the capOS boot image, generated bindings, host tooling, and verification paths. It started as the Security Verification Track S.10.0 inventory, records the Security Verification Track S.10.2 generated-code drift check, and now also records the Security Verification Track S.10.3 dependency policy plus the shared no_std generated-code patch helper. The consolidated long-horizon supply-chain risk view – floating Rust nightly, repo-pinned qemu-system-x86_64 / xorriso digests (CI now apt-installs qemu-system-x86=1:8.2.2+ds-0ubuntu1.16, xorriso=1:1.5.6-1.1ubuntu3, and ovmf=2024.02-2ubuntu0.8 so package identity is captured; the OVMF firmware blob is now repo-pinned by SHA-256 (OVMF_CODE_SHA256, landed at commit f1c8c8fb, merged at ca5a1fea) and the ovmf-verify Makefile gate fails the build on drift, but download-and-verify of the qemu-system-x86_64 / xorriso tool blobs remains a future step), PR-blocking CI environment provenance comparison, and the remaining immutable-runner-image / repo-managed tool-digest gap – is tracked as R13 in docs/design-risks-register.md; the gap text below stays consistent with that entry.

Summary

InputCurrent sourcePinning statusDrift-review status
Limine bootloader binariesMakefile:5-10, Makefile:34-49Git commit and selected binary SHA-256 values are pinned.make limine-verify fails if the checked-out commit or copied bootloader artifacts drift.
Rust toolchainrust-toolchain.toml:1-4, .github/workflows/ci.ymlDate-pinned nightly-2026-04-20 channel with target triples and the rust-src component required by custom-target -Zbuild-std userspace builds. The CI host-baseline, dma-assurance-models, and qemu-smoke jobs explicitly request the same dated nightly. The Kani job remains pinned separately to nightly-2025-11-21 paired with the Kani-compatible bundle installed by cargo kani setup.The dated channel resolves to rustc 1.97.0-nightly (e22c616e4 2026-04-19) (the 2026-04-20 manifest carries the previous day’s rustc commit). Bumps are review-visible as rust-toolchain.toml and workflow diffs; the advance procedure is recorded in the Rust Toolchain section below.
Workspace cargo dependenciesCargo.toml, crate Cargo.toml files, Cargo.lockLockfile pins exact crate versions and checksums for the root workspace. Manifest requirements remain semver ranges.make dependency-policy-check runs cargo deny check plus cargo audit against the root workspace and lockfile in CI.
Standalone cargo dependencies (covered by make dependency-policy-check)init/Cargo.lock, demos/Cargo.lock, demos/wasi-hello-rust/Cargo.lock, demos/wasi-cli-args/Cargo.lock, demos/wasi-env/Cargo.lock, demos/wasi-fs/Cargo.lock, demos/wasi-random/Cargo.lock, demos/wasi-preview1-refusals/Cargo.lock, demos/wasi-stdio-fd/Cargo.lock, tools/adventure-content-gen/Cargo.lock, tools/paperclips-content-gen/Cargo.lock, tools/mkmanifest/Cargo.lock, tools/remote-session-client/Cargo.lock, tools/ringtap-viewer/Cargo.lock, capos-rt/Cargo.lock, capos-service/Cargo.lock, shell/Cargo.lock, libcapos/Cargo.lock, libcapos-posix/Cargo.lock, capos-wasm/Cargo.lock, fuzz/Cargo.lockEach standalone workspace has its own lockfile. The Makefile DEPENDENCY_POLICY_MANIFESTS / DEPENDENCY_POLICY_LOCKFILES lists drive the gate.make dependency-policy-check runs the shared deny/audit baseline against every standalone manifest and lockfile listed above (root workspace Cargo.lock plus the 21 standalone lockfiles in this row). Cross-workspace version drift remains review-visible and intentional where lockfiles differ.
Standalone cargo dependencies (not yet under policy gates)tools/remote-session-client/src-tauri/Cargo.lock, vendor/wasmi-no_std/wasmi-1.0.9/Cargo.lockTwo checked-in lockfiles fall outside DEPENDENCY_POLICY_LOCKFILES. tools/remote-session-client/src-tauri/Cargo.lock is the Tauri scaffold lockfile; make remote-session-tauri only exposes deterministic policy and check modes and reviewed dev mode – distributable package and desktop automation modes are blocked. vendor/wasmi-no_std/wasmi-1.0.9/Cargo.lock is part of the vendored upstream snapshot covered separately by the wasmi =1.0.9 path-dependency pin in capos-wasm/Cargo.toml.Both lockfiles are review-visible through ordinary diffs but are not run through cargo deny check / cargo audit today. Promoting either into DEPENDENCY_POLICY_LOCKFILES is gated on the matching authority decision (Tauri scaffold scope decision; wasmi refresh procedure in vendor/wasmi-no_std/VENDORED_FROM.md).
Cap’n Proto compilerMakefile:12-80, tools/capnp-build/src/lib.rs, capos-config/build.rs, tools/check-generated-capnp.sh, tools/mkmanifest/src/lib.rs, tools/mkmanifest/src/main.rsOfficial capnproto-c++-1.2.0.tar.gz source tarball URL, version, and SHA-256 are pinned in Makefile; make capnp-ensure builds $(CAPOS_TOOLS_ROOT)/capnp/1.2.0/bin/capnp under the per-user tool cache so linked worktrees reuse it. The build rule patches the distributed CLI version placeholder to the pinned version before compiling.The shared build helper defaults to the pinned path and rejects CAPOS_CAPNP when it points elsewhere. Make targets export the pinned path and CI persists it through $GITHUB_ENV. make generated-code-check verifies both the exact compiler path and Cap'n Proto version 1.2.0 before regenerating bindings through Cargo. mkmanifest cue-to-capnp also rejects missing or non-canonical CAPOS_CAPNP, checks Cap'n Proto version 1.2.0, and delegates schema-aware JSON-to-binary conversion to that pinned compiler.
Cap’n Proto Rust runtime/codegen cratescapos-config/Cargo.toml, kernel/Cargo.toml, tools/capnp-build/Cargo.toml, Cargo.lockCargo manifests use exact capnp = "=0.25.4" and capnpc = "=0.25.3" requirements where declared; lockfiles pin exact crate versions and checksums.Security Verification Track S.10.3 now requires dependency-class and no_std review before these changes are accepted.
Kani verifier toolchain.github/workflows/ci.yml, Makefile, tools/run-kani-proofs.sh, tools/cloudbuild-kani.yaml, .gcloudignoreGitHub CI pins kani-verifier 0.67.0; cargo kani setup installs the matching Kani bundle plus nightly-2025-11-21-x86_64-unknown-linux-gnu into the user-local Kani/rustup paths. Local make kani-lib and make kani-dma-authority expect a compatible cargo-kani install. The high-memory make kani-lib-full path uses Google Cloud Build image digest rust@sha256:adab7941580c74513aa3347f2d2a1f975498280743d29ec62978ba12e3540d3a on E2_HIGHCPU_32, installs rustup from https://sh.rustup.rs, sources /usr/local/cargo/env, initializes minimal git metadata for build tooling that expects a repository, then pins nightly-2025-11-21 plus cargo-kani 0.67.0.The CI kani-proofs job installs kani-verifier 0.67.0, runs cargo kani setup, and executes the bounded make kani-lib harness list plus the DMA-authority make kani-dma-authority harness group. The Cloud Build config installs the same Kani version and runs make kani-lib-full; it depends on explicit source staging and logs in maintainer-private GCS buckets configured in tools/cloudbuild-kani.yaml, .gcloudignore secret exclusions, and account/project IAM for Cloud Build submission and the selected runtime service account. Version, image, worker, bucket, IAM, rustup bootstrap, synthetic git metadata, or setup-path changes are review-visible in the workflow, Cloud Build config, runner script, and this inventory.
Alloy Analyzer (DMA assurance model checker)Makefile ALLOY_VERSION/ALLOY_TARBALL_URL/ALLOY_TARBALL_SHA256, tools/run-dma-alloy-model.sh, models/dma/dma_authority.alsSelf-contained linux/amd64 Alloy Analyzer 6.2.0 app image (bundled Temurin JRE + native SAT solvers) pinned by SHA-256; make alloy-ensure downloads and verifies it into $(CAPOS_TOOLS_ROOT)/alloy/6.2.0/ (the jar is not vendored). This slice owns the Alloy pin shared with the scheduler lease model track.make model-dma-alloy verifies the tarball SHA-256, checks the launcher reports version 6.2.0, and runs the relational authority-graph checks/witnesses headless at scope for 4, failing on any counterexample or analyzer error. GitHub CI runs it in the dma-assurance-models job.
TLC model checker (DMA assurance lifecycle model)Makefile TLA_TOOLS_VERSION/TLA_TOOLS_JAR_URL/TLA_TOOLS_JAR_SHA256/TLA_JRE_URL/TLA_JRE_SHA256, tools/run-dma-tla-model.sh, models/dma/dma_authority.tlatla2tools.jar 1.7.4 (TLC 2.19) pinned by SHA-256 plus a SHA-256-pinned Temurin JRE 17.0.19+10 (the bare jar needs a JVM, unlike the self-contained Alloy app image); make tla-ensure downloads and verifies both into $(CAPOS_TOOLS_ROOT)/tla/ (neither is vendored). This slice owns the TLC pin shared by the scheduler/IRQ TLA+ model tracks.make model-dma-tla re-verifies the jar SHA-256 and the pinned JRE version, then runs TLC over the bounded .cfg (2 devices / 2 domains / 2 pages / 2 iovas, generations 0..1), failing closed on any invariant violation, deadlock, or analyzer error (exit code and the “No error” marker are both asserted). GitHub CI runs it in the dma-assurance-models job.
Generated capnp bindingscapos-config/src/lib.rs:10-12, tools/generated/capos_capnp.rs, tools/check-generated-capnp.shGenerated into Cargo OUT_DIR; the expected patched output is checked in under tools/generated/.make generated-code-check regenerates the canonical capos-config output and fails if that output differs from the checked-in baseline or if kernel-generated output reappears.
no_std patching of generated bindingstools/capnp-build/src/lib.rs, capos-config/build.rs, tools/check-generated-capnp.shOne shared build-support crate asserts the patch anchor and injects the no_std imports after generation. capos-config/build.rs calls that helper as the single schema binding owner.make generated-code-check verifies the patched output contains the expected no_std imports and matches the checked-in baseline.
Generated adventure contentdemos/adventure-content/content/prototype.cue, tools/adventure-content-gen/, demos/adventure-content/src/generated.rs, tools/check-generated-adventure-content.shPrototype mission content is authored in checked-in CUE and generated by a standalone locked Cargo host tool into a checked-in no_std Rust content blob. The checker requires the pinned CUE path under $(CAPOS_TOOLS_ROOT) and cue version v0.16.0.make generated-code-check runs generated-adventure-content-check, which exports the CUE source as JSON, runs tools/adventure-content-gen with cargo run --locked, formats the generated output, and fails on drift from the checked-in baseline.
Generated Paperclips contentdemos/paperclips-content/content/paperclips.cue, schema/paperclips-content.capnp, tools/paperclips-content-gen/, demos/paperclips-content/src/generated.rs, tools/check-generated-paperclips-content.shPaperclips game content is authored in checked-in CUE, schema-validated through the typed PaperclipsContent Cap’n Proto root, and generated by a standalone locked Cargo host tool into checked-in typed Cap’n Proto bytes embedded by a no_std Rust wrapper. The checker requires the pinned CUE path under $(CAPOS_TOOLS_ROOT), cue version v0.16.0, and the pinned Cap’n Proto compiler path/version used for schema-aware conversion.make generated-code-check runs generated-paperclips-content-check, which exports the CUE source as JSON, converts it through mkmanifest cue-to-capnp against schema/paperclips-content.capnp, runs tools/paperclips-content-gen with cargo run --locked, formats the generated output, and fails on drift from the checked-in generated content.
Userspace custom targettargets/x86_64-unknown-capos.json, .cargo/config.toml, Makefile, system*.cueSource-controlled target specification plus Cargo aliases, Makefile build wrappers, and manifest paths for booted init, demos, shell, and capos-rt runtime builds. The target JSON uses Rust nightly custom-target support and builds core,alloc from rust-src.make init-capos-build demos-capos-build shell-capos-build capos-rt-capos-build verifies the userspace crates against target_os = "capos"; QEMU smokes embed target/x86_64-unknown-capos/release userspace artifacts.
Userspace runtime surface checktools/check-userspace-runtime-surface.shSource-controlled script that treats capos-rt as the only owner of _start, panic, allocator, raw syscall, and entry-point macro definitions.Run directly when runtime or userspace entry code changes; it is not a QEMU transcript assertion and does not live inline in Makefile.
Linker script build scriptskernel/build.rs, init/build.rs, demos/*/build.rs, capos-rt/build.rs, capos-wasm/build.rsSource-controlled scripts and linker scripts. capos-rt/build.rs emits the runtime linker script for both the legacy target_os = "none" userspace build path and the booted custom target_os = "capos" path. capos-wasm/build.rs mirrors the same pattern for the wasm-host bin (Phase W.2 onward) and uses cargo:rustc-link-arg-bins so the linker script applies only to the bin and not the lib.Build rerun boundaries are explicit; generated link args are not independently audited.
CUE manifest compilerMakefile CUE_TARBALL_URL/CUE_TARBALL_SHA256, tools/mkmanifest/src/main.rs, tools/mkmanifest/src/lib.rs, .github/workflows/ci.ymlmake cue-ensure downloads the official cue_v0.16.0_linux_amd64.tar.gz release binary, verifies its SHA-256, extracts cue into $(CAPOS_TOOLS_ROOT)/cue/0.16.0/bin/cue, and checks the reported version – the same download-and-verify pattern used for Typst and uv. CAPOS_TOOLS_ROOT defaults to $HOME/.capos-tools (per-user shared cache); operators may override it explicitly. This replaces the prior go install cuelang.org/go/cmd/cue, which compiled from source under a floating Go toolchain rather than verifying a pinned binary by hash.Make exports CAPOS_CUE and CAPOS_TOOLS_ROOT to tools/mkmanifest, and CI records that exact path through $GITHUB_ENV before both the host-baseline cargo test-mkmanifest gate and QEMU smoke. mkmanifest::expected_cue_path derives the same per-user path, rejects missing or non-canonical CAPOS_CUE, and checks cue version v0.16.0 before export. The same path and version checks now gate both boot-manifest compilation and mkmanifest cue-to-capnp data-message conversion.
Default boot manifest defaults packagecue/defaults/defaults.cue, cue.mod/module.cue, system.cue, tools/mkmanifest/src/lib.rscue/defaults/defaults.cue declares package defaults and exports #DefaultSystem, the shared scaffold for the default boot manifest. cue.mod/module.cue pins module: "capos.local" with language v0.16.0. system.cue imports the defaults via capos.local/cue/defaults, declares package capos, and mkmanifest --package capos system.cue manifest.bin exports the unified package.make invokes mkmanifest with --package capos only when MANIFEST_SOURCE is system.cue; focused-proof system-*.cue manifests stay in single-file mode. The defaults package is a manifest-rule prerequisite, so edits trigger rebuilds.
Operator overlay surfacesystem.local.cue.example, system.local.cue (gitignored), .gitignoreThe repo-root overlay file is system.local.cue (package capos); system.local.cue.example is the committed worked-example template. CUE’s package mode unifies it with system.cue automatically.Operators copy the example, edit, and rebuild — system.local.cue is a wildcard-resolved manifest-rule prerequisite. The overlay is gitignored explicitly to avoid accidental commits of host-specific keys or principals.
Host-user manifest tagMakefile, system.cue _user @tag(user) / _displayName @tag(displayName), tools/mkmanifest/src/lib.rs cue_export_args / cue_tags_from_env_values, target/.cue-tags.<manifest>make run sets CAPOS_CUE_USER=$(USER). mkmanifest reads that structured account variable, derives displayName from the same account’s first GECOS/comment field in /etc/passwd when CAPOS_CUE_DISPLAY_NAME is unset, and falls back to the account name when the passwd comment is unavailable. It also reads generic CAPOS_CUE_TAGS (and --tag key=value CLI repeats) and forwards each entry to cue export --inject; structured CAPOS_CUE_USER / CAPOS_CUE_DISPLAY_NAME override duplicate generic keys. The target/.cue-tags.<manifest-bin> sentinel records the active tag state via a FORCE-prereq rule that touches the file only when content differs, so a tag change invalidates the cached manifest.bin; the recipe reads exported environment values at shell runtime rather than splicing tag text into shell syntax.The injected user value reaches the manifest via system.cue’s _user: string | *"operator" @tag(user) and surfaces as the default local operator seed account name; displayName reaches the seed account display name. Untagged system.cue keeps the operator account-name/display-name defaults, while focused demo and smoke manifests pin their own demo fixtures.
mdBook documentation toolsMakefile, book.tomlGitHub release assets for mdBook v0.5.0 and mdbook-mermaid v0.17.0 are pinned by version and SHA-256 under $(CAPOS_TOOLS_ROOT), which defaults to $HOME/.capos-tools. mdbook-mermaid supplies the pinned mermaid.min.js browser bundle used by both mdBook HTML rendering and docs-PDF Mermaid rasterization.make docs and make cloudflare-pages-build verify the tarball checksums and executable versions, refresh the Mermaid assets, and build target/docs-site.
Typst typesetter (paper and docs PDF builds)Makefile TYPST_VERSION, papers/schema-as-abi/main.typ, docs/manual.typGitHub release asset for Typst v0.14.2 is pinned by version and SHA-256 under $(CAPOS_TOOLS_ROOT)/typst/0.14.2, mirroring the mdBook pinning pattern. typst-ensure verifies the tarball checksum and the binary’s reported version before paper and docs-PDF targets invoke it. Bundled New Computer Modern font keeps builds reproducible across hosts.make paper rebuilds target/papers/schema-as-abi/main.pdf using the pinned Typst binary; make cloudflare-pages-build additionally publishes the PDF as target/docs-site/papers/schema-as-abi.pdf. make docs also uses Typst to compile the generated system manual PDF from docs/manual.typ plus per-page converted Markdown body content. Generated PDFs are not checked in; source main.typ, references.bib, docs/manual.typ, and documentation inputs are checked in.
Documentation PDF converterMakefile UV_VERSION / MD2TYPST_VERSION, .node-version, package.json, package-lock.json, tools/md2typst-constraints.txt, tools/docs-bundle.js, tools/build-typst-manual.js, tools/mermaid-puppeteer-config.json, docs/manual.typ, docs/manual-overrides/*.typGitHub release asset for uv 0.11.8 (uv-x86_64-unknown-linux-gnu.tar.gz) is pinned by version and SHA-256 under $(CAPOS_TOOLS_ROOT)/uv/0.11.8. uv-ensure verifies the tarball checksum and the binary’s reported version before PDF generation. uv tool run --constraints tools/md2typst-constraints.txt --from md2typst==0.3.3 md2typst pins the Markdown-to-Typst converter and its Python dependency set. Node version 22.16.0 is declared by .node-version and package.json; the current Makefile invokes node and npm from PATH, so host Node selection remains an operator/CI environment responsibility. package-lock.json pins @mermaid-js/mermaid-cli and its Puppeteer dependency tree; make mermaid-cli-ensure runs npm ci --ignore-scripts with PUPPETEER_SKIP_DOWNLOAD=1, so Puppeteer’s install script cannot fetch a browser during dependency installation. Mermaid rasterization uses the explicit MERMAID_BROWSER_BIN Chromium/Chrome executable, passes it to Puppeteer as PUPPETEER_EXECUTABLE_PATH, and renders PDF diagrams at MERMAID_PDF_SCALE=3 by default; tools/mermaid-puppeteer-config.json disables the browser sandbox for local and gVisor build containers. tools/docs-bundle.js reads the explicit manual page list from docs/manual.typ, generates target/docs-bundle/manual.md plus one Markdown file per manual page, and docs/manual.typ owns the PDF title page, contents, page order, page styling, and override placeholders.make docs-pdf converts each generated manual Markdown page to Typst with md2typst, normalizes anchors and links with tools/build-typst-manual.js, uses any matching checked-in docs/manual-overrides/<page-id>.typ instead of the generated page, rasterizes Mermaid diagrams through the explicit browser executable, and compiles target/docs-bundle/manual.pdf with pinned Typst. make docs copies that generated PDF to target/docs-site/manual.pdf for Cloudflare Pages publication. Generated Markdown, Typst body pages, and PDF files are ignored build artifacts, not tracked source.
QEMU and firmwareMakefile:85-96, tools/build-provenance.sh, .github/workflows/ci.yml qemu-smokeThe qemu-smoke CI job installs qemu-system-x86=1:8.2.2+ds-0ubuntu1.16 (amd64, noble-updates/main or noble-security/main, Ubuntu 24.04) and ovmf=2024.02-2ubuntu0.8 (amd64, noble-updates/main, Ubuntu 24.04). OVMF delivers /usr/share/ovmf/OVMF.fd – the first entry in the Makefile’s OVMF_CODE_CANDIDATES list, so the wildcard discovery resolves to that path on the pinned runner. The Makefile now also pins the selected OVMF firmware blob by SHA-256 (OVMF_CODE_SHA256) and gates the ISO and cloud-disk rules on ovmf-verify, which fails on hash drift and emits a NOTICE skip when no OVMF candidate is installed. Local boot verification still uses the host-installed qemu-system-x86_64.make build-provenance records the current QEMU version, selected executable path, package identity when discoverable, OVMF selected path or explicit absence, OVMF package identity when discoverable, and OVMF firmware hash when the configured firmware path exists. QEMU and OVMF are identified on the CI runner by package name, exact version, architecture, normalized apt source pocket, and selected path; the QEMU binary identity is captured via dpkg-query/apt-cache policy by make build-provenance per run and the OVMF firmware-blob SHA-256 is captured the same way. make ovmf-verify fails the build when the on-host OVMF firmware blob does not match the pinned OVMF_CODE_SHA256.
ISO and host filesystem toolsMakefile:317-341, tools/build-provenance.sh, .github/workflows/ci.yml qemu-smokeThe qemu-smoke CI job installs xorriso=1:1.5.6-1.1ubuntu3 (amd64, noble/main, Ubuntu 24.04), make=4.3-4.1build2 (amd64, noble/main, Ubuntu 24.04), and git=1:2.43.0-1ubuntu7.3 (amd64, noble-updates/main or noble-security/main, Ubuntu 24.04). Local builds still use host-installed xorriso, sha256sum, git, make, and shell utilities.make build-provenance records selected executable paths and package identities when discoverable for xorriso, sha256sum, make, git, and related local build tools, plus final ISO hashes. xorriso, make, and git are identified on the CI runner by package name, exact version, architecture, normalized apt source pocket, and selected path; the per-run identity is captured via dpkg-query/apt-cache policy by make build-provenance. The remaining host tools, including sha256sum, shell, build-essential, and curl, remain host-provided or package-observed rather than repo-digest-pinned.
Boot manifest and embedded binariessystem.cue:1-144, tools/mkmanifest/src/lib.rs:339-379, tools/mkmanifest/src/main.rs, tools/build-provenance.sh, tools/compare-build-provenance.py, Makefile:168-169, Makefile:332-341Source manifest is checked in; embedded ELF payloads are build artifacts or inline manifest bytes.Manifest validation checks references and path containment. make build-provenance now writes a local provenance record with runner OS/kernel/architecture identity, Rust toolchain details, selected host-tool paths and package identities when discoverable, hashes for the selected manifest, ISO, kernel, OVMF firmware when present, and every embedded binary reported by mkmanifest --print-binaries, including file-backed and inline payloads. make build-provenance-compare compares two retained records for material drift while ignoring generated timestamp and allowed local target/ or .capos-tools/ path-root movement.
Vendored upstream snapshotsvendor/wasmi-no_std/, vendor/dns-c-wahern/, vendor/fatfs-no_std/, vendor/rustls-webpki/, vendor/webpki-roots/, vendor/embedded-tls/, each with a VENDORED_FROM.mdEach vendored tree is a static, pinned snapshot recorded by version/tag, commit SHA when available, commit date when available, vendoring date, and license. vendor/wasmi-no_std/wasmi-1.0.9/ pins wasmi v1.0.9 (commit 61ba65e6563d8b2f5b699b018349d3330b28b9f3, Apache-2.0 OR MIT) consumed by capos-wasm/; vendor/dns-c-wahern/src/ pins William Ahern’s dns.c rel-20160808 (commit 4ec718a77633c5a02fb77883387d1e7604750251, MIT). vendor/rustls-webpki/rustls-webpki-0.103.13/ pins rustls-webpki 0.103.13 (artifact SHA-256 61c429a8…f756e, commit 2879b2ce…728e86, ISC) and vendor/webpki-roots/webpki-roots-1.0.7/ pins webpki-roots 1.0.7 (artifact SHA-256 52f5ee44…2eb9d, commit be948464…221688, CDLA-Permissive-2.0); both are the certificates/TLS Phase-1 verifier deps consumed by the capos-tls/ Phase-1 verifier crate. vendor/embedded-tls/embedded-tls-0.19.0/ pins the embedded-tls 0.19.0 crates.io package (embedded VCS commit 865e1fd983c583228e3bbeb9f4996f1abc454ca3, Apache-2.0) consumed only by the local TLS client handshake smoke. No source patches (one integration-only empty-[workspace] marker per crate); each path dep carries an exact version = "=X.Y.Z" pin so cargo-deny’s wildcards gate stays happy.The wasmi snapshot is exercised by make capos-wasm-build and the WASI smokes plus make dependency-policy-check (cargo-deny + cargo-audit against capos-wasm/Cargo.lock). The rustls-webpki / webpki-roots snapshots are exercised by capos-tls/ under cargo build / cargo build --features qemu (bare-metal x86_64-unknown-none) and by make dependency-policy-check against the root Cargo.lock. The embedded-tls snapshot is exercised by make run-cloud-tls-client-handshake, the focused capOS demo build, and make dependency-policy-check against demos/Cargo.lock. The dns.c snapshot is not yet on the v0 build path; demos/posix-dns-resolver/ compiles only main.c with a commented-out dns.h include. Refreshes follow the procedure recorded in each VENDORED_FROM.md. No vendor/dash/ source-build is present.
Build downloadsMakefile, Cargo lockfiles, rust-toolchain.tomlLimine, CUE, and documentation tool tarballs are explicitly fetched and SHA-256-verified; Cargo and rustup downloads are implicit when caches/toolchains are absent. The build no longer uses a Go toolchain: CUE is now a hash-verified release binary rather than a go install compile, so the actions/setup-go CI step and the floating go-version pin were removed.Limine artifacts, the CUE release binary, and documentation tool tarballs are verified by SHA-256. Cargo downloads rely on upstream tooling and lockfiles, with no separate repo policy beyond the lockfile checksums. Rustup downloads are now gated by the dated nightly-2026-04-20 channel pin (see Rust Toolchain section); only the dist tarballs themselves are not yet mirrored.
GitHub Actions identities and runner OS.github/workflows/ci.ymlEvery third-party Action is pinned by 40-character commit SHA with a trailing # v<X.Y.Z> comment marker. The runner OS is pinned to ubuntu-24.04 rather than the floating ubuntu-latest label.Pin bumps are review-visible as workflow diffs and the trailing version comment makes the intended release auditable. See the GitHub Actions Runner and Workflow Pinning section below for the current pin table and the bump procedure.

Security Verification Track S.10.3 Dependency Policy

Dependency changes are accepted only if they satisfy this policy and are recorded in the owning task checklist.

Dependency classes

Use these classes when reviewing a dependency change:

  • Kernel-critical no_std: crates used directly by kernel, capos-lib, capos-config, and capos-abi.
  • Userspace-runtime no_std: crates used by init, demos, and capos-rt.
  • Host/build: crates used by tools/*, build.rs helpers, and generated output pipelines.
  • Test/fuzz/dev: crates gated by dev-dependencies or target-specific for fuzz/proptests/smoke support.

Required pre-merge criteria

For any added dependency (or bump in any class):

  1. Manifest and features are explicit. Dependency entries must include explicit feature choices; avoid default-features = true unless justified.
  2. No_std compatibility is proven for no_std classes. Kernel-critical and userspace-runtime dependencies must compile in a #![no_std] mode with alloc where expected. cargo build -p <crate> --target x86_64-unknown-none must succeed for every kernel/no_std crate affected.
  3. Security policy checks run and pass. CI-equivalent checks for the touched workspace are required through make dependency-policy-check, which runs cargo deny check on every Cargo manifest and cargo audit on every lockfile.
  4. Dependency class change is justified in review. PR text must include target class, ownership rationale, transitive graph impact, and why the crate is not a transitive replacement for an already-allowed dependency.
  5. Lockfile behavior is explicit. Update only intended lockfiles and record intentional cross-workspace drift in this document if workspace purpose differs.

No_std add/edit checklist

  • Reject crates that require std, OS I/O, or unsupported platform APIs in the dependency path intended for kernel classes.
  • Reject dependencies that re-export broad platform facades or large unsafe surface unless there is a replacement with smaller scope and better audit visibility.
  • Record a license and supply-chain review result (via policy checks) before merge.
  • Confirm no unsafe contract escapes are added without a review surface note in the relevant module.

Standing requirements

  • Add Security Verification Track S.10.3 checks to the target branch plan item for any kernel/no_std crate dependency change and document the exact pass command set.
  • Keep lockfile deltas review-visible in normal PR flow; lockfile pinning is the minimum bar, not the gate.
  • Keep transitive drift in sync with the trust class: class-wide divergence across lockfiles requires explicit justification.

Remaining gaps after Security Verification Track S.10.3 policy

  • Mirror the resolved dated nightly dist tarballs (and their SHA-256 checksums) into the per-user tool cache as a further hardening step, so bumping the pin does not depend on rustup retaining its historical manifests. The dated pin closes the floating-channel gap; tarball mirroring would close the historical-availability gap.
  • Decide whether the local make kani-lib workflow should grow a repo-managed installer/bootstrap helper or continue to rely on separately provisioned user-local cargo-kani plus the Kani bundle/toolchain setup path.
  • CI now publishes target/build-provenance.txt as a named artifact on every qemu-smoke run (see actions/upload-artifact step in .github/workflows/ci.yml) and, on pull_request events, downloads the most recent successful main-branch artifact via actions/download-artifact and runs make build-provenance-compare BUILD_PROVENANCE_COMPARE_POLICY=ci-environment against it as a blocking PR gate. Missing base provenance is a CI failure, not a silent skip; artifact retention is therefore part of the gate.

Build Provenance Retention And Comparison Policy

Status 2026-06-07 06:35 UTC: this policy applies to local and CI proof artifacts produced by make build-provenance. The qemu-smoke CI job now publishes the candidate record as a named artifact on every run and, on pull_request events, runs make build-provenance-compare against the most recent successful main-branch artifact with BUILD_PROVENANCE_COMPARE_POLICY=ci-environment. That CI policy is PR-blocking for runner, tool, Rust, OVMF package, and OVMF hash drift while allowing expected base-vs-head source commit, ISO/kernel/manifest hash, and embedded-payload hash differences. This remains a reproducibility evidence policy, not a claim that production images are third-party reproducible before the unresolved pinning gates below are closed.

Package-pin bumps for qemu-system-x86, xorriso, make, git, or ovmf are the only planned baseline-refresh case where the PR comparison can fail on purpose: the candidate provenance records the new reviewed package identity, while the base-branch artifact still records the old one. That failure is not a green PR exception and is not a workflow bypass. The bump can land only through a reviewed local-main integration or maintainer push path after the branch’s qemu-smoke build, make run-smoke, and make build-provenance steps pass with the new pins, and the compare diff contains only the reviewed package-identity changes introduced by the same branch. After the bump lands, the next successful main-branch qemu-smoke push artifact becomes the refreshed base provenance; unrelated PRs must wait for that artifact before their blocking environment comparisons can pass.

For every externally cited QEMU proof, release candidate, paper artifact, or public performance/security claim, retain the following as one immutable evidence bundle:

  • target/build-provenance.txt from the exact checked commit, manifest, and recorded worktree state;
  • the kernel, manifest, ISO, OVMF firmware if used, and embedded-binary hashes recorded in that provenance file;
  • the exact command set and QEMU transcript or host-test log used as evidence;
  • the source commit hash, clean-tree assertion or retained git diff plus untracked-file inventory, and any non-default Make variables such as MANIFEST_SOURCE, CAPOS_CUE_TAGS, QEMU_NET, MERMAID_BROWSER_BIN, or CAPOS_TOOLS_ROOT;
  • the system.local.cue overlay state for default-manifest builds: record explicit absence, or retain the file content plus SHA-256 and size. Because the overlay is gitignored and unified into system.cue, a commit hash alone is not enough to reconstruct a default-manifest build that used it;
  • the runner identity: either a pinned CI/container image digest, or the host package identities for Rust, QEMU, xorriso, make, git, OVMF firmware package, and the operating-system image when the runner is not pinned.

Retention requirements:

  • Keep evidence bundles for any tagged release, published paper result, public benchmark, or public security claim for at least the lifetime of that claim.
  • Keep pre-merge task evidence until the reviewed branch has merged and the next full relevant verification has superseded it.
  • Keep failed evidence when it explains a known regression, review finding, or release blocker; otherwise failed local scratch logs may be discarded.
  • Do not rely on target/ as the retention store. target/ artifacts are local build output; retained evidence must be copied to the release, CI, or paper artifact store that owns the claim.

Comparison requirements:

  • Run local comparisons with make build-provenance-compare BASE_PROVENANCE=... CANDIDATE_PROVENANCE=... or tools/compare-build-provenance.py BASE CANDIDATE. The command exits zero only when records differ by generated timestamp and allowed local path roots such as worktree target/ or .capos-tools/, while all hashes, versions, package identities, and runner identities match.
  • Run PR base-vs-head environment comparisons with make build-provenance-compare BUILD_PROVENANCE_COMPARE_POLICY=ci-environment BASE_PROVENANCE=... CANDIDATE_PROVENANCE=.... This policy compares the default manifest source, host target, runner identity, GitHub-hosted image identity when present, Rust toolchain, selected executable identities, tool versions, OVMF selection, and OVMF hash, but ignores expected source commit, kernel/manifest/ISO hash, and embedded-binary hash changes between the base branch and PR head.
  • For package-pin bump branches, treat a ci-environment comparison failure as acceptable review evidence only when every reported difference is an intended package-identity change for qemu-system-x86, xorriso, make, git, or ovmf from the same branch. Any runner image, Rust toolchain, OVMF firmware hash, tool-version, or unrelated package drift remains blocking.
  • Compare two provenance records by commit, clean or retained-diff state, system.local.cue absence/hash/content policy, manifest source, manifest binary hash, kernel hash, ISO hash, embedded-binary table, OVMF hash or explicit absence, host-tool versions, package identities, and operating-system image identity.
  • A byte-identical ISO requires all recorded hashes to match. Equal source commits with different Rust, QEMU, xorriso, OVMF, or host package identities are compatible proof reruns, not reproducible-production evidence.
  • If a comparison differs only in paths under .capos-tools or worktree-local target/ directories while all hashes and versions match, treat the result as the same proof environment.
  • If a comparison differs in worktree state, overlay state, package identity, operating-system image identity, host-tool version, OVMF hash, Rust compiler commit/date, embedded-binary hash, or ISO hash, record the difference in the owning review or release note before citing the result.

Minimum runner identity for production-hardening branches:

  • Rust must be a date-pinned nightly or stronger hash-pinned toolchain, not the floating nightly channel.
  • QEMU, xorriso, make, and git must come from a pinned runner image digest or a documented package set with package name, version, architecture, repository, and distribution release.
  • OVMF firmware must be either repo-pinned by digest or identified by package name, version, architecture, repository, distribution release, selected path, and SHA-256.
  • Any runner image used for production reproducibility claims must be cited by immutable digest. Mutable tags are acceptable only for local proof evidence.

Production hardening must treat the following as unresolved supply-chain gates, not as cosmetic reproducibility work:

immutable runner image digest or repo-managed tool digests for qemu/xorriso/make/git

The Rust nightly date pin (currently nightly-2026-04-20) closes the floating-channel gate; tarball mirroring is tracked as a further hardening step in the Remaining gaps section above. The qemu-smoke job now installs qemu-system-x86=1:8.2.2+ds-0ubuntu1.16 (amd64, noble-updates/main or noble-security/main, Ubuntu 24.04), xorriso=1:1.5.6-1.1ubuntu3 (amd64, noble/main, Ubuntu 24.04), make=4.3-4.1build2 (amd64, noble/main, Ubuntu 24.04), git=1:2.43.0-1ubuntu7.3 (amd64, noble-updates/main or noble-security/main, Ubuntu 24.04), and ovmf=2024.02-2ubuntu0.8 (amd64, noble-updates/main, Ubuntu 24.04) so the QEMU, ISO writer, make, git, and OVMF firmware identities are all captured for UEFI smoke builds: package name, exact version, architecture, normalized apt source pocket, and the per-run identity captured via dpkg-query/apt-cache policy by make build-provenance. OVMF additionally records the selected path (/usr/share/ovmf/OVMF.fd) and per-run SHA-256, and the Makefile now pins the selected firmware blob by SHA-256 through the ovmf-verify gate wired into the ISO and cloud-disk rules. Repo-pinned digests (download-and-verify rather than apt-installed) for qemu-system-x86, xorriso, make, and git, or an immutable runner image digest that contains them, remain future hardening tracked in docs/design-risks-register.md (R13). xorriso has no version in noble-updates; the pin uses the only available noble/main version, which is what every Ubuntu 24.04 host resolves to.

Until those gates land, generated ISO/manifest/payload artifacts plus target/build-provenance.txt are suitable for local and CI proof evidence, but not for claims that a third party can reproduce an identical production boot image from source alone.

Bootloader and ISO Inputs

The Makefile now pins Limine at commit aad3edd370955449717a334f0289dee10e2c5f01 and verifies these copied artifacts:

ArtifactChecksum reference
$(LIMINE_DIR)/limine-bios.sysLIMINE_BIOS_SYS_SHA256 in Makefile
$(LIMINE_DIR)/limine-bios-cd.binLIMINE_BIOS_CD_SHA256 in Makefile
$(LIMINE_DIR)/limine-uefi-cd.binLIMINE_UEFI_CD_SHA256 in Makefile
$(LIMINE_DIR)/BOOTX64.EFILIMINE_BOOTX64_EFI_SHA256 in Makefile

$(LIMINE_DIR) resolves to $(CAPOS_TOOLS_ROOT)/limine/<LIMINE_COMMIT> (default $HOME/.capos-tools/limine/<commit> unless CAPOS_TOOLS_ROOT is overridden), shared with the rest of the per-user pinned tool cache.

make limine-ensure clones https://github.com/limine-bootloader/limine.git only when $(LIMINE_DIR)/.git is absent, fetches the pinned commit if needed, checks it out detached, and runs make inside the Limine tree (the limine-ensure recipe). make limine-verify then checks the repository HEAD and artifact checksums (the limine-verify recipe). The ISO copies the kernel, generated manifest.bin, Limine config, and verified Limine artifacts into iso_root/, runs xorriso, then runs limine bios-install (the $(ISO) recipe).

Remaining reproducibility gap: Limine source is pinned, but the Limine build host compiler and environment are not pinned or recorded.

Rust Toolchain

rust-toolchain.toml specifies:

  • channel = "nightly-2026-04-20"
  • targets = ["x86_64-unknown-none", "aarch64-unknown-none", "wasm32-wasip1"]
  • components = ["rust-src"]

The wasm32-wasip1 target is needed for the WASI Preview 1 demo payloads (demos/wasi-hello-rust/, demos/wasi-cli-args/, demos/wasi-random/) built by make wasi-hello-rust-build, make wasi-cli-args-build, and make wasi-random-build; the wasm-host binary itself is built for the booted x86_64-unknown-capos userspace target instead.

The pinned dated channel resolves to:

  • rustc 1.97.0-nightly (e22c616e4 2026-04-19)
  • host target x86_64-unknown-linux-gnu

The 2026-04-20 manifest packages the rustc commit cut on 2026-04-19; that is the upstream dist naming convention, not a drift. Rustup will continue to install the same dist tarball for nightly-2026-04-20 as long as upstream retains it.

The Makefile derives HOST_TARGET from rustc -vV (Makefile:12) and uses that for tools/mkmanifest (Makefile:28-29). Cargo aliases in .cargo/config.toml:4-48 hard-code x86_64-unknown-linux-gnu for host tests. The custom userspace target aliases in .cargo/config.toml use targets/x86_64-unknown-capos.json plus -Zjson-target-spec and -Zbuild-std=core,alloc, so rust-src is a required toolchain component. The CI host-baseline and qemu-smoke jobs install the same nightly-2026-04-20 toolchain so CI matches the local rust-toolchain.toml resolution. The kani-proofs job stays on nightly-2025-11-21 because Kani requires its own paired nightly bundle installed by cargo kani setup; advancing the Kani pin is tracked separately through that bundle’s compatibility matrix.

Rust Nightly Date Pin Policy

The pin is one of the supply-chain-trust controls listed in this proposal alongside the Limine commit, OVMF firmware SHA-256, capnp tarball SHA-256, CUE binary, mdBook/mdbook-mermaid release assets, Typst binary, uv binary, and pinned cargo-deny/cargo-audit/cargo-kani releases. All of these must be pinned at the same trust level – date- or hash-anchored, never a floating channel or moving tag. This subsection states the policy for the Rust nightly entry; the next subsection states the mechanical advance procedure.

Where the pin lives. Exactly one source: rust-toolchain.toml as a date-anchored nightly channel of the form nightly-YYYY-MM-DD. The CI workflow’s host-baseline and qemu-smoke toolchain: values must mirror that same dated channel. No other file may declare a nightly date; no float, no nightly shorthand, no commit-hash override.

Promotion criteria. A bump is accepted only when the candidate nightly satisfies all of the following against the worktree where the pin lands:

  • make builds the full workspace clean (kernel + standalone userspace + ISO) with no new warnings under cargo build --features qemu.
  • make fmt-check passes across the workspace and all standalone crates.
  • make workflow-check passes (CLAUDE.md token budget, mandatory-context budgets, slice trailers).
  • make check passes (the aggregate build/test gate that includes generated-code-check and the host-test aliases).
  • make run-smoke passes on the developer host when QEMU smoke is feasible there; if QEMU is unavailable locally, the bump branch’s CI qemu-smoke run is the authoritative gate.
  • Any new rustc warning, lint, or unrelated build failure introduced by the new nightly is treated as a real gate failure. Do not relax capOS code or silence the lint to land the bump.

Rollback. If a promotion exposes a regression in a downstream crate that capOS depends on (limine, x86_64, spin, smoltcp, wasmi, capnp/capnpc, or any cargo-deny/cargo-audit pinned tool), revert the pin to the prior dated channel on main, file a tracking note in docs/tasks/ with the failing date, the failing crate, and the upstream issue if one exists, and resume normal cadence only after the downstream regression is resolved or worked around.

Cadence. Bump the pin at least once per quarter even without a specific feature trigger so production-provenance evidence does not lag upstream. Bump out of cadence when (a) a security advisory affects the current pinned nightly’s rustc/cargo/std (consult rust-lang/rust, rustsec/advisory-db, and the cargo-audit output for the pinned dist), or (b) a compiler feature, fix, or lint that capOS depends on lands upstream. Unbounded float is not permitted: the dated channel must always resolve to a concrete YYYY-MM-DD.

Approvals. Maintainer-driven, single reviewed slice per bump. No automated promotion bot. The pin bump is its own contract change and must not be bundled with unrelated behavior changes; the reviewed diff must show only rust-toolchain.toml, the CI workflow, this proposal’s summary table and resolved-rustc line, and any minimal lint/code adjustments forced by the new nightly with an inline justification.

Trust-input dimension. The pin closes the floating-channel supply- chain gate listed in the Build Provenance Retention And Comparison Policy (“Minimum runner identity for production-hardening branches: Rust must be a date-pinned nightly or stronger hash-pinned toolchain, not the floating nightly channel”). Mirroring the resolved dist tarballs into the per-user tool cache (the same shape as Limine, capnp, CUE, mdBook, and Typst pins) remains a future hardening step tracked in the Remaining gaps section.

Advance procedure (bumping the dated nightly)

When to bump:

  • A compiler feature, fix, or lint that capOS depends on lands in upstream nightly after 2026-04-20. Example triggers: a Cargo or rustc fix that unblocks a build path; a core/alloc change that affects -Zbuild-std; a rustfmt change required for the project formatting baseline.
  • Toolchain drift hygiene: schedule a bump at least once per release window even without a specific feature trigger, so production-provenance evidence does not lag too far behind upstream.

How to bump:

  1. Choose a candidate nightly date and verify all required targets and the rust-src component are simultaneously available for that date:

    rustup toolchain add nightly-<YYYY-MM-DD> \
        --target x86_64-unknown-none \
        --target aarch64-unknown-none \
        --target wasm32-wasip1 \
        --component rust-src
    

    If any target or component is missing, try adjacent dates (rustup’s nightly dist manifests sometimes drop a target for a single day) until one is found that provides the full set.

  2. Update both files in the same commit:

    • rust-toolchain.toml channel value.
    • .github/workflows/ci.yml – both the host-baseline and qemu-smoke toolchain: values. Leave kani-proofs on its own pin.
  3. Run the full local gate set against the candidate before pushing: make fmt-check, cargo build --features qemu, make check, make workflow-check, make run-smoke. Treat any new warning or unrelated build failure as a real gate failure – do not patch around compiler drift by relaxing capOS code.

  4. Update the Rust toolchain row in this file’s summary table, the resolved rustc line above, and the last_reviewed front-matter timestamp. Cite the new dated channel.

  5. Land the pin bump as its own reviewed slice, not bundled with unrelated behavior changes. The pin is itself the provenance contract.

Remaining reproducibility gap: rustup retains nightly dist manifests for a finite window. A future hardening slice may mirror the resolved dist tarballs plus their SHA-256 checksums into the per-user tool cache the same way Limine and capnp are pinned today, so a bump-without-mirror does not become a silent loss of historical reproducibility.

CI Runner Package Pins

The qemu-smoke CI job installs qemu-system-x86, xorriso, make, git, and ovmf via apt on an ubuntu-24.04 runner. Those packages provide the QEMU emulator that executes every QEMU smoke, the ISO writer that builds the bootable image consumed by smokes, the build and repository tools used after checkout, and the UEFI firmware blob selected by make run-uefi and the cloud-disk path. A floating apt install (no =<version> specifier) would let upstream Ubuntu silently roll any of them on the next CI run, so this section names the version pins, the file that owns them, and the procedure for advancing them.

CI Package Pin Policy

The pin is one of the supply-chain-trust controls listed in this proposal alongside the Limine commit, OVMF firmware SHA-256, Rust nightly date pin, capnp tarball SHA-256, CUE binary, mdBook/mdbook-mermaid release assets, Typst binary, uv binary, and pinned cargo-deny/cargo-audit/cargo-kani releases. All of these must be pinned at the same trust level – date- or hash-anchored, never a floating channel or moving tag. This subsection states the policy for the QEMU, xorriso, make, git, and OVMF package entries; the next subsection states the mechanical advance procedure.

Where the pin lives. Exactly one source: the Install boot smoke dependencies step of the qemu-smoke job in .github/workflows/ci.yml. Each package must be invoked as <name>=<exact-version> (no * wildcard and no major-only floor) so the apt resolver fails closed rather than silently rolling forward. The currently pinned versions are qemu-system-x86=1:8.2.2+ds-0ubuntu1.16 (amd64, noble-updates/main or noble-security/main, Ubuntu 24.04), xorriso=1:1.5.6-1.1ubuntu3 (amd64, noble/main, Ubuntu 24.04), make=4.3-4.1build2 (amd64, noble/main, Ubuntu 24.04), git=1:2.43.0-1ubuntu7.3 (amd64, noble-updates/main or noble-security/main, Ubuntu 24.04), and ovmf=2024.02-2ubuntu0.8 (amd64, noble-updates/main, Ubuntu 24.04). The summary table, the QEMU and firmware and ISO and host filesystem tools rows, the Host Tools section, and the Build Provenance Retention And Comparison Policy mirror these strings; the policy text is the single source of truth and the other locations track it.

Promotion criteria. A bump is accepted only when all of the following hold against the bump branch:

  • The Ubuntu base image rolls (noble/noble-updates/noble-security publishes a newer version of the package) or a security advisory affects the currently pinned version. Cosmetic version bumps without an upstream trigger are not accepted; the pin moves forward when there is a reason to move it.
  • apt-cache madison <package> on a current Ubuntu 24.04 host lists the candidate version, and the candidate is available from noble-updates/main (or noble/main when no noble-updates entry exists, as is the case for xorriso today). Versions sourced from third-party PPAs or *-proposed pockets are not accepted.
  • The bump branch’s qemu-smoke execution reaches and passes the new-pin build evidence steps: make build, make run-smoke, make build-provenance, and candidate provenance artifact upload. The pull-request make build-provenance-compare BUILD_PROVENANCE_COMPARE_POLICY=ci-environment step is expected to fail only on reviewed package-identity fields that match the new pinned strings rather than the previous ones; every other comparison difference remains blocking.
  • No new QEMU, xorriso, make, git, or OVMF behavior is silently relied on: if the bump unlocks a smoke that previously failed, that smoke must be enabled and reviewed in the same bump branch rather than treated as incidental.
  • The Trusted Build Inputs summary table, QEMU and firmware row, ISO and host filesystem tools row, Host Tools section, and Build Provenance Retention And Comparison Policy text are updated to cite the new versions and the new resolved repository (noble/noble-updates) in the same commit.

Rollback. If a promotion exposes a regression in the QEMU smoke path, the ISO writer, build orchestration, repository operations, or UEFI boot, revert the .github/workflows/ci.yml change to the prior pinned version on main, file a tracking task under docs/tasks/ with the failing version, the failing smoke, and the upstream Ubuntu/QEMU/xorriso/OVMF issue if one exists, and resume normal cadence only after the regression is resolved or worked around. Reverting also requires reverting the summary-table and policy text mirrors so the recorded versions stay consistent with the workflow file.

Cadence. Bump the pins at least once per quarter even without a specific security trigger, so production-provenance evidence does not lag upstream Ubuntu point releases. Bump out of cadence when (a) a security advisory affects the current pinned version of any of the packages (consult the Ubuntu Security Notices, the QEMU security mailing list, the Git security advisories, GNU make release notes, and the ovmf/edk2 advisories), or (b) a fix that capOS depends on lands in a newer Ubuntu point release. Unbounded float is not permitted: each package must always resolve to a concrete <epoch>:<upstream>-<debian> version string.

Approvals. Maintainer-driven, single reviewed slice per bump. No automated promotion bot. The pin bump is its own contract change and must not be bundled with unrelated behavior changes; the reviewed diff must show only .github/workflows/ci.yml, this proposal’s summary table and resolved-version mirrors, the relevant production-provenance task record when sub-items move, and any minimal smoke adjustments forced by the new package versions with an inline justification.

Trust-input dimension. The pin closes the runner/OS/tool identity gate listed in the Build Provenance Retention And Comparison Policy (“Minimum runner identity for production-hardening branches: QEMU, xorriso, make, and git must come from a pinned runner image digest or a documented package set with package name, version, architecture, repository, and distribution release”) for the apt-installed package set it owns. A pinned runner image digest (replacing the ubuntu-24.04 mutable label with an immutable image SHA) or repo-managed tool digests for those packages remain future hardening tracked in docs/design-risks-register.md (R13).

Advance procedure (bumping the apt-pinned versions)

When to bump:

  • An Ubuntu Security Notice affects the currently pinned version of qemu-system-x86, xorriso, make, git, or ovmf.
  • A QEMU, xorriso, make, git, or OVMF point release lands in noble-updates/main that capOS needs (typically a virtio, MSI-X, ISO writer, build-tool, repository-tool, or UEFI fix).
  • Quarterly hygiene cadence with no specific feature trigger, so the pin does not lag too far behind upstream.

How to bump:

  1. On a current Ubuntu 24.04 host (or a ubuntu:24.04 container that has refreshed apt-get update), list available versions of each package:

    apt-cache madison qemu-system-x86
    apt-cache madison xorriso
    apt-cache madison make
    apt-cache madison git
    apt-cache madison ovmf
    

    Pick the highest stable version from noble-updates/main. If a package has no noble-updates entry (as is the case for xorriso today), pick from noble/main. Do not select from *-proposed, *-backports, or third-party PPAs.

  2. Update the single source in the Install boot smoke dependencies step of the qemu-smoke job in .github/workflows/ci.yml so each package line reads <name>=<exact-version>.

  3. Update the mirrors in this file in the same commit: the summary-table rows for QEMU and firmware and ISO and host filesystem tools, the Host Tools section, the Build Provenance Retention And Comparison Policy text, and the Remaining gaps for Security Verification Track S.10.2/S.10.3 block under Manifest, Embedded Binaries, and Downloaded Artifacts. Refresh the last_reviewed front-matter timestamp.

  4. If the OVMF package version moves, the OVMF firmware blob SHA-256 may change. Recompute OVMF_CODE_SHA256 in Makefile from the resolved firmware path (/usr/share/ovmf/OVMF.fd on Ubuntu 24.04) and verify make ovmf-verify passes against the new digest. Land the OVMF_CODE_SHA256 change in the same commit as the package bump.

  5. Push the bump branch and let qemu-smoke exercise the new pins through make, make run-smoke, make build-provenance, and candidate provenance artifact upload. The acceptance gate for the bump itself is those steps passing plus a reviewed PR make build-provenance-compare BUILD_PROVENANCE_COMPARE_POLICY=ci-environment failure whose diff is limited to the intended package-identity strings replacing the previous ones. Land the bump through the reviewed local-main integration or maintainer push path; after it reaches main, the next successful main-branch qemu-smoke push artifact is the new base record for unrelated PR comparisons.

  6. Land the pin bump as its own reviewed slice, not bundled with unrelated behavior changes. The pin is itself the provenance contract.

Remaining reproducibility gap: the ubuntu-24.04 runner label is still managed by GitHub Actions, not by an immutable image digest, so the host package set underneath the apt-installed qemu-system-x86, xorriso, make, git, and ovmf pins can still roll between runs. A future hardening slice may move the qemu-smoke job to a self-built runner image referenced by digest, mirror the apt package files into the per-user tool cache the same way Limine and capnp are pinned today, or both, so a bump-without- mirror does not become a silent loss of historical reproducibility.

Cargo Dependencies

The root workspace members are capos-abi, capos-config, capos-lib, capos-tls, kernel, and the host-only tools/capnp-build build-support crate. Cargo.toml keeps default members to capos-config, capos-lib, capos-tls, and kernel so ordinary root bare-metal builds do not build the host helper as a target package but do build the capos-tls certificates/TLS verifier-dependency probe. The vendored rustls-webpki / webpki-roots path dependencies declare their own [workspace] and are listed in the root Cargo.toml exclude set (the same isolation as the vendored fatfs crate), so they are not workspace members. The vendored embedded-tls client-state machine snapshot follows the same workspace isolation and is consumed only by the standalone demos/ workspace. init/, demos/, tools/mkmanifest/, tools/ringtap-viewer/, capos-rt/, shell/, libcapos/, libcapos-posix/, capos-wasm/, and fuzz/ are standalone workspaces with their own lockfiles.

Important direct dependencies and current root-lock resolutions:

DependencyManifest referencesRoot lock resolution
capos-abicapos-config/Cargo.toml, capos-lib/Cargo.tomllocal path package in Cargo.lock
argon2capos-lib/Cargo.toml; optional capos-config/Cargo.toml credential-validation feature used by kernel/init/mkmanifest bootstrap validation0.5.3 in Cargo.lock
capnpcapos-config/Cargo.toml, capos-lib/Cargo.toml, kernel/Cargo.toml0.25.4 in Cargo.lock
capos-capnp-buildcapos-config/Cargo.tomllocal path package in Cargo.lock
capnpctools/capnp-build/Cargo.toml0.25.3 in Cargo.lock
limine cratekernel/Cargo.toml:8 ("0.6" range)0.6.3 in Cargo.lock
spinkernel/Cargo.toml:9 ("0.9" range)0.9.8 in Cargo.lock
x86_64kernel/Cargo.toml:10 ("0.15" range)0.15.4 in Cargo.lock
linked_list_allocatorkernel/Cargo.toml:11 ("0.10" range)0.10.6 in Cargo.lock
smoltcpkernel/Cargo.toml:16 ("0.13.0" caret range)0.13.0 in Cargo.lock
loomcapos-config/Cargo.toml:270.7.2 in Cargo.lock
proptestcapos-lib/Cargo.toml1.11.0 in Cargo.lock
rustls-webpki (vendored path)capos-tls/Cargo.toml (=0.103.13, default-features = false, alloc)local path package (vendor/rustls-webpki/rustls-webpki-0.103.13) in Cargo.lock
webpki-roots (vendored path)capos-tls/Cargo.toml (=1.0.7, default-features = false)local path package (vendor/webpki-roots/webpki-roots-1.0.7) in Cargo.lock
rustls-pki-typestransitive of the vendored rustls-webpki/webpki-roots (alloc)1.14.1 in Cargo.lock
untrustedtransitive of the vendored rustls-webpki0.9.0 in Cargo.lock
zeroizetransitive of rustls-pki-types (alloc)1.8.2 in Cargo.lock

The four kernel-critical crates limine, spin, x86_64, and smoltcp are declared with semver-range requirements ("0.6", "0.9", "0.15", and the caret "0.13.0"), not the exact =X.Y.Z requirements applied to capnp (=0.25.4) in kernel/Cargo.toml and sha2 (=0.10.9 in capos-lib/Cargo.toml). This requirement-level asymmetry is currently unintentional drift in manifest style rather than a deliberate policy: the exact crate version that ships is still pinned by the checked-in Cargo.lock checksums above and is review-visible through lockfile diffs, so a range requirement does not widen what actually compiles without a lockfile change. Tightening these four manifest requirements to =X.Y.Z to match capnp/sha2 is a separate build-risk change (a manifest edit plus lockfile regeneration and re-verification), tracked as a doc-accuracy gap here rather than changed in this inventory pass.

Standalone lockfile drift observed during this inventory:

The TLS client handshake smoke adds a userspace-runtime no_std dependency in the standalone demos/ workspace: embedded-tls = "=0.19.0" as a path dependency under vendor/embedded-tls/embedded-tls-0.19.0/, with default-features = false and only the rustpki feature enabled. demos/Cargo.lock pins the resulting RustCrypto TLS 1.3 closure. The capOS custom target forces the software AES and POLYVAL backends in .cargo/config.toml so those crypto dependencies do not select x86 accelerated backend code that is outside the custom-target build contract.

LockfileNotable direct/runtime resolution
init/Cargo.lockcapnp 0.25.4, capnpc 0.25.3, linked_list_allocator 0.10.6
demos/Cargo.lockcapnp 0.25.4, capnpc 0.25.3, linked_list_allocator 0.10.6
demos/wasi-hello-rust/Cargo.lockSingle-package leaf lockfile for the wasm32-wasip1 Rust hello payload; no third-party direct dependencies.
demos/wasi-cli-args/Cargo.lockSingle-package leaf lockfile for the Phase W.3 argv-grant wasm32-wasip1 Rust payload; no third-party direct dependencies.
demos/wasi-env/Cargo.lockSingle-package leaf lockfile for the WASI environment-grant wasm32-wasip1 Rust payload; no third-party direct dependencies.
demos/wasi-fs/Cargo.lockSingle-package leaf lockfile for the WASI filesystem wasm32-wasip1 Rust payload; no third-party direct dependencies.
demos/wasi-random/Cargo.lockSingle-package leaf lockfile for the Phase W.4 random_get wasm32-wasip1 Rust payload; no third-party direct dependencies.
demos/wasi-preview1-refusals/Cargo.lockSingle-package leaf lockfile for the WASI Preview 1 refusal-coverage wasm32-wasip1 Rust payload; no third-party direct dependencies.
demos/wasi-stdio-fd/Cargo.lockSingle-package leaf lockfile for the WASI stdio-fd wasm32-wasip1 Rust payload; no third-party direct dependencies.
tools/mkmanifest/Cargo.lockcapnp 0.25.4, capnpc 0.25.3, serde_json 1.0.149
tools/adventure-content-gen/Cargo.lockHost generator for adventure content; locked dependencies include serde_json and the cue-export-to-JSON pipeline; no capnp runtime dependency.
tools/paperclips-content-gen/Cargo.lockHost generator for Paperclips content; locked dependencies include serde_json and capnp 0.25.4 for schema-aware JSON-to-binary conversion through mkmanifest cue-to-capnp.
tools/remote-session-client/Cargo.lockStandalone Linux host-side remote-session client; pins capnp 0.25.4 and serde 1.0.228; no transitive wasmi, Argon2, or smoltcp dependency. Covered by make dependency-policy-check.
tools/ringtap-viewer/Cargo.lockcapnp 0.25.4, capnpc 0.25.3; no Argon2 because it uses baseline capos-config
capos-rt/Cargo.lockcapnp 0.25.4, capnpc 0.25.3, linked_list_allocator 0.10.6
capos-service/Cargo.lockcapnp 0.25.4, capnpc 0.25.3, linked_list_allocator 0.10.6 (the same allocator resolution as capos-rt/demos/libcapos; no cross-workspace drift).
libcapos/Cargo.lockcapnp 0.25.4, capnpc 0.25.3, linked_list_allocator 0.10.6 plus the local capos-rt path dependency.
libcapos-posix/Cargo.lockcapnp 0.25.4, capnpc 0.25.3, linked_list_allocator 0.10.6, plus local capos-rt and libcapos path dependencies.
shell/Cargo.lockblake2 0.10.6, capnp 0.25.4, capnpc 0.25.3, linked_list_allocator 0.10.6; no Argon2 because it uses baseline capos-config
capos-wasm/Cargo.lockcapnp 0.25.4, capnpc 0.25.3, linked_list_allocator 0.10.6, wasmi 1.0.9 (vendored static-pinned at vendor/wasmi-no_std/wasmi-1.0.9/); no Argon2.
fuzz/Cargo.lockcapnp 0.25.4, capnpc 0.25.3, libfuzzer-sys 0.4.12
tools/remote-session-client/src-tauri/Cargo.lock (not yet under policy gates)Tauri scaffold lockfile carrying ~435 transitive packages pinned through tauri = "=2.11.1"; only reachable through make remote-session-tauri policy / check / dev modes. Not covered by make dependency-policy-check today; promotion is gated on the Tauri authority decision.
vendor/wasmi-no_std/wasmi-1.0.9/Cargo.lock (vendored snapshot lockfile)Upstream wasmi workspace lockfile preserved with the static-pinned snapshot; capos-wasm consumes wasmi only through its own =1.0.9 path dependency, which lands in capos-wasm/Cargo.lock and is covered there. The vendored lockfile is not separately gated; see vendor/wasmi-no_std/VENDORED_FROM.md for the refresh procedure and policy re-check.

Cargo lockfiles pin exact crate versions and crates.io checksums, so ordinary crate upgrades are review-visible through lockfile diffs. They do not, by themselves, define whether a dependency is acceptable for kernel/no_std use, whether multiple lockfiles must converge, or whether advisories/licenses block the build.

Security Verification Track S.10.3 policy gate:

  • deny.toml defines the shared license, advisory, ban, and source baseline.

  • The allowed license set is intentionally limited to permissive licenses used by current locked dependencies. BSD-3-Clause is accepted for the Argon2 credential-validation dependency closure (subtle through password-hash, digest, and blake2); it is OSI-approved, FSF-free, and carries only the standard non-endorsement clause beyond the already-allowed BSD-2-Clause. 0BSD is accepted for the smoltcp networking dependency closure (smoltcp and managed); it is OSI-approved and carries no attribution or non-endorsement condition beyond the existing permissive-license baseline.

  • make dependency-policy-check runs cargo deny check on the root workspace, init, demos, tools/mkmanifest, tools/ringtap-viewer, capos-rt, shell, and fuzz.

  • The same target runs cargo audit --deny warnings on every checked-in lockfile, with one explicit audit ignore: RUSTSEC-2026-0173 (proc-macro-error2 unmaintained warning). The ignored path is pulled into lockfiles through smoltcp’s optional defmt logging feature; capOS does not enable defmt for smoltcp, but cargo audit scans lockfiles rather than the target feature set. Remove the ignore when upstream smoltcp / defmt no longer resolves that crate.

  • The same target copies package.json and package-lock.json into a private temporary directory and runs a dry-run install there:

    PUPPETEER_SKIP_DOWNLOAD=1 npm ci --ignore-scripts --dry-run
    

    That preserves the npm ci package/lock synchronization check without modifying the worktree install. It also runs npm audit --package-lock-only --audit-level=high. Lifecycle scripts stay disabled for the docs dependency install path; the browser used by Mermaid PDF rendering is an explicit host executable selected by MERMAID_BROWSER_BIN.

  • capos-config keeps Argon2 behind the credential-validation feature. Bootstrap/config validation remains available in the baseline feature set, while validators that need to parse PHC credential strings enable the feature. Runtime clients and inspection tools that only need ring/schema/CapSet data use the baseline feature set.

  • Local packages are marked publish = false so cargo-deny treats them as private, and local path dependencies include version = "0.1.0" so registry wildcard requirements can remain denied.

  • CI installs pinned cargo-deny 0.19.4 and cargo-audit 0.22.1 and runs the target.

Remaining dependency-policy gap: decide whether standalone lockfiles may intentionally drift from the root lockfile, especially for capnp and allocator crates used by userspace.

Cap’n Proto Compiler, Runtime, and Generated Bindings

The trusted Cap’n Proto inputs are:

  • schema/capos.capnp, the source schema.
  • Repo-local pinned capnp, invoked through the capnpc Rust build dependency via CAPOS_CAPNP.
  • capnp runtime crate with default-features = false and alloc.
  • capnpc codegen crate.
  • Generated capos_capnp.rs written to Cargo OUT_DIR.
  • Local no_std patching applied after generation by tools/capnp-build.

capos-config/build.rs delegates schema generation to tools/capnp-build. That shared helper runs capnpc::CompilerCommand over schema/capos.capnp, reads the generated capos_capnp.rs, asserts that the expected #![allow(unused_variables)] anchor is present, and injects:

#![allow(unused)]
#![allow(unused_imports)]
fn main() {
use ::alloc::boxed::Box;
use ::alloc::string::ToString;
}

The generated code used by builds is included from OUT_DIR in capos-config/src/lib.rs:10-12. The expected patched output is checked in as tools/generated/capos_capnp.rs, so schema, compiler, capnpc crate, and patch-output changes must update that baseline and become review-visible as a source diff.

Security Verification Track S.10.2 generated-code drift check:

  • make generated-code-check first builds the checked-in init ELF required by kernel build-script validation, exports its absolute path as CAPOS_INIT_ELF, and runs tools/check-generated-capnp.sh, tools/check-generated-adventure-content.sh, and tools/check-generated-paperclips-content.sh.
  • The script invokes the actual Cargo build-script path for capos-config in an isolated target directory, so it checks the generated artifact that crate would include from OUT_DIR.
  • During that build, tools/capnp-build also copies the patched binding to a deterministic package-scoped path under the isolated target directory. The checker consumes those explicit paths rather than searching Cargo’s hashed build-script output directories.
  • The script verifies that the patched file still contains the capnpc anchor plus the local no_std patch imports, compares the output against tools/generated/capos_capnp.rs, and fails if a kernel-generated output path appears in the isolated target directory.
  • Any intentional schema/codegen/patch change must update the checked-in baseline in the same review, making generated output drift review-visible.
  • make check runs fmt-check plus generated-code-check for a single local or CI entry point.
  • Current pinned compiler source is capnproto-c++-1.2.0.tar.gz from https://capnproto.org/ with SHA-256 ed00e44ecbbda5186bc78a41ba64a8dc4a861b5f8d4e822959b0144ae6fd42ef. The checked-in tools/generated/capos_capnp.rs baseline must be regenerated with that compiler when schema or codegen behavior intentionally changes. The current pinned baseline SHA-256 is 5ab84731324fe9cc984d7aba7dd97963a773800cc52c4c1693fcb6bb448329a6.

Adventure content generation uses:

  • demos/adventure-content/content/prototype.cue as the checked-in source.
  • tools/adventure-content-gen, a standalone Cargo host tool with tools/adventure-content-gen/Cargo.lock.
  • demos/adventure-content/src/generated.rs as the checked-in generated no_std Rust baseline consumed by demos/adventure-content/src/lib.rs.
  • tools/check-generated-adventure-content.sh, which derives the same $(CAPOS_TOOLS_ROOT)/cue/0.16.0/bin/cue path as the Makefile, rejects a mismatched CAPOS_CUE, checks cue version v0.16.0, exports explicit JSON, runs the generator with cargo run --locked, formats the output with rustfmt --edition 2024, and fails if the result differs from demos/adventure-content/src/generated.rs.

Any intentional content-source or generator change must update the checked-in generated Rust baseline in the same review. The generator manifest and lockfile are included in make dependency-policy-check.

The no_std patch source is single-owned by tools/capnp-build; capos-config/build.rs emits its crate-specific rerun directives and calls the helper.

Alloy Analyzer (DMA Assurance Model)

The DMA assurance Alloy model (models/dma/dma_authority.als) is checked by a pinned Alloy Analyzer, the same trust level as the Limine, capnp, CUE, Typst, and uv pins.

  • Pinned artifact: alloy-6.2.0-linux-amd64.tar.gz from the official AlloyTools/org.alloytools.alloy GitHub release v6.2.0 (https://github.com/AlloyTools/org.alloytools.alloy/releases/download/v6.2.0/alloy-6.2.0-linux-amd64.tar.gz), SHA-256 5a5494a4bac6e243e471590bb44a91e25a35794a5af1ae1f332be30b9c54a9e7. This is the self-contained linux/amd64 app image: it bundles a Temurin JRE under lib/runtime/ and the native SAT solver libraries, so the gate needs no host JVM and pins the analyzer and its runtime by one hash. The org.alloytools.alloy.dist.jar (bare jar, host-JVM dependent) is deliberately not used.
  • Where the pin lives: Makefile ALLOY_VERSION / ALLOY_PLATFORM / ALLOY_TARBALL_URL / ALLOY_TARBALL_SHA256. make alloy-ensure downloads the tarball (curl with retry), verifies the SHA-256, extracts the app image into $(CAPOS_TOOLS_ROOT)/alloy/6.2.0/ (shared per-user cache, default $HOME/.capos-tools), and confirms the launcher reports version 6.2.0. The jar is not vendored into the repository.
  • Drift review: make model-dma-alloy re-verifies the tarball SHA-256 and the reported launcher version on every run before invoking the model. A bump is a Makefile ALLOY_VERSION + ALLOY_TARBALL_SHA256 diff plus a refreshed checked-result record in models/dma/README.md.
  • Why output is parsed, not exit-code-gated: the Alloy CLI exec subcommand always exits 0; a check that finds a counterexample, a run that finds no instance, and a syntax/resolution error all return success with the failure visible only in the printed verdict table. tools/run-dma-alloy-model.sh parses that table and fails closed on any check that is not UNSAT, any run that is not SAT, or any analyzer error marker.
  • Platform/CI scope: the pinned app image is linux/amd64 (the dev/CI host architecture). GitHub CI runs make model-dma-alloy in the dma-assurance-models job on ubuntu-24.04. Other architectures would need the matching Alloy app image (or the bare jar plus a host JVM). Ownership of the Alloy pin is shared with the scheduler lease model track (scheduler-cpu-isolation-lease-authority-model).

TLC Model Checker (DMA Assurance Lifecycle Model)

The DMA assurance TLA+ lifecycle model (models/dma/dma_authority.tla) is checked by a pinned TLC, the same trust level as the Limine, capnp, CUE, Typst, uv, and Alloy pins. Unlike the self-contained Alloy app image, tla2tools.jar is a bare Java jar, so a JVM is pinned alongside it.

  • Pinned artifacts: tla2tools.jar from the official tlaplus/tlaplus GitHub release v1.7.4 (TLC 2.19), https://github.com/tlaplus/tlaplus/releases/download/v1.7.4/tla2tools.jar, SHA-256 936a262061c914694dfd669a543be24573c45d5aa0ff20a8b96b23d01e050e88; and a Temurin JRE 17.0.19+10 linux/x64 tarball (OpenJDK17U-jre_x64_linux_hotspot_17.0.19_10.tar.gz from the adoptium/temurin17-binaries release), SHA-256 adb5a2364baa51de1ef91bb9911f5a61d24b045fe1d6647cb8050272a3a8ee75. Pinning the JRE as well as the jar fixes both the checker and its runtime by hash.
  • Where the pin lives: Makefile TLA_TOOLS_VERSION / TLA_TOOLS_JAR_URL / TLA_TOOLS_JAR_SHA256 / TLA_JRE_URL / TLA_JRE_SHA256. make tla-ensure downloads both (curl with retry), verifies their SHA-256, extracts the JRE into $(CAPOS_TOOLS_ROOT)/tla/jre/ and places the jar at $(CAPOS_TOOLS_ROOT)/tla/1.7.4/tla2tools.jar (shared per-user cache, default $HOME/.capos-tools), and confirms the launcher reports 17.0.19. Neither is vendored into the repository.
  • Drift review: make model-dma-tla re-verifies the jar SHA-256 and the JRE launcher version on every run before invoking the model. A bump is a Makefile pin diff plus a refreshed checked-result record in models/dma/README.md.
  • Why output is parsed and exit-code-gated: TLC returns a non-zero exit code (12) on an invariant violation, a deadlock, or a parse/semantic error, but tools/run-dma-tla-model.sh additionally asserts the Model checking completed. No error has been found. marker and rejects any violation/error marker, so a future TLC behaviour change cannot turn a violation into a green gate. The model is checked with deadlock detection enabled; the spec provides an explicit terminating self-loop for the all-pages-parked state, so any other stuck state is a genuine modelling gap.
  • Platform/CI scope: the pinned JRE tarball is linux/x64 (the dev/CI host architecture). GitHub CI runs make model-dma-tla in the dma-assurance-models job on ubuntu-24.04; other architectures would need the matching Temurin JRE. Ownership of the TLC pin is shared by the scheduler/IRQ TLA+ model tracks (scheduler-nohz-activation-model, irq-msix-waiter-determinism-model).

Cargo Build Scripts

Build scripts currently do these trusted operations:

ScriptBehavior
kernel/build.rsWatches kernel/linker-x86_64.ld and itself.
capos-config/build.rsCalls tools/capnp-build to watch schema/capos.capnp, generate bindings, and apply the shared no_std patch. Checked by make generated-code-check.
tools/capnp-build/src/lib.rsHost build-support helper for pinned capnp path validation, schema generation, and no_std generated-binding patching. Unit tests cover patch injection and missing-anchor rejection.
tools/adventure-content-gen/src/main.rsHost generator for the prototype adventure CUE source. Checked by make generated-code-check through tools/check-generated-adventure-content.sh, which uses pinned CUE and locked Cargo dependencies.
init/build.rsEmits a linker script argument for init/linker.ld.
demos/*/build.rsEmits a linker script argument for demos/linker.ld.
capos-rt/build.rsEmits a linker script argument for capos-rt/linker.ld when building current target_os = "none" userspace or custom-target target_os = "capos" probes.
capos-wasm/build.rsEmits a linker script argument for capos-wasm/linker.ld (Phase W.2 onward; uses cargo:rustc-link-arg-bins so the script applies only to the wasm-host bin and not the lib).

The linker build scripts derive CARGO_MANIFEST_DIR from Cargo and only emit link arguments plus rerun directives. The capnp build scripts read and rewrite generated code under OUT_DIR. None of these scripts fetch network resources.

Security Verification Track S.10.2 coverage: make generated-code-check exercises the canonical capos-config capnp build script through Cargo, validates the patched generated file, fails if kernel-generated output reappears, and fails if the canonical output no longer matches the checked-in generated baseline.

Manifest, Embedded Binaries, and Downloaded Artifacts

system.cue declares named binaries and services. Makefile builds manifest.bin by running tools/mkmanifest on the host. mkmanifest runs:

  1. Resolve the pinned CUE compiler from $(CAPOS_TOOLS_ROOT), reject missing or mismatched CAPOS_CUE, check cue version v0.16.0, then run cue export system.cue --out json or package-mode equivalent.
  2. JSON-to-CueValue conversion and manifest validation (tools/mkmanifest/src/lib.rs).
  3. Binary embedding from relative paths (tools/mkmanifest/src/lib.rs).
  4. Binary-reference validation and Cap’n Proto serialization (tools/mkmanifest/src/main.rs).

The adjacent mkmanifest cue-to-capnp subcommand uses the same pinned CUE export path but does not parse the result as SystemManifest. Instead, it resolves and validates CAPOS_CAPNP, checks Cap'n Proto version 1.2.0, and passes the exported JSON to Cap’n Proto:

capnp convert json:binary <schema.capnp> <RootType>

It is the supported schema-aware path for CUE-authored data messages rooted at arbitrary specified Cap’n Proto structs; live capabilities and interface objects are outside that data-file contract.

Path handling rejects absolute paths, parent traversal, non-normal components, and canonicalized paths that escape the manifest directory (tools/mkmanifest/src/lib.rs). The generated manifest.bin is copied into the ISO as /boot/manifest.bin and loaded by Limine via limine.conf:5.

Downloaded or generated artifacts in the current build:

ArtifactProducerPinning/drift status
$(LIMINE_DIR) checkout ($(CAPOS_TOOLS_ROOT)/limine/<commit>)git clone/git fetch in the limine-ensure recipeCommit-pinned and artifact-verified.
Cargo registry cratescargo build, cargo run, tests, fuzzLockfile-pinned checksums plus CI-enforced deny/audit checks through make dependency-policy-check.
Node registry packagesnpm ci --ignore-scripts for docs Mermaid renderingpackage-lock.json pins package tarball integrity. Lifecycle scripts are disabled, Puppeteer’s browser download path is skipped, and make dependency-policy-check enforces the npm ci package/lock synchronization invariant plus high-severity npm audit state.
Chromium/Chrome for Mermaid PDF renderingHost executable selected by MERMAID_BROWSER_BIN or auto-detected from chromium-browser, chromium, google-chrome-stable, or google-chromeHost-provided browser, not repo-pinned. The docs PDF target fails closed if no executable is available and passes the selected path to Puppeteer as PUPPETEER_EXECUTABLE_PATH, rather than allowing Puppeteer’s npm install script to download an implicit browser artifact.
Rust toolchain, targets, and rust-srcrustup from rust-toolchain.toml when absentDate-pinned nightly-2026-04-20 channel; rust-src is declared for custom-target -Zbuild-std userspace builds. The advance procedure for bumping the pin lives in the Rust Toolchain section above.
target/ kernel and host artifactsCargoGenerated, not checked in.
init/target/, demos/target/, capos-rt/target/, capos-wasm/target/ ELFsCargo standalone buildsGenerated, embedded into manifest.bin where referenced; make build-provenance records hashes for embedded file-backed and inline payloads.
target/x86_64-unknown-capos/, init/target/x86_64-unknown-capos/, demos/target/x86_64-unknown-capos/, shell/target/x86_64-unknown-capos/, capos-rt/target/x86_64-unknown-capos/, libcapos/target/x86_64-unknown-capos/, libcapos-posix/target/x86_64-unknown-capos/, and capos-wasm/target/x86_64-unknown-capos/ userspace artifactsCargo aliases using targets/x86_64-unknown-capos.jsonGenerated artifacts for booted userspace manifests, the capos-rt smoke binary, the wasm-host Phase W.2 binary, and the libcapos / libcapos-posix C-substrate staticlibs.
manifest.bintools/mkmanifestGenerated from system.cue plus ELF payloads; not checked in. Hash is recorded by make build-provenance.
iso_root/ and capos.isoMakefile, xorriso, Limine installerGenerated and gitignored; Limine inputs verified. Final ISO hash is recorded by make build-provenance.
target/build-provenance.txttools/build-provenance.sh via make build-provenanceGenerated and gitignored; records runner OS/kernel/architecture identity, GitHub Actions image identity when present, Rust toolchain details, selected executable paths, package identities when discoverable, OVMF selected path/package/absence state, tool versions, git commit, manifest/ISO/kernel/OVMF hashes, and embedded payload origin plus hashes. CI publishes the artifact as build-provenance-<sha> on every qemu-smoke run (30-day retention). On pull_request events the qemu-smoke job locates the most recent successful main-branch build-provenance-<sha> artifact, downloads it via actions/download-artifact, and runs make build-provenance-compare BUILD_PROVENANCE_COMPARE_POLICY=ci-environment against the candidate record as a blocking PR gate.

Remaining gaps for Security Verification Track S.10.2/S.10.3:

  • CI now publishes target/build-provenance.txt as a named artifact on every qemu-smoke run (30-day retention) and, on pull_request events, downloads the most recent successful main-branch build-provenance-<sha> artifact and runs make build-provenance-compare against the candidate record with BUILD_PROVENANCE_COMPARE_POLICY=ci-environment. The compare step is PR-blocking for runner/tool/Rust/OVMF environment drift and fails when the base artifact cannot be found.
  • qemu-smoke apt-pins qemu-system-x86, xorriso, make, git, and ovmf, and make build-provenance records normalized package identity where the runner exposes it. Repo-pinned digests (download-and-verify rather than apt-installed packages) for qemu-system-x86, xorriso, make, and git, or an immutable runner image digest containing that package set, remain future production-reproducibility hardening tracked in docs/design-risks-register.md (R13).
  • Decide whether CI should record the pinned cue export JSON or final manifest.bin bytes if manifest reproducibility becomes release-critical.

Vendored Upstream Snapshots

The repository carries static, pinned snapshots of selected upstream sources under vendor/. Each snapshot has its own VENDORED_FROM.md recording the upstream URL, tag/version, commit SHA, commit date, vendoring date, license, vendoring posture, and refresh procedure. Snapshots are kept byte-identical to their pinned upstream artifact (git commit, or the crates.io published crate as noted below); the only non-upstream changes permitted without a patches/ unified diff are the documented integration-only empty-[workspace] marker and build-inert files restored from the same upstream commit when the publish include omitted them (for rustls-webpki, src/test_utils.rs and rustfmt.toml, both recorded in its VENDORED_FROM.md). Any future functional patch must be recorded as a unified diff under the snapshot’s patches/ directory plus a Patches entry per the procedure in the snapshot’s VENDORED_FROM.md.

SnapshotUpstreamTag/VersionCommit SHALicenseConsumer
vendor/wasmi-no_std/wasmi-1.0.9/https://github.com/wasmi-labs/wasmiv1.0.961ba65e6563d8b2f5b699b018349d3330b28b9f3Apache-2.0 OR MIT (dual)capos-wasm/ (WASI host adapter wasm-host bin and Preview 1 import surface)
vendor/dns-c-wahern/src/https://github.com/wahern/dnsrel-201608084ec718a77633c5a02fb77883387d1e7604750251MITPOSIX adapter Phase P1.2 Phase B DNS smoke; not yet on the v0 build path (the smoke compiles only demos/posix-dns-resolver/main.c with a commented-out dns.h include)
vendor/rustls-webpki/rustls-webpki-0.103.13/https://github.com/rustls/webpki0.103.13 (crates.io crate)2879b2ce7a476181ac3050f73fe0835f04728e86ISCcapos-tls/ Phase-1 verifier (WebPKI X.509 path building + signature verification, no_std + alloc, no crypto provider in the default build)
vendor/webpki-roots/webpki-roots-1.0.7/https://github.com/rustls/webpki-roots1.0.7 (crates.io crate)be948464fd5907af6227213a066743a161221688CDLA-Permissive-2.0capos-tls/ Phase-1 trust-anchor bootstrap (compiled-in Mozilla NSS root bundle, no_std)
vendor/embedded-tls/embedded-tls-0.19.0/https://github.com/drogue-iot/embedded-tls0.19.0 (crates.io crate)865e1fd983c583228e3bbeb9f4996f1abc454ca3Apache-2.0demos/cloud-tls-client-handshake-smoke/ TLS 1.3 client state machine (no_std + alloc, default std/tokio features disabled, rustpki enabled)

The rustls-webpki and webpki-roots snapshots use a published-crate posture distinct from the git-clone snapshots above: each is the crates.io published .crate artifact, SHA-256-verified against the crates.io index (61c429a8…f756e and 52f5ee44…2eb9d respectively), with the upstream commit recorded from the artifact’s embedded .cargo_vcs_info.json. For rustls-webpki, two build-inert files the publish include omitted (src/test_utils.rs, a #[cfg(test)] module, and rustfmt.toml) are restored from the same upstream commit so cargo fmt resolves the module tree and formats the snapshot under upstream’s own style config; see its VENDORED_FROM.md. capos-tls/ (a root-workspace member and the Phase-1 host verifier crate) depends on both as exact-pinned path dependencies (version = "=0.103.13" / version = "=1.0.7") and forces them to link for x86_64-unknown-none under cargo build and cargo build --features qemu. rustls-webpki is selected with default-features = false, features = ["alloc"], so neither std nor a ring / aws-lc-rs crypto provider is compiled; the active compiled closure is rustls-pki-types (alloc, pulling zeroize) and untrusted (ISC), all pinned in the root Cargo.lock and covered by make dependency-policy-check. The ring optional dependency appears in Cargo.lock as an unselected optional entry; aws-lc-rs is a feature-gated optional / dev-only dependency and does not resolve into the root lockfile at all. Neither is ever feature-activated, so no crypto provider is compiled and cargo deny does not evaluate ring (cargo tree -p capos-tls -e features activates only rustls-pki-types, zeroize, untrusted, webpki-roots, and rustls-webpki[alloc]). The webpki-ring feature is host-test-only and supplies the signature algorithms for cargo test-tls; the default bare-metal build remains provider-free.

The embedded-tls snapshot uses the same published-crate posture: the vendored tree is the crates.io 0.19.0 package with .cargo_vcs_info.json recording upstream commit 865e1fd983c583228e3bbeb9f4996f1abc454ca3. The local handshake smoke depends on it with an exact path pin, disables default std and tokio, and enables only rustpki so the TLS 1.3 client path can run under target_os = "capos" over a TcpSocket cap. The empty [workspace] marker is the only local integration change.

capos-wasm/Cargo.toml pins the wasmi path dependency to version = "=1.0.9" so cargo-deny’s wildcards gate continues to pass; the snapshot is exercised by make capos-wasm-build, every make run-wasi-* smoke, and make dependency-policy-check (cargo-deny + cargo-audit on capos-wasm/Cargo.lock). Refreshing wasmi to a newer tag requires the rsync pattern, manifest pin bump, lockfile regeneration, and policy re-check recorded in vendor/wasmi-no_std/VENDORED_FROM.md.

The dns.c snapshot is intentionally a strict subset (only src/dns.c, src/dns.h, LICENSE, and README.md); ancillary upstream files (cache, mem, spf, zone, regress) are excluded because the v0 build path does not need them. Future POSIX-adapter phases that widen libcapos-posix enough to compile dns.c whole will start consuming the snapshot in the build instead of carrying it as a documentation-only reference.

vendor/dash/ is not present at this revision. If a future POSIX-adapter phase imports dash, add a new row above plus a vendor/dash/VENDORED_FROM.md recording the same provenance fields.

Host Tools

Current local host versions observed during this inventory:

ToolObserved versionBuild role
capnp1.2.0Repo-selected schema compiler built by make capnp-ensure from a SHA-256-pinned official source tarball into $(CAPOS_TOOLS_ROOT).
cuev0.16.0Repo-selected manifest compiler installed by make cue-ensure into $(CAPOS_TOOLS_ROOT) from the SHA-256-verified official release binary.
qemu-system-x86_6410.2.2Boot verification via make run and make run-uefi.
xorriso1.5.8ISO generation.
make4.4.1Build orchestration.
git2.53.0Limine checkout/fetch and review workflow.

These are local environment observations, not repository pins. On the qemu-smoke CI runner, qemu-system-x86, xorriso, make, and git are apt-pinned to qemu-system-x86=1:8.2.2+ds-0ubuntu1.16 (amd64, noble-updates/main or noble-security/main, Ubuntu 24.04), xorriso=1:1.5.6-1.1ubuntu3 (amd64, noble/main, Ubuntu 24.04), make=4.3-4.1build2 (amd64, noble/main, Ubuntu 24.04), and git=1:2.43.0-1ubuntu7.3 (amd64, noble-updates/main or noble-security/main, Ubuntu 24.04) by the “Install boot smoke dependencies” step; the per-run identity for each is captured via dpkg-query and normalized apt source pockets by tools/build-provenance.sh. The bump procedure mirrors OVMF: run apt-cache madison <tool> on a current Ubuntu 24.04 host, pick the highest stable version from noble-updates/main (or noble/main when no noble-updates entry exists, as is the case for xorriso and make today), and update the pinned version string in .github/workflows/ci.yml plus this row. make run-uefi selects an OVMF firmware blob from OVMF_CODE_CANDIDATES in Makefile:96-97; the Makefile pins the expected blob via OVMF_CODE_SHA256 and the ovmf-verify target enforces the match before ISO and cloud-disk construction. On the qemu-smoke CI runner the ovmf=2024.02-2ubuntu0.8 apt-install resolves the first candidate (/usr/share/ovmf/OVMF.fd), ovmf-verify succeeds against the pinned digest, and make build-provenance records the resulting firmware-blob SHA-256 per run. Build hosts without any OVMF candidate installed see an ovmf-verify NOTICE skip rather than a failure, so research workflows that never invoke make run-uefi continue to build the ISO unchanged.

Remaining gap for Security Verification Track S.10.3: decide whether full production reproducibility uses an immutable runner image digest, repo-managed download-and-verify tool digests for the apt-pinned build/boot tools, or both. build-essential, curl, sha256sum, the shell, and the checkout-time git used by actions/checkout remain runner-provided; the PR-blocking provenance gate records and compares the post-checkout build environment, but it does not turn the mutable ubuntu-24.04 runner label into an immutable production image.

GitHub Actions Runner and Workflow Pinning

The CI harness in .github/workflows/ci.yml is itself a supply-chain input: its identities determine which third-party code runs against every push and pull request, and the chosen runner image determines the host package set underneath every host-baseline, Kani, and optional QEMU job. Mutable @v<N> or @master references on third-party Actions would allow upstream owners to swap out the executed code at any time without a repository diff, and ubuntu-latest would silently roll the runner OS when GitHub re-points it.

The current policy is to pin every third-party Action to a 40-character commit SHA and to pin the runner OS to a specific release rather than the floating label. Each pinned uses: line carries a trailing # v<X.Y.Z> comment so reviewers and bump PRs can read the intended release without following the SHA through the GitHub UI.

IdentityPinned referenceNotes
runs-on: runner imageubuntu-24.04Replaces ubuntu-latest; applied to host-baseline, kani-proofs, dma-assurance-models, and qemu-smoke. GitHub-hosted ImageOS and ImageVersion are recorded in target/build-provenance.txt when present and are compared by the PR-blocking CI environment policy. Bump only when the next LTS is needed and the full make check plus QEMU smokes are reverified against the new image.
actions/checkout34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1Resolved from the actions/checkout v4 major-version tag.
swatinem/rust-cachec19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1Canonical Swatinem/rust-cache v2.9.1 release commit. The v2 major-tracking tag carries the same 2.9.1 message but points at a distinct republication commit; always dereference the exact release tag rather than the major tag.
dtolnay/rust-toolchain3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master @ 2026-03-27The upstream action does not publish numbered releases; its documented usage is @master. The pin is a snapshot of master at the dated commit.
actions/upload-artifactea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2Resolved from the actions/upload-artifact v4.6.2 lightweight tag (same SHA as the moving v4 major tag at resolution time). Used in qemu-smoke to publish target/build-provenance.txt.
actions/download-artifactd3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0Resolved from the actions/download-artifact v4.3.0 release tag. Paired with actions/[email protected] (both v4 series) and used in qemu-smoke on pull_request events to fetch the most recent successful main-branch build-provenance-<sha> artifact for the blocking make build-provenance-compare BUILD_PROVENANCE_COMPARE_POLICY=ci-environment step.

Bump procedure for any of the entries above:

  1. Resolve the candidate release to its commit SHA via the upstream release tag, e.g. gh api repos/<owner>/<repo>/git/ref/tags/v<X.Y.Z> (dereference any annotated tag through gh api repos/<owner>/<repo>/git/tags/<sha>), or gh api repos/<owner>/<repo>/commits/<branch> for branch-tracked actions like dtolnay/rust-toolchain. Always dereference the exact release tag (vX.Y.Z) rather than the moving major-version tag (vX): major-version tags can be re-cut at a republication commit whose tag message still names the same release (as observed for swatinem/rust-cache@v2), so following vX can pin a different commit than the canonical vX.Y.Z release.
  2. Update both the SHA and the trailing # v<X.Y.Z> comment in .github/workflows/ci.yml so the reviewer sees the intended release.
  3. Run make fmt-check and make workflow-check locally for the bump branch. Workflow hygiene plus YAML well-formedness must pass before review. The acceptance gate for the bump itself is a green CI run on the bump branch – make check plus the existing QEMU smokes – which exercises the new Action versions end-to-end.
  4. Treat any master-branch SHA pin (currently dtolnay/rust-toolchain) as a manual-bump dependency: the upstream action does not publish release tags, so bumping its SHA is the only way to absorb upstream fixes. Schedule those bumps explicitly rather than relying on a floating reference.

This pinning closes the mutable-tag supply-chain gap for the CI harness itself. It does not by itself satisfy the “pinned runner image digest” line of the Build Provenance Retention And Comparison Policy: ubuntu-24.04 is still a label managed by GitHub Actions, not an immutable image digest. The current documented equivalent for PR gating is to retain the GitHub-hosted ImageOS/ImageVersion fields in target/build-provenance.txt and compare them against the latest successful main-branch record. A future production-hardening slice may move to a self-built runner image referenced by digest, mirror the build-tool packages, or both.

Inventory Method

This inventory is based on source inspection, Cargo metadata, lockfile checks, and local host-tool version queries. Local host-tool versions are observations, not repository pins; the tables above distinguish enforced pins from observed environment state.

Useful commands for refreshing the inventory:

  • git status --short --branch
  • rg -n "S\\.10|trusted|supply|Limine|limine|capnp|capnpc|QEMU|qemu|download|curl|git clone|wget|build\\.rs|rust-toolchain|Cargo\\.lock" ...
  • rg --files
  • cargo metadata --locked --format-version 1 --no-deps
  • rg -n '^name = |^version = |^checksum = ' Cargo.lock init/Cargo.lock demos/Cargo.lock tools/mkmanifest/Cargo.lock tools/ringtap-viewer/Cargo.lock capos-rt/Cargo.lock shell/Cargo.lock libcapos/Cargo.lock libcapos-posix/Cargo.lock capos-wasm/Cargo.lock fuzz/Cargo.lock
  • command -v rustc cargo capnp cue qemu-system-x86_64 xorriso sha256sum git make
  • rustc -Vv, cargo -V, capnp --version, cue version, qemu-system-x86_64 --version, xorriso -version, make --version, git --version