feat(transport): production-boundary signing advisory, secret-key proof, runbook (#110)

Owner decisions on #110: one signing key per environment; TrustedKeys stay hand-edited;
Signing:ProductionBoundary (new, default off) logs a startup warning and reports a Degraded
bundle-signing-policy /health/ready entry while RequireSignedBundles is off; the private key
is read via ${secret:} (proved end to end, never logged); cluster pull decided not to be
built; differential deletions stay deferred. Adds docs/operations/bundle-signing-runbook.md.

Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
Joseph Doherty
2026-11-09 22:50:18 -05:00
parent a4806576af
commit 559e02f5c8
11 changed files with 421 additions and 10 deletions
@@ -1,6 +1,6 @@
# Transport addendum — cluster-to-cluster pull and differential bundles (ScadaBridge#45)
**Date:** 2026-11-09 · **Status:** design addendum. Not implemented, and not scheduled.
**Date:** 2026-11-09 · **Status:** design addendum. **Owner decisions 2026-11-09 (ScadaBridge#110): pull — decided NOT to build; differential deletions — deferred.** Neither is implemented.
**Origin:** `2026-05-24-transport-design.md` §18 and deferred-work register row 19 (now Gitea #45).
The third deferred item, bundle signing, **is** implemented. See "Bundle Signing" in
`docs/requirements/Component-Transport.md`.
@@ -20,6 +20,8 @@ recommendation, so either feature can be picked up when there is a concrete need
## 1. Cluster-to-cluster pull
> **DECIDED — NOT TO BUILD (owner, 2026-11-09, ScadaBridge#110).** No cluster-to-cluster pull, no cross-environment network path, no stored cross-environment credential. The CLI export → import recipe below (Option A) is the supported path, with the receiving side requiring signed bundles (`docs/operations/bundle-signing-runbook.md`). The questions and options that follow are kept as a historical record only; do not build B or C without a new owner decision.
### What exists today
A pull can already be **orchestrated** without any new server code. The CLI speaks to any
@@ -74,6 +76,8 @@ design session before writing any of it.
## 2. Differential bundles
> **DEFERRED (owner, 2026-11-09, ScadaBridge#110).** Differential deletions (D2) stay out of scope: the importer never deletes and there are no tombstones. Import-side Identical auto-skip already gives the differential effect. The hash-only variant below remains an option only if file size or preview length becomes a real complaint.
### What exists today
Every export is a full snapshot of the selected artifacts plus, optionally, their dependency
@@ -114,11 +118,9 @@ unless D2 is designed on its own.
---
## Decisions this addendum leaves open
## Decisions (resolved 2026-11-09, ScadaBridge#110)
1. Pull: is any cross-environment network path acceptable to change control (P3)? Nothing else
can be decided until this is.
2. Pull: which machine identity, a stored service account or a new export-scoped credential (P1/P2)?
3. Differential: is propagating deletions in scope at all (D2)?
4. Signing, which the pull depends on: see the open decisions in Component-Transport.md
"Bundle Signing".
1. Pull: **not built.** No cross-environment network path (P3) and no machine identity (P1/P2) will be introduced.
2. Differential: deletions (D2) **stay deferred**; no tombstones.
3. Signing: one key per environment, hand-edited `TrustedKeys`, `${secret:}` key source, enforcement on at the
production boundary once every exporter signs — see `docs/operations/bundle-signing-runbook.md`.