#219: verified reproducible build without network access
All checks were successful
CI / Lint, typecheck, test (pull_request) Successful in 6m45s
CI / Build container images (pull_request) Successful in 1m14s
CI / Auth e2e pack (pull_request) Successful in 8m37s
CI / Import/export fidelity gate (pull_request) Successful in 57s
CD / Build and push images (push) Successful in 21s
CD / Deploy to Test (push) Successful in 12s
CD / Smoke tests against Test (push) Successful in 1m16s
CD / Promote to Int (push) Successful in 28s
CI / Lint, typecheck, test (push) Successful in 6m19s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Successful in 8m12s
CI / Import/export fidelity gate (push) Successful in 58s
All checks were successful
CI / Lint, typecheck, test (pull_request) Successful in 6m45s
CI / Build container images (pull_request) Successful in 1m14s
CI / Auth e2e pack (pull_request) Successful in 8m37s
CI / Import/export fidelity gate (pull_request) Successful in 57s
CD / Build and push images (push) Successful in 21s
CD / Deploy to Test (push) Successful in 12s
CD / Smoke tests against Test (push) Successful in 1m16s
CD / Promote to Int (push) Successful in 28s
CI / Lint, typecheck, test (push) Successful in 6m19s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Successful in 8m12s
CI / Import/export fidelity gate (push) Successful in 58s
The ADR 0024 §4 decision, taken explicitly and both ways: customers OPERATE prebuilt digest-pinned images (no customer-side build), and ADDITIONALLY the workspace build is verified to work with networking disabled - so site-local patching stays possible without internet. Evidence (docs/vs-nfd/96-offline-build-protokoll.md): pnpm install --offline --frozen-lockfile plus pnpm build under docker run --network none (node:22.15.1-alpine + pnpm 11.9.0, the pinned toolchain), reproduced twice from clean checkouts with identical results. The offline kit is the pnpm store (~870 MB) plus the build user's ~/.cache (~460 MB - the prisma engines live there; without the cache the prisma postinstall fails offline). The one network dependency found and bounded: the drawio plugin's installable ZIP fetches its pinned vendor tarball on first build. Deploy images contain no plugin ZIPs, so the delivery-relevant build is fully offline (CI=1 skips the fetch, as in CI); an offline ZIP build pre-seeds the tarball into packages/plugins/drawio/vendor/. Also catches up the operations manual's scheduler-job table to 10 (read-trail-maintenance was added in #224 without the row here). Refs #219. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AUtYMxwTCMHG9mVHnwbFg8
This commit is contained in:
parent
2f7ba65eef
commit
a758c9d78b
@ -41,6 +41,27 @@ documented mirror or update path.
|
|||||||
bundle, verify by digest, back up, apply, verify, roll back — with the
|
bundle, verify by digest, back up, apply, verify, roll back — with the
|
||||||
irreversibility of migrations stated explicitly.
|
irreversibility of migrations stated explicitly.
|
||||||
|
|
||||||
|
## Decisions taken in #219
|
||||||
|
|
||||||
|
- **Both paths, with stated roles**: customers OPERATE prebuilt,
|
||||||
|
digest-pinned images (the CI release build; mirrored per #218) — no
|
||||||
|
customer-side build for operation. ADDITIONALLY the workspace build is
|
||||||
|
verified to work with networking disabled, so site-local patching
|
||||||
|
remains possible (open source as an audit advantage) — the "no local
|
||||||
|
patching" consequence therefore does not apply.
|
||||||
|
- **The offline kit** is the pnpm store plus the build user's `~/.cache`
|
||||||
|
(the prisma postinstall pulls its engines from there instead of the
|
||||||
|
network) — both filled by one online `pnpm install --frozen-lockfile`.
|
||||||
|
- **Evidence**: `pnpm install --offline --frozen-lockfile` and
|
||||||
|
`pnpm build` under `docker run --network none` (node:22.15.1-alpine,
|
||||||
|
pnpm 11.9.0 — the pinned toolchain), reproduced twice from clean
|
||||||
|
checkouts (`docs/vs-nfd/96-offline-build-protokoll.md`).
|
||||||
|
- **The one network dependency found**: the drawio plugin's installable
|
||||||
|
ZIP fetches its pinned vendor tarball on first build. Deploy images
|
||||||
|
contain no plugin ZIPs, so the delivery-relevant build is fully
|
||||||
|
offline (`CI=1` skips the fetch, as in CI); for an offline ZIP build
|
||||||
|
the tarball is pre-seeded into `packages/plugins/drawio/vendor/`.
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
- Digest pinning creates recurring maintenance: security updates now
|
- Digest pinning creates recurring maintenance: security updates now
|
||||||
|
|||||||
@ -71,7 +71,7 @@ gehen" ist dort eine schlechtere Antwort als „getestet, hier ist die Anleitung
|
|||||||
|
|
||||||
- [x] Alle Images auf Digest pinnen (schließt den `gotenberg:8`-Punkt ein) · 1 AT · #203
|
- [x] Alle Images auf Digest pinnen (schließt den `gotenberg:8`-Punkt ein) · 1 AT · #203
|
||||||
- [x] Mirror-Verfahren in interne Registry dokumentieren · 1 AT · #218
|
- [x] Mirror-Verfahren in interne Registry dokumentieren · 1 AT · #218
|
||||||
- [ ] Build ohne Netz reproduzierbar (pnpm Offline-Store / reine
|
- [x] Build ohne Netz reproduzierbar (pnpm Offline-Store / reine
|
||||||
Prebuilt-Images) · 2–3 AT · #219
|
Prebuilt-Images) · 2–3 AT · #219
|
||||||
- [ ] Testlauf in netzisolierter Umgebung, Protokoll als Beleg · 2 AT · #220
|
- [ ] Testlauf in netzisolierter Umgebung, Protokoll als Beleg · 2 AT · #220
|
||||||
- [ ] Offline-Update-Pfad inkl. Migrationen · 2–3 AT · #221
|
- [ ] Offline-Update-Pfad inkl. Migrationen · 2–3 AT · #221
|
||||||
|
|||||||
@ -57,10 +57,16 @@ dokumentiert die realen Instanzen).
|
|||||||
auf den Spiegel zeigen. Vollständige Prozedur:
|
auf den Spiegel zeigen. Vollständige Prozedur:
|
||||||
`deploy/stages.md` §5b; Ausführungsnachweis:
|
`deploy/stages.md` §5b; Ausführungsnachweis:
|
||||||
`95-mirror-protokoll.md`.
|
`95-mirror-protokoll.md`.
|
||||||
- ⏳ offen: netzloser Build (#219), Testlauf in isolierter Umgebung
|
- **Netzloser Build (#219): ✅ verifiziert und entschieden.** Betrieb
|
||||||
(#220), Offline-Update-Pfad (#221); Meilenstein M28. Bereits vorhanden
|
läuft aus Prebuilt-Images; zusätzlich ist der Workspace-Build ohne
|
||||||
als Grundlage: alle Dritt-Images digest-gepinnt (#203), ein
|
Netz zweifach reproduziert (Offline-Kit = pnpm-Store + Build-Cache;
|
||||||
authoritativer Node-Pin (#236), SBOMs je Release (#202).
|
einzige Grenze: das installierbare drawio-Plugin-ZIP braucht sein
|
||||||
|
vorab abgelegtes Vendor-Tarball). Entscheidung und Prozedur:
|
||||||
|
ADR 0024 §Decisions, Nachweis: `96-offline-build-protokoll.md`.
|
||||||
|
- ⏳ offen: Testlauf in isolierter Umgebung (#220), Offline-Update-Pfad
|
||||||
|
(#221); Meilenstein M28. Bereits vorhanden als Grundlage: alle
|
||||||
|
Dritt-Images digest-gepinnt (#203), ein authoritativer Node-Pin
|
||||||
|
(#236), SBOMs je Release (#202).
|
||||||
|
|
||||||
## 2 Update und Rollback
|
## 2 Update und Rollback
|
||||||
|
|
||||||
@ -120,10 +126,10 @@ Referenz: `docs/operations/restore-runbook.md` (maßgeblich),
|
|||||||
|
|
||||||
Alle Jobs laufen in der api (in-app Scheduler, `jobs`-Tabelle), sind im
|
Alle Jobs laufen in der api (in-app Scheduler, `jobs`-Tabelle), sind im
|
||||||
Site-Admin-Systempanel sichtbar und dort manuell auslösbar (auditiert
|
Site-Admin-Systempanel sichtbar und dort manuell auslösbar (auditiert
|
||||||
als `job.triggered`). Aktueller Bestand (9):
|
als `job.triggered`). Aktueller Bestand (10):
|
||||||
|
|
||||||
| Job | Rhythmus | Wirkung |
|
| Job | Rhythmus | Wirkung |
|
||||||
| -------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
| -------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| `trash-purge` | täglich | endgültiges Löschen abgelaufener Papierkorb-Seiten **und** -Teiche (`trash.retentionDays`, #31/#193) |
|
| `trash-purge` | täglich | endgültiges Löschen abgelaufener Papierkorb-Seiten **und** -Teiche (`trash.retentionDays`, #31/#193) |
|
||||||
| `orphan-file-sweep` | täglich | verwaiste Uploads entfernen (#194); trägt nachts auch den SHA-256-Backfill (#199) |
|
| `orphan-file-sweep` | täglich | verwaiste Uploads entfernen (#194); trägt nachts auch den SHA-256-Backfill (#199) |
|
||||||
| `page-compaction` | stündlich | `page_updates`-Log in den Zustand mergen |
|
| `page-compaction` | stündlich | `page_updates`-Log in den Zustand mergen |
|
||||||
@ -133,6 +139,7 @@ als `job.triggered`). Aktueller Bestand (9):
|
|||||||
| `mail-outbox-retention` | täglich | SENT/endgültig FAILED Outbox-Zeilen löschen (#234) |
|
| `mail-outbox-retention` | täglich | SENT/endgültig FAILED Outbox-Zeilen löschen (#234) |
|
||||||
| `data-export-purge` | stündlich | abgelaufene DSGVO-Datenexporte entfernen (#68) |
|
| `data-export-purge` | stündlich | abgelaufene DSGVO-Datenexporte entfernen (#68) |
|
||||||
| `notification-digest` | alle 15 min (Versand nach Nutzer-Präferenz) | Benachrichtigungs-Digests versenden |
|
| `notification-digest` | alle 15 min (Versand nach Nutzer-Präferenz) | Benachrichtigungs-Digests versenden |
|
||||||
|
| `read-trail-maintenance` | täglich | Lesetrail-Partitionen vorausanlegen + `read_events` nach `readTrail.retentionDays` beschneiden (#224, auditiert `read_trail.pruned`) |
|
||||||
|
|
||||||
Der e2e-Zaun `apps/web/e2e/system.spec.ts` pinnt diese Zahl — ein
|
Der e2e-Zaun `apps/web/e2e/system.spec.ts` pinnt diese Zahl — ein
|
||||||
neuer Job ohne Handbuch-/Zaun-Anpassung wird rot.
|
neuer Job ohne Handbuch-/Zaun-Anpassung wird rot.
|
||||||
|
|||||||
78
docs/vs-nfd/96-offline-build-protokoll.md
Normal file
78
docs/vs-nfd/96-offline-build-protokoll.md
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
# Offline-Build-Protokoll — Build ohne Netzzugang (Issue #219)
|
||||||
|
|
||||||
|
Nachweis für die in ADR 0024 §4 geforderte, ausdrücklich getroffene
|
||||||
|
Entscheidung zur Reproduzierbarkeit ohne Netz. Belegstufe: **live
|
||||||
|
verifiziert** — zweifach aus sauberem Checkout reproduziert.
|
||||||
|
|
||||||
|
- **Datum:** 2026-07-31
|
||||||
|
- **Toolchain (gepinnt):** Container `node:22.15.1-alpine` (identisch
|
||||||
|
zum Basis-Image der Deploy-Images, Node-Pin #236), pnpm `11.9.0`
|
||||||
|
(`packageManager`-Feld in `package.json`, via corepack aktiviert).
|
||||||
|
- **Netzisolation:** `docker run --network none` — der Build-Container
|
||||||
|
hat keinerlei Egress; jede Netzabhängigkeit schlägt hart fehl.
|
||||||
|
|
||||||
|
## Entscheidung (ADR 0024 §4)
|
||||||
|
|
||||||
|
**Beides, mit klarer Rollenverteilung:**
|
||||||
|
|
||||||
|
1. **Ausgelieferte Instanzen laufen aus Prebuilt-Images** (Release-Build
|
||||||
|
der CI, digest-gepinnt, gespiegelt nach `95-mirror-protokoll.md`) —
|
||||||
|
der Kunde baut für den Betrieb nichts selbst.
|
||||||
|
2. **Zusätzlich ist der Workspace-Build ohne Netz verifiziert** — die
|
||||||
|
Behörde KANN lokal patchen (Quelloffenheit als Prüfvorteil), ohne
|
||||||
|
dass dafür Internetzugang nötig wäre.
|
||||||
|
|
||||||
|
## Offline-Kit
|
||||||
|
|
||||||
|
Einmalig auf einem Rechner **mit** Netz erzeugt:
|
||||||
|
|
||||||
|
| Bestandteil | Erzeugung | Inhalt |
|
||||||
|
| ------------------------------------ | ------------------------------------------------------ | ------------------------------------------------------------------- |
|
||||||
|
| pnpm-Store (~870 MB) | `pnpm install --frozen-lockfile` mit `store-dir`-Mount | alle Pakete exakt nach `pnpm-lock.yaml` |
|
||||||
|
| `~/.cache` des Build-Users (~460 MB) | fällt beim selben Install an | u. a. die Prisma-Engines, die das prisma-Postinstall sonst nachlädt |
|
||||||
|
| optional: `drawio-30.3.6.tar.gz` | einmalig von der gepinnten GitHub-Release-URL | nur für das installierbare drawio-Plugin-ZIP nötig (s. u.) |
|
||||||
|
|
||||||
|
## Prozedur (offline)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# sauberer Checkout + Offline-Kit gemountet, KEIN Netz:
|
||||||
|
docker run --rm --network none -e CI=1 \
|
||||||
|
-v <checkout>:/work -v <store>:/pnpm-store -v <cache>:/root/.cache \
|
||||||
|
-w /work node:22.15.1-alpine sh -c '
|
||||||
|
corepack enable && corepack prepare pnpm@11.9.0 --activate
|
||||||
|
pnpm config set store-dir /pnpm-store
|
||||||
|
pnpm install --offline --frozen-lockfile
|
||||||
|
pnpm build'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ergebnis
|
||||||
|
|
||||||
|
| Lauf | Checkout | `pnpm install --offline` | `pnpm build` | Artefakte geprüft |
|
||||||
|
| ---- | -------------------- | ------------------------ | ------------ | --------------------------------------------------- |
|
||||||
|
| 1 | frisch (git archive) | OK (11,8 s) | Exit 0 | `apps/api/dist/main.js`, `apps/web/dist/index.html` |
|
||||||
|
| 2 | frisch (git archive) | OK | Exit 0 | identisch vorhanden |
|
||||||
|
|
||||||
|
## Befund und bewusste Grenze
|
||||||
|
|
||||||
|
- **Einzige Netzabhängigkeit im Build:** das drawio-Plugin holt beim
|
||||||
|
ersten Bau seines **installierbaren ZIPs** das gepinnte
|
||||||
|
draw.io-Release-Tarball (v30.3.6) von GitHub nach `vendor/`. Ohne Netz
|
||||||
|
und ohne `CI=1` schlägt genau dieser Schritt fehl (beobachtet, Lauf 0
|
||||||
|
dieses Protokolls).
|
||||||
|
- **Einordnung:** Die Deploy-Images enthalten keine Plugin-ZIPs —
|
||||||
|
Plugins werden zur Laufzeit über die Dropzone installiert. Der
|
||||||
|
auslieferungsrelevante Build ist damit vollständig offline; `CI=1`
|
||||||
|
(der auch in der CI gilt) überspringt den Vendor-Fetch und baut das
|
||||||
|
Controller-Bundle. Wer das drawio-ZIP offline bauen will, legt das
|
||||||
|
Tarball aus dem Offline-Kit vorab als
|
||||||
|
`packages/plugins/drawio/vendor/drawio-30.3.6.tar.gz` ab — der Build
|
||||||
|
lädt nur, was nicht schon dort liegt.
|
||||||
|
- Prisma-Engines kommen offline aus `~/.cache` — der Cache gehört
|
||||||
|
deshalb fest zum Kit (ohne ihn schlägt das prisma-Postinstall fehl).
|
||||||
|
|
||||||
|
## Konsequenz „kein lokales Patchen"?
|
||||||
|
|
||||||
|
Entfällt — mit dem Offline-Kit ist lokales Patchen möglich. Wer es
|
||||||
|
organisatorisch ausschließen will, betreibt nur die Prebuilt-Images;
|
||||||
|
beides ist dokumentiert und die Wahl liegt beim Betreiber
|
||||||
|
(Betriebshandbuch §1).
|
||||||
Loading…
Reference in New Issue
Block a user