docs: site secrets ride the artifact deploy; gRPC hub retired in ScadaBridge
This commit is contained in:
@@ -281,6 +281,9 @@ Component-NotificationService.md). Notification delivery happens on the central
|
||||
cluster, so no notification artifact or SMTP credential is ever distributed to
|
||||
sites.
|
||||
|
||||
A site's **secrets** are a fifth, *derived* artifact class riding the same command —
|
||||
see *Site secrets* below.
|
||||
|
||||
### Per-site artifact revision (2026-09-14)
|
||||
|
||||
`Site` carries two nullable columns — `ArtifactRevisionHash` (`string?`, max 100)
|
||||
@@ -331,6 +334,59 @@ design**: a partial map would silently report the unqueried sites as up to date,
|
||||
so the pending-updates cache instead discards the faulted flight and the UI shows
|
||||
the aggregate as unavailable.
|
||||
|
||||
### Site secrets (2026-09-28)
|
||||
|
||||
Site secrets ride the artifact deploy instead of the (now retired) gRPC secrets
|
||||
hub — design `docs/plans/2026-09-28-site-secrets-artifact-deploy-design.md`; see
|
||||
that doc's *Implementation notes (as built)* section for the deviations called
|
||||
out below.
|
||||
|
||||
- **Derived, not configured.** `SiteSecretsCollector` scans the site's data
|
||||
connection artifacts (`SecretReferenceScanner` over `PrimaryConfigurationJson`
|
||||
/ `BackupConfigurationJson`) for `secret:<name>` string values and resolves
|
||||
each name against the central `ISecretStore`, producing the ciphertext-only
|
||||
`SecretArtifact` rows the command carries (`DeployArtifactsCommand.Secrets`,
|
||||
proto field 9) plus the set of unresolved references. A site with no `secret:`
|
||||
references ships no secrets and is unaffected by any of this.
|
||||
- **Fail closed, per site.** A site with one or more unresolved (absent or
|
||||
tombstoned) references fails its deploy *before* `_communicationService` is
|
||||
called — nothing is sent, the site keeps its previous stamp, and the error
|
||||
names the secret and the referencing data connection(s): `Secret 'X'
|
||||
referenced by data connection(s) A, B is not in the central secret store`
|
||||
(semicolon-joined for more than one). Other sites in the same sweep are
|
||||
unaffected.
|
||||
- **Stamp gating.** A site is stamped `ArtifactRevisionHash`/`ArtifactsDeployedAt`
|
||||
only when every shipped secret actually applied. Two failure shapes are
|
||||
distinguished from an ordinary site failure and never stamped: an **old
|
||||
site** (wire `Success = true`, secrets were shipped, but the response has no
|
||||
`SecretsApplied` at all — a pre-feature site build) fails with `Site build
|
||||
predates secret deployment — upgrade the site before deploying secrets`; a
|
||||
**partial apply** (`SecretsApplied` less than the shipped count) fails with
|
||||
`Site applied {n} of {m} secrets`. Both apply identically on the all-sites
|
||||
sweep (`DeployCoreAsync`) and the per-site retry (`RetryForSiteAsync`).
|
||||
- **Staleness hash.** `ArtifactRevisionHashService` folds secrets into the same
|
||||
hash as every other artifact class (`HashableSecret`: a SHA-256 digest of the
|
||||
ciphertext/nonce/tag/wrapped-DEK material, never plaintext, plus `KekId` and
|
||||
`Revision`) so a KEK rewrap correctly flips a site to out of date. A
|
||||
referenced-but-not-yet-created secret hashes as an explicit `Missing` marker
|
||||
(`DeployArtifactsCommand.MissingSecrets`, central-only — never on the wire),
|
||||
so that site reads *Out of date*, never *Current*, until the secret exists.
|
||||
**A `null` secrets list and an empty one hash identically** (the existing
|
||||
null-when-empty convention for every artifact class), so a site with no
|
||||
secret references keeps its pre-existing hash across the upgrade that added
|
||||
this feature.
|
||||
- **Audit.** One best-effort `DeploySiteSecrets` / `SiteSecrets` audit row is
|
||||
written per site deploy that carried secrets or a missing-secret failure
|
||||
(never for a site with no secret references at all) — after-state is `{
|
||||
deploymentId, secrets: [{name, revision}], missing: [name], success }`, which
|
||||
structurally excludes ciphertext. Written on both `DeployCoreAsync` and
|
||||
`RetryForSiteAsync`, including the fail-closed path (audited even though
|
||||
nothing was sent).
|
||||
- **Central store.** Central resolves secrets from `ISecretStore`, composed by
|
||||
the Host per `Secrets:Store:Provider` — see Component-Host.md → *Secrets*.
|
||||
- **Site apply and the per-node mirror** — see Component-SiteRuntime.md →
|
||||
*Deployed Secrets*.
|
||||
|
||||
## Site-Side Apply Atomicity
|
||||
|
||||
Applying a deployment at the site is **all-or-nothing per instance**:
|
||||
@@ -420,6 +476,7 @@ The Deployment Manager sends the following commands to sites via the Communicati
|
||||
- **Configuration Database (MS SQL)**: Stores deployment status and deployed configuration snapshots.
|
||||
- **Security & Auth**: Enforces Deployment role (with optional site scoping).
|
||||
- **Configuration Database (via IAuditService)**: Logs all deployment actions, system-wide artifact deployments, and instance lifecycle changes.
|
||||
- **`ZB.MOM.WW.Secrets.Abstractions`** (`ISecretStore`, `SecretName`): `SiteSecretsCollector` resolves a site's referenced secrets against the Host-composed central store — see Component-Host.md → *Secrets*.
|
||||
|
||||
## Interactions
|
||||
|
||||
|
||||
Reference in New Issue
Block a user