7.8 KiB
2.1 image build trust
The reachable image-recipe/build-debian-iso.sh wrapper invokes the archived
builder; that builder is part of the supported source surface.
Debian Secure Boot chain
Both installation media and the installed ESP now preserve the Debian signed
shim, signed GRUB and MokManager payloads. The removable entry is shim, with the
matching GRUB beside it; the Debian vendor path is retained too. GRUB bootstrap
configuration resolves the installation-media label or installed root UUID,
then loads the complete /boot/grub/grub.cfg. Other vendor directories and
existing shim helpers are not deleted. No signing key or signature is generated.
scripts/secure_boot.py record obtains the exact installed package from a
trusted Debian APT index, verifies its archive SHA256 and compares required EFI
bytes with that archive. It records package/version/archive/file identities
before package indexes are cleaned. verify and stage compare those bytes
again and require the PE signature table reported by sbverify. Missing
provenance, unavailable verifier, unsigned/changed files or an invalid boot
identifier fail before copying the chain. The receipt inherits image/root
custody; it is not a standalone Debian signature or protection against root.
The kernel retains the existing authenticated Debian provenance and security
floor checks. EFI payload authentication does not replace those kernel checks.
This follows Debian's Secure Boot package chain and removable EFI layout. The source no longer requires disabling Secure Boot or generates an unsigned GRUB as a fallback. Previously published images retain their own acceptance and boot requirements.
Offline regression coverage exercises both amd64/arm64 layouts, distinct shim and GRUB bytes, label/UUID configuration, preserved vendor content, tampered, stripped and missing payloads, provenance/origin failures, unavailable verifier and unsafe destination/configuration paths. Signature-tool/authority boundaries use fixtures; they do not certify a firmware boot. Actual selected Debian packages, firmware trust/DBX/SBAT state, successful boot and rejection of a modified boot component still require an explicitly selected disposable image and firmware environment. No ISO was built, signed or booted for this source change.
Explicit image inputs
The builder now requires --source-ref <full commit> and --input-manifest <JSON>. scripts/image_inputs.py refuses a different/dirty tracked checkout,
missing provenance references, missing baseline archives, mismatched hashes,
unsafe archive members and standalone AIUI. It copies inputs into a fresh staging
area and hashes the copied bytes again. Native AIUI must be part of the qualified
dashboard payload. The release wrapper binds the selected backend/frontend hashes
to its signed OTA bytes; the UAT wrapper binds them and the radio tools to its
qualification receipt. This adds input selection, not a replacement signing
scheme. A manifest is reviewed evidence, not self-authenticating provenance.
Schema 1 has source_ref, architecture (amd64 or arm64), explicit positive
build_number and source_date_epoch, and two maps. Every map value has path,
sha256 and a nonempty provenance reference to the corresponding qualification.
Relative paths resolve beside the input manifest. artifacts contains exactly:
archipelago,archy-reticulum-daemon,archy-rnodeconf,archy-esptool;nostr-rs-relay,fips.deb,tailscale.deb, andweb-ui.tar(tar/gzip accepted).
container_archives maps safe .tar/.tar.zst filenames to reviewed inputs and
must include FileBrowser and fmcd. Image digests, signatures, platform selection,
licenses and packaged radio capability checks must be established by that input
qualification. No placeholder manifest or signatures are supplied. The source
workspace is bundled using git archive of the selected commit. No first-boot
clone, installed-node binary capture, newest-directory fallback, remote image
capture or tag-only image extraction remains in the reachable recipe.
The Debian OCI index is fixed at
sha256:9c6e381421d0f48d1b8133e573f33c185ee16cbf505eda9c4a8a4791b25ea8a6.
APT and debootstrap use Debian snapshot 20261109T224401Z and security snapshot
20261109T173309Z. Signed APT indexes and package hashes remain mandatory;
only snapshot expiration checks are disabled. An APT post-update hook also
requires the exact previously authenticated InRelease SHA256 values; runtime
provisioning removes that owned build-only hook. Snapshot transport uses HTTP to
bootstrap a minimal root before CA certificates are installed; Debian archive
signatures authenticate it. Registry HTTPS verification is never disabled.
The separately pinned ngit installer retains its version and archive hash checks.
FIPS and Tailscale are explicit qualified package inputs, not mutable build-time
repository resolutions. Runtime APT sources are installed by the offline policy
helper after build package operations. No automatic APT installation modifies the
build host. Cached rootfs payloads must match both the recipe/input hash and the
recorded archive hash.
Authenticated InRelease and Packages.xz checks on both architectures confirm the
selected snapshots contain signed shim/GRUB and security kernels including
6.12.113-1 and 6.12.116-1. These are package-index checks, not installed package or
firmware acceptance. Evidence is retained in the 20261109 report's
image-inputs-readonly/verified-boot-package-indexes-resume.json.
Input locking is not a bit-for-bit ISO reproducibility claim: filesystem creation, installation-time values, imported toolchains and final media layout still need paired immutable builds. Existing signed/UAT checks remain required. No ISO, OTA, APK, production signature or installed-node change was made for this work.
Host and application policy
The builder provisions image-recipe/host-policy into the exported root and
again after final installer service setup. It refuses /, unsafe paths, foreign
APT sources, differing existing assets and foreign systemd masks. This is a
fresh-image operation, not an installed-node migration.
The owned nft transaction replaces only the fips and archipelago_host
tables after custody and syntax checks; foreign tables and independent drops
remain authoritative. Host input/forward default to drop, output remains allowed.
FIPS publishing/SSH drop-ins remain scoped to fips0; HTTPS and WireGuard are
explicitly preserved. Private app ports, WG forwarding and named container
bridges are allowed; arbitrary bridges and TollGate bridging are not.
The firewall service must succeed before configured network/listener services. The application-profile service must load and observe all eight manifest-named profiles in enforce mode before application startup. Profiles provide a shared container baseline, not per-app exhaustive least-privilege policies: app data and networking remain usable while mounts, kernel control writes and control-secret paths are denied. OCI mounts/capabilities/seccomp remain essential boundaries. Missing profiles fail container creation; they are never silently disabled.
Qualification includes real disposable namespace packets (IPv4/IPv6, WG, FIPS publication/removal, app/SSH denial, container forwarding, TollGate denial, invalid transaction preservation and independent foreign drops), offline provisioning/refusal/idempotence, and actual systemd sandbox/failure dependency checks. The exact Grafana profile also passed positive app-data and negative control-secret access using a private Podman store/rootfs and a disposable AppArmor policy namespace; namespace and storage cleanup passed. This does not qualify complete app images, Docker, every deployment topology or a machine boot. Retain those explicit artifact/runtime gates before release.