diff --git a/REGISTER.md b/REGISTER.md index 24d37ee..e1baeb8 100644 --- a/REGISTER.md +++ b/REGISTER.md @@ -8,13 +8,13 @@ Generated by `tools/register_index.py` from `findings/`. Do not edit by hand. La | ID | Finding | System | Severity | Disclosure | Escalation | Fix owner | Status | Cadence | Next check | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| [RISK-F-0009](findings/RISK-F-0009-openbao-deny-set-covers-a-third-of-high-risk-lanes.md) | agent-high-risk-boundary denies 6 of 17 high-risk lanes; the direct bao path is unprotected for the rest | railiance-platform | **high** | embargoed | none | railiance-platform | open | instant (0) | **due** | +| [RISK-F-0009](findings/RISK-F-0009-openbao-deny-set-covers-a-third-of-high-risk-lanes.md) | agent-high-risk-boundary denies 6 of 17 high-risk lanes; the direct bao path is unprotected for the rest | railiance-platform | **high** | embargoed | none | railiance-platform | open | 1h (1) | 2026-08-20 11:02Z | | [RISK-F-0008](findings/RISK-F-0008-audit-retention-legal-basis-assumed.md) | The legal basis for retaining audit facts against an erasure request has been assumed, never established | audit-core | medium | public | **required** (t2, partially-answered) | risk-nexus | open | instant (0) | **due** | | [RISK-F-0007](findings/RISK-F-0007-unverified-tenant-boundary.md) | No consumer's tenant boundary is verified anywhere | estate | **high** | embargoed | **answered** (t4, assigned) | per-consumer, on request | accepted | instant (0) | **due** | -| [RISK-F-0006](findings/RISK-F-0006-apps-pg-no-backup-configured.md) | apps-pg has no backup configured at all: R0 means no recovery | railiance-platform | **high** | embargoed | **answered** (t3, approved) | railiance-platform | open | instant (0) | **due** | -| [RISK-F-0005](findings/RISK-F-0005-audit-core-unfiltered-read-path.md) | audit-core read path applies no tenant filter; the bound is deployment, not code | audit-core | medium | embargoed | none | audit-core | open | instant (0) | **due** | -| [RISK-F-0004](findings/RISK-F-0004-tenant-engine-unfiltered-event-read.md) | tenant-engine events() returns the entire event log unfiltered | tenant-engine | **high** | embargoed | none | tenant-engine | open | instant (0) | **due** | -| [RISK-F-0003](findings/RISK-F-0003-ops-warden-read-boundary-ungraded-lanes.md) | ops-warden agent read-boundary does not fire on ungraded catalog lanes | ops-warden | medium | embargoed | none | ops-warden | mitigated | instant (0) | **due** | +| [RISK-F-0006](findings/RISK-F-0006-apps-pg-no-backup-configured.md) | apps-pg has no backup configured at all: R0 means no recovery | railiance-platform | **high** | embargoed | **answered** (t3, approved) | railiance-platform | open | 1h (1) | 2026-08-20 11:02Z | +| [RISK-F-0005](findings/RISK-F-0005-audit-core-unfiltered-read-path.md) | audit-core read path applies no tenant filter; the bound is deployment, not code | audit-core | medium | embargoed | none | audit-core | open | 1h (1) | 2026-08-20 11:02Z | +| [RISK-F-0004](findings/RISK-F-0004-tenant-engine-unfiltered-event-read.md) | tenant-engine events() returns the entire event log unfiltered | tenant-engine | **high** | embargoed | none | tenant-engine | open | 1h (1) | 2026-08-20 11:02Z | +| [RISK-F-0003](findings/RISK-F-0003-ops-warden-read-boundary-ungraded-lanes.md) | ops-warden agent read-boundary does not fire on ungraded catalog lanes | ops-warden | medium | embargoed | none | ops-warden | mitigated | 1h (1) | 2026-08-20 11:02Z | | [RISK-F-0002](findings/RISK-F-0002-ops-warden-sign-ungated.md) | ops-warden signs SSH certificates with no authorization decision, and its unblock is now unsafe | ops-warden | medium | embargoed | **withdrawn** (t6, withdrawn-hazard-window-closed) | ops-warden | open | instant (0) | **due** | | [RISK-F-0001](findings/RISK-F-0001-flex-auth-unauthenticated-check.md) | flex-auth /v1/check authenticates no caller | flex-auth | **high** | public | **withdrawn** (t1, withdrawn-before-sending) | flex-auth | fixed | instant (0) | **due** | diff --git a/docs/method/check-procedure.md b/docs/method/check-procedure.md index 2248898..7284cd5 100644 --- a/docs/method/check-procedure.md +++ b/docs/method/check-procedure.md @@ -53,6 +53,23 @@ make register check that is not written down did not happen** — the same rule this register applies to every repo it grades. +## One check per sitting + +**A finding you recorded as `moved` is not clean-checked in the same sitting.** + +The ladder says `instant` means "now, and again immediately until a check comes +back clean". The temptation is to record the movement, re-read what you just +wrote, find it consistent, and climb — which produces a `1h` rung seconds after +a change, on the evidence of your own keystrokes. + +That is self-certification, and the rung is supposed to carry information about +how long the world has held still, not about how quickly the register can agree +with itself. A finding that moved stays at `instant` until a *later* pass finds +nothing new. It costs one extra check and it keeps the signal honest. + +Applied on 2026-08-20: `RISK-F-0002`, `RISK-F-0007` and `RISK-F-0008` all moved +and were left due rather than climbed. + ## What must not happen **Stamping `clean` without doing the four questions.** It costs nothing, takes diff --git a/docs/regulatory/audit-retention-basis.md b/docs/regulatory/audit-retention-basis.md index d02e302..4183e18 100644 --- a/docs/regulatory/audit-retention-basis.md +++ b/docs/regulatory/audit-retention-basis.md @@ -8,10 +8,10 @@ determined: "2026-08-20" finding: RISK-F-0008 sources_read: "GDPR Arts 5, 6, 17, 21, 32; Recitals 49, 65; HGB §257; AO §147" external_review: none -last_checked: "2026-08-20T05:25:00Z" -next_check: "2026-08-20T05:25:00Z" -cadence: instant -clean_streak: 0 +last_checked: "2026-08-20T10:02:42Z" +next_check: "2026-08-20T11:02:42Z" +cadence: 1h +clean_streak: 1 --- # RISK-REG-0001 — the retention basis, written down @@ -113,3 +113,7 @@ argument avoided by holding less data is better than a strong one relied upon. happened. Reviewed every 90 days with `RISK-F-0008`, or immediately on any trigger. + +## Reviews + +- **2026-08-20** — clean check: grounds unchanged; still waiting on audit-core's co-residency horizon. Cadence instant → 1h (1 clean in a row); next check 2026-08-20 11:02Z. diff --git a/findings/RISK-F-0002-ops-warden-sign-ungated.md b/findings/RISK-F-0002-ops-warden-sign-ungated.md index 5fe3034..5da0f12 100644 --- a/findings/RISK-F-0002-ops-warden-sign-ungated.md +++ b/findings/RISK-F-0002-ops-warden-sign-ungated.md @@ -29,8 +29,8 @@ embargo_review: "2026-11-17" escalation: withdrawn escalation_trigger: 6 escalation_status: withdrawn-hazard-window-closed -last_checked: "2026-08-19T21:30:00Z" -next_check: "2026-08-19T21:30:00Z" # due now: the ladder starts at instant +last_checked: "2026-08-20T10:02:41Z" +next_check: "2026-08-20T10:02:41Z" cadence: instant clean_streak: 0 graded_by: risk-nexus @@ -234,3 +234,36 @@ the thing that had gone stale was this register's own grading, four hours old. - **2026-08-19** — constraint lifted, escalation withdrawn, severity unchanged. Open at review: has `ops-warden` presented SA tokens and enabled the gate; is `FLEX-WP-0007` still the stated blocker or has it too gone stale. + +## Check — 2026-08-20: a new availability fact, and it is the one that matters now + +`RISK-V-0001` verified `flex-auth`'s NetworkPolicies against the live cluster +and found a third policy nobody had mentioned: + +``` +flex-auth-ops-warden, created 2026-08-19T12:47:18Z +policyTypes: [Ingress, Egress] +ingress: no rules at all +``` + +`Ingress` in `policyTypes` with zero rules means deny all ingress. On its face, +nothing reaches that pin. + +**This is now the live question on this finding.** The attestation hazard +lifted when `flex-auth` shipped; what remained was whether enabling +`policy.enabled` breaks signing on availability grounds. If the pin +`ops-warden` calls admits no ingress, a `fail_closed: true` gate against it +fails closed — every `warden sign` stops. + +The register is **not** concluding that, and said so to both owners: the policy +may be mid-rollout, it may not be the pin `ops-warden` targets, and another +policy may admit the traffic. Both were told on 2026-08-20, before either flips +a switch, which is the entire reason this finding is carried as a peer rather +than folded into `RISK-F-0001`. + +The severity is unchanged at `medium`. What changed is the evidence, and it +changed in the direction of "do not enable this yet" for a completely different +reason than the one this finding was filed for. That is the second time in two +days that this finding's blocker turned out to be a claim about the world at a +date. +- **2026-08-20** — not clean: RISK-V-0001 found the flex-auth-ops-warden policy admits no ingress; the live question is now availability, not attestation. Cadence instant → instant; checked again immediately. diff --git a/findings/RISK-F-0003-ops-warden-read-boundary-ungraded-lanes.md b/findings/RISK-F-0003-ops-warden-read-boundary-ungraded-lanes.md index 08bc9c9..c558d5b 100644 --- a/findings/RISK-F-0003-ops-warden-read-boundary-ungraded-lanes.md +++ b/findings/RISK-F-0003-ops-warden-read-boundary-ungraded-lanes.md @@ -24,10 +24,10 @@ embargo_condition: "RISK-F-0009 resolved — the OpenBao deny set covers every h embargo_since: "2026-08-19" embargo_review: "2026-09-18" escalation: none -last_checked: "2026-08-20T05:40:00Z" -next_check: "2026-08-20T05:40:00Z" # due now: the ladder starts at instant -cadence: instant -clean_streak: 0 +last_checked: "2026-08-20T10:02:42Z" +next_check: "2026-08-20T11:02:42Z" +cadence: 1h +clean_streak: 1 graded_by: risk-nexus ruling: RISK-RULING-2026-08-19 --- @@ -225,3 +225,4 @@ finding's own fix has landed. **Verification limit, recorded rather than assumed:** the mitigation is `ops-warden`'s report and this register has not probed it. Their operator token is expired, which is also why `RISK-F-0009` rests on a file comparison. +- **2026-08-20** — clean check: checked against the inbox and the owner's record; nothing moved. Cadence instant → 1h (1 clean in a row); next check 2026-08-20 11:02Z. diff --git a/findings/RISK-F-0004-tenant-engine-unfiltered-event-read.md b/findings/RISK-F-0004-tenant-engine-unfiltered-event-read.md index 65feb2d..e0840ec 100644 --- a/findings/RISK-F-0004-tenant-engine-unfiltered-event-read.md +++ b/findings/RISK-F-0004-tenant-engine-unfiltered-event-read.md @@ -25,10 +25,10 @@ embargo_condition: "the read path filters by tenant in code" embargo_since: "2026-08-19" embargo_review: "2026-09-18" escalation: none -last_checked: "2026-08-19T21:20:00Z" -next_check: "2026-08-19T21:20:00Z" # due now: the ladder starts at instant -cadence: instant -clean_streak: 0 +last_checked: "2026-08-20T10:02:42Z" +next_check: "2026-08-20T11:02:42Z" +cadence: 1h +clean_streak: 1 graded_by: risk-nexus ruling: RISK-RULING-2026-08-19-B --- @@ -88,3 +88,4 @@ tenant data, and that is what `production_rescore` is for. - **2026-08-19** — filed and graded from `RISK-F-0001`'s unfiled list. Open at review: does `tenant-engine` confirm; is a fix tracked; what does the log actually contain. +- **2026-08-20** — clean check: checked against the inbox and the owner's record; nothing moved. Cadence instant → 1h (1 clean in a row); next check 2026-08-20 11:02Z. diff --git a/findings/RISK-F-0005-audit-core-unfiltered-read-path.md b/findings/RISK-F-0005-audit-core-unfiltered-read-path.md index 880395e..74f906d 100644 --- a/findings/RISK-F-0005-audit-core-unfiltered-read-path.md +++ b/findings/RISK-F-0005-audit-core-unfiltered-read-path.md @@ -25,10 +25,10 @@ embargo_condition: "AUDIT-WP-0008-T04 lands a tenant filter in the read path" embargo_since: "2026-08-19" embargo_review: "2026-11-17" escalation: none -last_checked: "2026-08-19T21:20:00Z" -next_check: "2026-08-19T21:20:00Z" # due now: the ladder starts at instant -cadence: instant -clean_streak: 0 +last_checked: "2026-08-20T10:02:42Z" +next_check: "2026-08-20T11:02:42Z" +cadence: 1h +clean_streak: 1 graded_by: risk-nexus ruling: RISK-RULING-2026-08-19-B --- @@ -77,3 +77,4 @@ No escalation. Known, owned, tracked, moving. - **2026-08-19** — filed and graded from `RISK-F-0001`'s unfiled list. Open at review: has `AUDIT-WP-0008-T04` moved; is `may_read: false` still true of every production credential, not only the sender. +- **2026-08-20** — clean check: checked against the inbox and the owner's record; nothing moved. Cadence instant → 1h (1 clean in a row); next check 2026-08-20 11:02Z. diff --git a/findings/RISK-F-0006-apps-pg-no-backup-configured.md b/findings/RISK-F-0006-apps-pg-no-backup-configured.md index 64e3193..e354607 100644 --- a/findings/RISK-F-0006-apps-pg-no-backup-configured.md +++ b/findings/RISK-F-0006-apps-pg-no-backup-configured.md @@ -31,10 +31,10 @@ escalation_answered: "2026-08-19" escalation_answered_by: the-custodian escalation_act: approve decision: "spend for apps-pg backup storage approved; no ceiling stated" -last_checked: "2026-08-19T23:05:00Z" -next_check: "2026-08-19T23:05:00Z" # due now: the ladder starts at instant -cadence: instant -clean_streak: 0 +last_checked: "2026-08-20T10:02:42Z" +next_check: "2026-08-20T11:02:42Z" +cadence: 1h +clean_streak: 1 graded_by: risk-nexus ruling: RISK-RULING-2026-08-19-B --- @@ -115,3 +115,4 @@ claim, not a control. - **2026-08-19** — escalation answered, spend approved. Open at review: is a backup configured; has a restore been demonstrated; what does it cost. +- **2026-08-20** — clean check: checked against the inbox and the owner's record; nothing moved. Cadence instant → 1h (1 clean in a row); next check 2026-08-20 11:02Z. diff --git a/findings/RISK-F-0007-unverified-tenant-boundary.md b/findings/RISK-F-0007-unverified-tenant-boundary.md index 3338ccf..f8d6bdf 100644 --- a/findings/RISK-F-0007-unverified-tenant-boundary.md +++ b/findings/RISK-F-0007-unverified-tenant-boundary.md @@ -34,8 +34,8 @@ accepted_by: the-custodian accepted_on: "2026-08-19" accepted_until: "production transition (hard expiry, not a date)" decision: "pragmatic default before production — carried unverified; verification of a named consumer boundary on request" -last_checked: "2026-08-19T23:05:00Z" -next_check: "2026-08-19T23:05:00Z" # due now: the ladder starts at instant +last_checked: "2026-08-20T10:02:41Z" +next_check: "2026-08-20T10:02:41Z" cadence: instant clean_streak: 0 graded_by: risk-nexus @@ -155,3 +155,23 @@ production rather than at it. - **2026-08-19** — escalation answered, accepted until production with verification on request. Open at review: any request received; any further instances found; whether production is close enough to re-take the default. + +## Check — 2026-08-20: the on-request path has been walked once + +`RISK-V-0002` — verification of `user-engine`'s tenant boundary, requested +through the documented path on 2026-08-20. + +`user-engine` was chosen because they are a consumer with a boundary who is +**not** already carrying a finding about one. Using `tenant-engine` +(`RISK-F-0004`) or `audit-core` (`RISK-F-0005`) would have tested the path +against systems already known to fail it, which would have proved nothing about +the path. + +The acceptance recorded here rests on that path working. Until 2026-08-20 it +had never been used, which made it a plan rather than a route. All three +outcomes are informative and the least comfortable one is the most useful: +if nothing comes back, the estate learns that it is carrying this finding on an +assumption that asking works. + +Grade unchanged. Nothing about the boundary itself has moved. +- **2026-08-20** — not clean: On-request verification walked for the first time: RISK-V-0002 asks user-engine. Cadence instant → instant; checked again immediately. diff --git a/findings/RISK-F-0008-audit-retention-legal-basis-assumed.md b/findings/RISK-F-0008-audit-retention-legal-basis-assumed.md index 66e9be3..0a8ef7a 100644 --- a/findings/RISK-F-0008-audit-retention-legal-basis-assumed.md +++ b/findings/RISK-F-0008-audit-retention-legal-basis-assumed.md @@ -32,8 +32,8 @@ escalation_act: rule decision: "identity in audit records: opaque subject ids preferred, agent identifiers where possible, operator credentials only where necessary, policy decisions tracked to the responsible party; zone-level privacy guarantees may raise the floor" outstanding: "a defensible retention period per category (waits on audit-core's co-residency horizon), and the trigger list for buying an external answer" determination: RISK-REG-0001 -last_checked: "2026-08-20T05:25:00Z" -next_check: "2026-08-20T05:25:00Z" # due now: the ladder starts at instant +last_checked: "2026-08-20T10:02:41Z" +next_check: "2026-08-20T10:02:41Z" cadence: instant clean_streak: 0 graded_by: risk-nexus @@ -308,3 +308,4 @@ The finding stays open. What remains is a retention period per category, which waits on the co-residency horizon, and the trigger list for buying an external determination. The record is reviewed every 90 days with this finding, or immediately on any trigger. +- **2026-08-20** — not clean: The determination now exists: RISK-REG-0001 states the grounds per category and names duration as the weak point. Cadence instant → instant; checked again immediately. diff --git a/findings/RISK-F-0009-openbao-deny-set-covers-a-third-of-high-risk-lanes.md b/findings/RISK-F-0009-openbao-deny-set-covers-a-third-of-high-risk-lanes.md index 2d3cb96..f2c27c4 100644 --- a/findings/RISK-F-0009-openbao-deny-set-covers-a-third-of-high-risk-lanes.md +++ b/findings/RISK-F-0009-openbao-deny-set-covers-a-third-of-high-risk-lanes.md @@ -25,10 +25,10 @@ disclosure: embargoed embargo_condition: "the deny set covers every high-risk lane with a KV path, verified against live OpenBao" embargo_since: "2026-08-20" escalation: none -last_checked: "2026-08-20T05:40:00Z" -next_check: "2026-08-20T05:40:00Z" -cadence: instant -clean_streak: 0 +last_checked: "2026-08-20T10:02:42Z" +next_check: "2026-08-20T11:02:42Z" +cadence: 1h +clean_streak: 1 graded_by: risk-nexus ruling: RISK-RULING-2026-08-20 --- @@ -177,3 +177,4 @@ otherwise. about this has been checked twice yet. Open at the next check: does the deployed policy match the file; do any agent tokens carry both policies; has `railiance-platform` taken the catalog-generated deny set. +- **2026-08-20** — clean check: checked against the inbox and the owner's record; nothing moved. Cadence instant → 1h (1 clean in a row); next check 2026-08-20 11:02Z. diff --git a/tools/record_check.py b/tools/record_check.py index a6c92e7..c4edc54 100644 --- a/tools/record_check.py +++ b/tools/record_check.py @@ -28,7 +28,7 @@ def main(argv: list[str]) -> int: if len(argv) < 2: fail(__doc__) fid, outcome, rest = argv[0], argv[1], argv[2:] - matches = [f for f in lib.findings() if f["id"] == fid] + matches = [f for f in lib.findings() + lib.regulatory() if f.get("id") == fid] if not matches: fail(f"no finding with id {fid}") f = matches[0]