Files
server-deploy/internal/aptrepo

Staged Docker repository authentication

deployctl verify-repository accepts strict JSON with directory (absolute trusted staging directory), suite, architecture, and versions (exact version strings for docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin and docker-compose-plugin). It does not select a latest version or resolve dependencies.

The directory must contain docker.asc, Release, Release.gpg and uncompressed Packages. The caller obtains these from the Docker Ubuntu repository. No runtime network request is performed by this command. Limits are 1 MiB, 1 MiB, 64 KiB and 16 MiB respectively. Files must be nonempty regular files; symlinks are rejected. Trusted ancestors and absence of concurrent writers are required. This is not an atomic filesystem snapshot against hostile writers. Additional staging files are ignored, never executed.

Trust and verification

  1. Exact armored key SHA-256 is pinned in source. Initial trust was bootstrapped from https://download.docker.com/linux/ubuntu/gpg, not supplied by the request. Primary fingerprint: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88. Rotation or formatting changes require a reviewed source update; fail closed.
  2. Linux /usr/bin/gpg dearmors into a new private temporary directory; /usr/bin/gpgv verifies the detached signature against the copied Release bytes, with that keyring and isolated homedir. No shell, ambient GnuPG config or personal keyring. Each child has a 15-second timeout and bounded output. Errors do not expose raw GnuPG diagnostics or metadata. Non-Linux or missing tools fail closed.
  3. Successful process exit and a single accepted primary-fingerprint signature are required; weak digests, expired/revoked/bad signatures and unknown status types fail closed. SHA-256/384/512 are accepted.
  4. Authenticated Release must describe Docker CE and the requested supported Ubuntu suite, architecture and stable component. Date must be within 30 days and no more than 10 minutes in the future; Valid-Until is enforced when present.
  5. The exact uncompressed stable Packages entry's SHA-256 and byte size must match. Five explicitly requested versions are resolved to authenticated index records; the derived lock is checked by installplan's source/path/version constraints.

The machine clock, OS and installed GnuPG are trusted. This is not a persistent anti-rollback ledger: an older authentic Release inside the freshness window can pass, and a missing Valid-Until is governed by the local 30-day policy. No online key revocation lookup is performed. Key pin maintenance is an operator responsibility.

Result boundaries

repositoryAuthenticated: true attests to these metadata bytes at verifiedAt. For verify-repository, packageBytesVerified: false and executable: false remain explicit: no deb bytes, Ubuntu dependency repository, dependency closure, installation scripts, system compatibility or service behavior have been verified. The result is not a signed capability. plan-environment still treats a supplied lock as untrusted and does not accept a caller's authentication claim to clear its trust blockers.

Signature scratch data is removed on normal return; a killed process can leave its own private temporary directory. Deployment writes remain disabled. writesEnabled in version refers to deployment writes, not verification scratch files.

scripts/probe-docker-repository.sh /absolute/path/to/deployctl is an optional local online integration check. It downloads public metadata over HTTPS into a new temporary directory, tests real authentication and rejects tampering. Versions selected by this test are fixtures, not recommended installation versions. It does not install packages, alter APT, use SSH or touch application data.

Verify actual deb bytes

verify-artifacts requires the same request fields as verify-repository, plus artifactDirectory: an absolute trusted directory containing exactly the five deb files named by the basename of each authenticated Filename. No other entries, subdirectories, symlinks or special files are accepted. The two directories must not be concurrently modified. Repository signatures and metadata are verified anew in the same call; the command accepts neither a supplied lock nor trust flags.

Each file is streamed through SHA-256 with a 64 KiB copy buffer and its signed index size as the read bound (plus one overflow-detection byte). The existing lock policy caps each file at 512 MiB and requires exactly five files. A last-file failure rejects the entire result. No partial successful report is emitted. The verifier never unpacks a deb or executes its contents. It does not change the staged files. Metadata identity checks supplement, not replace, the trusted directory/no concurrent writer requirement.

Only verify-artifacts may set packageBytesVerified: true; executable stays false. This verifies the selected five Docker package bytes, not the complete Ubuntu dependency closure, package-internal safety or installation compatibility. It is a point-in-time observation: do not reuse this JSON to authorize later execution of paths that may have changed. A future installer must recheck or own immutable verified snapshots under its operation lock.

Set DEPLOYCTL_ONLINE_ARTIFACT_PROBE=1 along with DEPLOYCTL_ONLINE_REPOSITORY_PROBE=1 when running scripts/verify-linux.sh to also download the five real public deb fixtures into a new local temporary directory. The optional probe verifies all files, then changes one byte without changing length and asserts rejection. It retains test files for inspection; they are not installed and one is intentionally damaged by the negative test.