diff --git a/10-functional/features/f-platform/f5-dev-console.md b/10-functional/features/f-platform/f5-dev-console.md index 909aa1d..db538f8 100644 --- a/10-functional/features/f-platform/f5-dev-console.md +++ b/10-functional/features/f-platform/f5-dev-console.md @@ -90,6 +90,14 @@ panel ([F4](f4-backup-restore.md)), the sync quarantine view ([E6](../e-sync/e6-sync-status.md)), and a worker heartbeat that the boot probe reads. +The snapshot renders effective configuration and environment, so every +secret-bearing value is masked before it reaches the page. The match is on the +key, and it covers plural forms: a retired key list is as sensitive as the key +in use, and a rule written for the singular alone does not see it. A key whose +sensitivity is uncertain is masked — an over-masked diagnostic row costs a +reader one lookup, while an under-masked one publishes a secret to anything +that can read the page, including a screenshot or a support bundle. + The heartbeat is written from the worker's own loop rather than an event listener, because the listener form does not fire reliably under the worker. @@ -117,6 +125,8 @@ by architecture test, so no shipped code path can pull it in | A run finishing between two polls | The registry entry survives both; the closing audit record is durable. | | A worker dying mid-run | An opening record with no close; surfaced as an orphan. | | A credential rotated mid-output | The next line uses the new pattern; already-written lines keep the old redaction. | +| A retired key list alongside the key in use | Both are masked in the snapshot; the plural name is not a way out of the rule. | +| A benign key whose name resembles a secret | Masked. The rule errs toward masking, and the cost is one lookup. | | A query with a trailing statement | Rejected as multiple statements; semicolons inside quoted literals pass. | | A failed job pruned from the queue | The lifecycle log survives independently. | | The queue dashboard package absent | Registration is skipped silently. | @@ -150,6 +160,7 @@ by architecture test, so no shipped code path can pull it in | **F5-R23** | Development commands MUST be filtered out of the palette server-side for non-developers, and only the safe tier may appear at all. | | **F5-R24** | Queue-dashboard imports MUST be confined to a single file, enforced by architecture test. | | **F5-R25** | The queue dashboard MUST be registered only when both the development flag and the package are present. | +| **F5-R26** | The system snapshot MUST mask every secret-bearing configuration and environment value, matching singular and plural key forms alike, and MUST resolve an uncertain key toward masking. | ## Related diff --git a/40-quality/README.md b/40-quality/README.md index fce1101..aa9c4ac 100644 --- a/40-quality/README.md +++ b/40-quality/README.md @@ -48,6 +48,7 @@ itself. | **Q-R23** | A change that alters behaviour MUST cite a requirement identifier that already exists on the canonical spec. | | **Q-R24** | A user-visible change MUST carry a conventional commit subject written as release-note copy, in the user's language. | | **Q-R25** | A test MUST NOT be marked skipped or pending to make a gate green without a recorded reason. | +| **Q-R26** | A component property rendered as raw markup MUST be locked against client mutation. | ## The principle underneath diff --git a/40-quality/code-standards.md b/40-quality/code-standards.md index 76f94a6..dd76d0f 100644 --- a/40-quality/code-standards.md +++ b/40-quality/code-standards.md @@ -151,6 +151,14 @@ Credentials and secrets never appear in a serialisable component property, so they cannot reach a rendered snapshot — enforced by a registry-backed architecture test. +Output is escaped. Where a value must be rendered as raw markup — an inline +vector image is the honest case, since escaping it stops it drawing — the +property holding it is locked against client mutation. A serialisable component +property is rehydrated from the client on every request, so "the server built +this markup" is true only of the first render; without the lock the raw sink +accepts whatever the client returns. The lock and the raw echo are a pair, and +neither is safe to add or remove alone. + ## Related - [ADR-0001](../00-overview/decisions/0001-modular-architecture.md) · [ADR-0002](../00-overview/decisions/0002-di-only-rule.md) · [ADR-0009](../00-overview/decisions/0009-brick-money-multi-currency.md) · [ADR-0018](../00-overview/decisions/0018-amounts-plaintext-at-rest.md)