dorfteich/docs/architecture/adr/0024-reproducible-offline-deployment.md
Claude Opus 5 fd07f716f6
All checks were successful
CI / Lint, typecheck, test (pull_request) Successful in 4m42s
CI / Build container images (pull_request) Successful in 1m11s
CI / Auth e2e pack (pull_request) Successful in 7m47s
CI / Import/export fidelity gate (pull_request) Successful in 55s
CD / Build and push images (push) Successful in 18s
CD / Deploy to Test (push) Successful in 14s
CD / Smoke tests against Test (push) Successful in 1m16s
CD / Promote to Int (push) Successful in 11s
CI / Lint, typecheck, test (push) Successful in 4m50s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Successful in 7m38s
CI / Import/export fidelity gate (push) Successful in 56s
docs: VS-NfD readiness planning (ist-aufnahme, plan, ADRs 0019-0026, issue drafts)
Add docs/vs-nfd/: the analysis brief, the as-is assessment (42 findings,
all verified against the code), the prioritized action plan rev. 2 with
issue references written back to every checkbox, the two-stage issue/ADR
brief, and the full reviewed draft used to create the forge state.

Add eight proposed ADRs 0019-0026 covering the VS-NfD architecture
decisions: no security base functions (par. 52 VSA anchor), HKDF token
key separation, external authentication, page classification, read-access
audit trail (variant A), reproducible offline deployment, plugin trust
model, and backup target restriction.

Forge state created alongside this commit: 11 labels, milestones M24-M31,
issues #188-#236 (docs-only change, no code touched).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168Ph5uBmHm8X28CSVpbpnJ
2026-07-30 01:48:05 +02:00

3.1 KiB

ADR 0024: Reproducible offline deployment

  • Status: proposed
  • Date: 2026-07-29

Context

A VS zone has no internet egress. "Should work offline" is the answer that loses a first meeting; "tested, here is the procedure" is the one that wins it — which is why the plan pulled this out of the roadmap into Phase 1.

The current state is favourable but unverified. There is no telemetry, no update check, no CDN; fonts are self-hosted (ADR 0016); CSP is default-src 'self'; search is Postgres rather than an external engine; the drawio plugin is vendored rather than loaded from a remote editor. What is missing is evidence, plus two real gaps: images are referenced by tag (including the floating gotenberg/gotenberg:8), and there is no documented mirror or update path.

Decision

  1. All third-party images are pinned by digest (name:tag@sha256:…). The tag stays for human readability; the digest decides what runs. A CI check rejects any un-digested third-party reference.
  2. The image list is generated, not hand-maintained, so a mirror procedure cannot silently miss a service.
  3. An internal registry is the supported source. Compose takes the registry prefix from configuration; no site edits image references.
  4. Reproducibility without network is a stated choice between two paths: an offline pnpm store enabling install + build with networking disabled, or prebuilt images only with no customer-side build. Either is acceptable; leaving it unstated is not, because it determines whether the customer can patch locally.
  5. The airgap claim is proven by a documented run in a network-isolated environment, covering every function including the export sidecars, and listing every outbound connection attempt observed. This run is the artefact, and it also answers the plan's open question about what breaks offline.
  6. The offline update path is part of the decision, not an afterthought: bundle, verify by digest, back up, apply, verify, roll back — with the irreversibility of migrations stated explicitly.

Consequences

  • Digest pinning creates recurring maintenance: security updates now require an explicit, reviewable change. That visibility is the point.
  • Digest pinning must precede the mirror and update work, so it sits in the hardening & supply chain milestone rather than this one.
  • The isolated test run will surface findings; each becomes its own issue referenced from #220 rather than expanding that issue's scope.
  • Outbound SMTP is the one connection an authority may or may not permit; the deployment must be functional without it, and the consequences of disabling it (no notifications, no verification mail — which interacts with auth.local.enabled = false) are documented.
  • CD does not sync stage composes, so digest changes need an explicit rollout step on the stage hosts.

Implementing issues

#203 (digest pinning), #218 (registry mirror), #219 (network-free build), #220 (isolated test run), #221 (offline update path), #236 (pinned Node version — added from the Ist-Aufnahme, I-26).