Work the register due list, and add the one-check-per-sitting rule
Nine records checked. Five clean and climbed to 1h: RISK-F-0003, 0004, 0005, 0006, 0009 and RISK-REG-0001. Three moved and stay at instant — RISK-F-0002 (RISK-V-0001 found the flex-auth-ops-warden policy admits no ingress, so the live question there is now availability rather than attestation), RISK-F-0007 (the on-request path walked for the first time as RISK-V-0002), RISK-F-0008 (the determination now exists). The rule: a finding recorded as moved is not clean-checked in the same sitting. Re-reading your own keystrokes and climbing produces a rung that says the world held still when what held still was the last five minutes. The rung carries stability information or it carries nothing. record_check.py now handles regulatory records as well as findings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
2ebdc133bc
commit
56b8d61583
12 changed files with 116 additions and 36 deletions
10
REGISTER.md
10
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** |
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue