Task 9 (closeout) of the Secrets gRPC-hub program. Bookkeeping only; no code. - clustered-secrets.md, Production enablement: the gRPC hub is no longer pending. It is BUILT, SHIPPED (0.4.1) and LIVE-GATED PASS 4/4 (ScadaBridge main @ f6c3f7c5, docs/plans/2026-08-07-secrets-grpc-hub-live-gate.md), so the "until that ships, ScadaBridge replication stays off" line is replaced with the truth: the code path is merged and gated, and production enablement is a separate operator action behind a still-default-off flag. OtOpcUa's pair-local topology is recorded as live-gated (lmxopcua master @ 1bd79c8e) rather than pending re-gate. Rotation fan-out corrected: on ScadaBridge it is BOTH central nodes plus both nodes of every site pair, because each central node has its own independent store. - components/secrets/GAPS.md: new "gRPC hub delivered" section recording the 0.4.0/0.4.1 publish, both gates with SHAs and gate-doc paths, and the residual. Existing narrative left intact and amended, not rewritten. - CLAUDE.md Secrets row: lib version 0.3.0 -> 0.4.1 and the app-pin claim corrected (ScadaBridge pins 0.4.1 for the Grpc replicator; the other three still pin 0.2.3); the "production topologies DECIDED" region now records delivery, both gates, default-off, and the residual. - Plan ledger: task 9 completed. Residual carried forward as scadaproj#4 — ScadaBridge's central pair does not converge with itself (central-b served an authenticated but EMPTY manifest all gate while central-a held every secret) and the site client dials a single endpoint; these are one design question, since failover to an empty hub would succeed and silently stop convergence. scadaproj#3 is closed. Claude-Session: https://claude.ai/code/session_014WNM4vjoVksyyBraTXSZE1
Secrets (encrypted secret store + ${secret:} resolution)
Normalizes how the family stores and consumes secrets — SQL/login passwords, API-key HMAC
peppers, LDAP bind passwords, connection strings, TLS material — which are handled ad-hoc
and inconsistently across the three apps today (Data-Protection-encrypted connection
strings in ScadaBridge; peppers/passwords in environment variables; LDAP passwords in
appsettings).
The goal is the shared ZB.MOM.WW.Secrets library: AES-256-GCM envelope encryption at
rest, a pluggable master-key provider and store, an audited ISecretResolver +
${secret:name} config expander for app runtime, and a Blazor /admin/secrets management
UI. The library is built, published (0.1.2), and live-proven via its reference consumer;
per-app adoption is the tracked follow-on.
- Target:
spec/SPEC.md - Realized API:
shared-contract/ZB.MOM.WW.Secrets.md - Implementation:
../../ZB.MOM.WW.Secrets/· designdocs/plans/2026-07-15-secrets-manager-design.md - Adoption backlog:
GAPS.md
Status
| State | |
|---|---|
| Library | Built + published — ZB.MOM.WW.Secrets{,.Abstractions,.Ui} 0.1.2 on the dohertj2-gitea feed; .Cli in-repo (not packed); .Akka replicator deferred (design only) |
| Reference consumer | HistorianGateway — adopted + live-proven (2026-07-16): historian password sourced via ${secret:}, authenticated read against the real wonder historian |
| Three sister apps | Not yet adopted — see per-app current-state + GAPS |
Per-project current state
| Project | Today (baseline) | Doc |
|---|---|---|
| OtOpcUa | (code-verified baseline) | current-state/otopcua/CURRENT-STATE.md |
| MxAccessGateway | (code-verified baseline) | current-state/mxaccessgw/CURRENT-STATE.md |
| ScadaBridge | (code-verified baseline) | current-state/scadabridge/CURRENT-STATE.md |
Not applicable as a fourth adopter row but the exemplar: HistorianGateway already consumes the lib — its wiring is the template the three apps follow (see the shared-contract "Consumer wiring" section).