Compare commits
No commits in common. "6cd969dda93b536dfeb7b567adcf0d8e1fd926de" and "9b7e2e9bd2175cdf92a328c8a4408876bfa1b6e3" have entirely different histories.
6cd969dda9
...
9b7e2e9bd2
11 changed files with 12 additions and 481 deletions
|
|
@ -15,7 +15,6 @@ distinction that matters here.
|
|||
| `ADR-0005` | Implement one lane narrowly, route everything else |
|
||||
| `ADR-0006` | Enforcement is zone-scoped, never a global flag |
|
||||
| `ADR-0007` | Build-stage permissiveness stops at credential disclosure; every lane carries an explicit `risk` grade |
|
||||
| `ADR-0008` | A lane's risk grade covers every field its path discloses, not just the field it is named after |
|
||||
|
||||
### Owned versus inherited — check `owner:` before changing anything
|
||||
|
||||
|
|
|
|||
1
SCOPE.md
1
SCOPE.md
|
|
@ -155,7 +155,6 @@ superseding ADR, never an in-place edit.
|
|||
| `ADR-0005` | Implement one lane narrowly, route everything else |
|
||||
| `ADR-0006` | Enforcement is zone-scoped, never a global flag (`policy.enabled` stays off until WP-0032) |
|
||||
| `ADR-0007` | Build-stage permissiveness stops at credential disclosure; every lane carries an explicit `risk` grade |
|
||||
| `ADR-0008` | A lane's risk grade covers every field its path discloses, not just the field it is named after |
|
||||
|
||||
Rules we follow but do not own — NetKingdom canon, the IAM profile, the
|
||||
credential-management standard, the-custodian's ADR-001 workplan convention — are
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
| workplan | WARDEN-WP-0030 | finished | — | workplans/WARDEN-WP-0030-delegation-register.md |
|
||||
| workplan | WARDEN-WP-0031 | finished | — | workplans/WARDEN-WP-0031-policy-caller-identity.md |
|
||||
| workplan | WARDEN-WP-0032 | proposed | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| workplan | WARDEN-WP-0033 | active | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | ADHOC-2026-06-27-T01 | done | — | workplans/ADHOC-2026-06-27.md |
|
||||
| task | ADHOC-2026-06-29-T01 | done | — | workplans/ADHOC-2026-06-29.md |
|
||||
| task | ADHOC-2026-08-11-T01 | done | — | workplans/ADHOC-2026-08-11.md |
|
||||
|
|
@ -122,7 +121,3 @@
|
|||
| task | WARDEN-WP-0032-T04 | wait | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T05 | done | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0032-T06 | progress | — | workplans/WARDEN-WP-0032-security-zones.md |
|
||||
| task | WARDEN-WP-0033-T01 | progress | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T02 | todo | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T03 | todo | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T04 | todo | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
|
|
|
|||
|
|
@ -1,94 +0,0 @@
|
|||
---
|
||||
id: ops-warden-adr-0008
|
||||
type: adr
|
||||
title: "ADR-0008 — A lane's risk grade covers every field its path discloses"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: accepted
|
||||
version: "1.0"
|
||||
revision: "1"
|
||||
owner: ops-warden
|
||||
binds: "ops-warden"
|
||||
created: "2026-08-21"
|
||||
updated: "2026-08-21"
|
||||
last_reviewed: "2026-08-21"
|
||||
review_interval: 6m
|
||||
enforced_by: "registry/routing/catalog.yaml fields + risk; tests/test_routing.py::test_high_risk_lanes_classified"
|
||||
supersedes: ""
|
||||
successor: ""
|
||||
---
|
||||
|
||||
# ADR-0008 — A lane's risk grade covers every field its path discloses
|
||||
|
||||
## Status
|
||||
|
||||
Accepted 2026-08-21, after `secrets-engine` found two under-graded lanes while
|
||||
reviewing ops-warden's own catalog metadata.
|
||||
|
||||
## Context
|
||||
|
||||
`ADR-0007` requires every catalog lane to carry an explicit `risk` grade. It does
|
||||
not say what the grade is *of*, and the omission turned out to matter.
|
||||
|
||||
The catalog describes a lane by a single `fetch_command` naming a single field —
|
||||
`bao kv get -field=ISSUE_CORE_API_KEY <path>`. Grading followed that description.
|
||||
But the unit of disclosure is not the field, it is the **path**: `bao kv get`
|
||||
without `-field` returns every key stored there, and an agent session that
|
||||
discloses one field has disclosed all of them.
|
||||
|
||||
On 2026-08-19, grading all 27 lanes, ops-warden graded
|
||||
`issue-core-ingestion-api-key` and `reuse-surface-hub-write-token` as `standard`
|
||||
— "ordinary internal workload secrets". Both grades read only the headline field.
|
||||
`CCR-2026-0002` records a deliberate decision to keep `GITEA_BACKEND_TOKEN` at the
|
||||
first path; `CCR-2026-0005` declares a dual-consumer webhook HMAC at the second.
|
||||
Neither is recovered by rotating the credential the lane is named after.
|
||||
|
||||
Three details make this worth a record rather than a fix:
|
||||
|
||||
- **The evidence was already ours.** The field sets were in the CCRs the catalog
|
||||
already cites as authoritative. This was not missing data; it was unread data.
|
||||
- **A test held the error still.** `test_high_risk_lanes_classified` asserted
|
||||
`issue-core-ingestion-api-key` was *not* high. A first grading pass had marked
|
||||
it high, the test contradicted it, and the test was believed. A test that
|
||||
encodes a judgement defends that judgement from correction.
|
||||
- **Another repo found it.** `secrets-engine` graded both `high` independently
|
||||
while drafting catalog entries whose schema records `fields`. A schema that
|
||||
names the field set makes the right grade obvious; ours did not have one.
|
||||
|
||||
## Decision
|
||||
|
||||
**A lane's `risk` grade is a property of its path, and must cover the union of
|
||||
everything a read of that path would disclose.**
|
||||
|
||||
1. Where the field set is known, the catalog records it as `fields`, with the
|
||||
authority it came from.
|
||||
2. The grade is argued against the most damaging field, not the named one.
|
||||
3. Where the field set is unknown, that is stated — never assumed to be one
|
||||
field. An unverified field set is a reason to grade conservatively, matching
|
||||
the `inter-hub-bootstrap-ssh` precedent under `ADR-0007`.
|
||||
4. Establishing a field set must not be done by reading the secret. Use the
|
||||
owning CCR, the owner's catalog, or `bao kv metadata`. `bao kv get` on a
|
||||
high-risk path is the 2026-07-16 vector and is forbidden by
|
||||
`ADR-0004` for agent sessions regardless of intent.
|
||||
|
||||
## Consequences
|
||||
|
||||
`ADR-0007` is unchanged and still governs: every lane carries an explicit grade,
|
||||
and absence fails safe. This record says what that grade must account for.
|
||||
|
||||
Grading gets more expensive: it now requires knowing what is at a path, not just
|
||||
what the lane is called. That cost is the point — the cheap version produced two
|
||||
wrong answers in one pass and is the reason this exists.
|
||||
|
||||
A test that asserts a grade is asserting a judgement. When a grade is disputed,
|
||||
re-argue it from evidence before trusting the test that encodes it.
|
||||
|
||||
## Related
|
||||
|
||||
- `ADR-0007` — every lane carries an explicit grade; build-stage permissiveness
|
||||
stops at credential disclosure
|
||||
- `ADR-0004` — high-risk lanes refuse raw value streaming to agent sessions
|
||||
- `ADR-0001` — the catalog is a pointer layer; `fields` records the owner's
|
||||
declared field set with its source, and does not restate their procedure
|
||||
- `WARDEN-WP-0033-T02`; `secrets-engine` `SECRETS-WP-0006`
|
||||
- `history/2026-07-16-credential-disclosure-lessons.md`
|
||||
|
|
@ -69,4 +69,3 @@ and the publication is a defect.
|
|||
| `ADR-0005` | Implement one lane narrowly, route everything else | ops-warden |
|
||||
| `ADR-0006` | Enforcement is zone-scoped, never a global flag | ops-warden |
|
||||
| `ADR-0007` | Build-stage permissiveness stops at credential disclosure | ops-warden |
|
||||
| `ADR-0008` | A lane's risk grade covers every field its path discloses | ops-warden |
|
||||
|
|
|
|||
|
|
@ -1,100 +0,0 @@
|
|||
# GENERATED by scripts/emit_high_risk_paths.py -- do not edit by hand.
|
||||
# Concrete KV data paths for lanes ops-warden grades `risk: high`.
|
||||
#
|
||||
# This is an INPUT, not a policy. ops-warden states which paths it grades
|
||||
# high; railiance-platform owns what agent-high-risk-boundary denies and may
|
||||
# deny more, deny less, or dispute a grade (ADR-0002, ADR-0008).
|
||||
#
|
||||
# Grades cover every field a read of the path discloses, not the field the
|
||||
# lane is named after (ADR-0008). `fields` is recorded where an owning CCR
|
||||
# declares it, and is null where the field set has not been established --
|
||||
# null means unknown, never 'one field'.
|
||||
|
||||
generated_at: "2026-08-21T06:37:27Z"
|
||||
source: ops-warden/registry/routing/catalog.yaml
|
||||
catalog_revision: "c357ce5908e562755f3c41c24074edc9d231e6ce"
|
||||
catalog_revision_date: "2026-08-21T08:36:42+02:00"
|
||||
catalog_dirty: false
|
||||
high_risk_lane_count: 19
|
||||
concrete_path_count: 14
|
||||
|
||||
# Graded high but not a single KV address -- a routing pattern, a broker
|
||||
# grant, or a non-KV lane. Nothing here for a policy to deny.
|
||||
no_concrete_path:
|
||||
- database-dynamic-credentials
|
||||
- inter-hub-bootstrap-ssh
|
||||
- object-storage-sts
|
||||
- openbao-api-key
|
||||
- ops-warden-warden-sign-token
|
||||
|
||||
paths:
|
||||
- id: agent-harness-binky-mail-approle
|
||||
data_path: tenants/data/binky/company-email/imap
|
||||
metadata_path: tenants/metadata/binky/company-email/imap
|
||||
owner_repo: railiance-platform
|
||||
fields: null # field set not established -- unknown, not one
|
||||
- id: agent-harness-forgejo-deploy
|
||||
data_path: platform/data/workloads/agent-harness/forgejo-deploy-key
|
||||
metadata_path: platform/metadata/workloads/agent-harness/forgejo-deploy-key
|
||||
owner_repo: railiance-platform
|
||||
fields: null # field set not established -- unknown, not one
|
||||
- id: audit-core-senders
|
||||
data_path: platform/data/workloads/audit-core/senders
|
||||
metadata_path: platform/metadata/workloads/audit-core/senders
|
||||
owner_repo: ops-mason
|
||||
fields: null # field set not established -- unknown, not one
|
||||
- id: binky-company-email-imap
|
||||
data_path: tenants/data/binky/company-email/imap
|
||||
metadata_path: tenants/metadata/binky/company-email/imap
|
||||
owner_repo: railiance-platform
|
||||
fields: null # field set not established -- unknown, not one
|
||||
- id: binky-qonto-api
|
||||
data_path: tenants/data/binky/qonto-api
|
||||
metadata_path: tenants/metadata/binky/qonto-api
|
||||
owner_repo: railiance-platform
|
||||
fields: null # field set not established -- unknown, not one
|
||||
- id: email-connect-transactional
|
||||
data_path: platform/data/workloads/email-connect/transactional
|
||||
metadata_path: platform/metadata/workloads/email-connect/transactional
|
||||
owner_repo: railiance-platform
|
||||
fields: null # field set not established -- unknown, not one
|
||||
- id: forgejo-admin-api-token
|
||||
data_path: platform/data/workloads/forgejo/forgejo-admin
|
||||
metadata_path: platform/metadata/workloads/forgejo/forgejo-admin
|
||||
owner_repo: railiance-platform
|
||||
fields: null # field set not established -- unknown, not one
|
||||
- id: issue-core-ingestion-api-key
|
||||
data_path: platform/data/workloads/issue-core/issue-core/issue-core-runtime
|
||||
metadata_path: platform/metadata/workloads/issue-core/issue-core/issue-core-runtime
|
||||
owner_repo: railiance-platform
|
||||
fields: [ISSUE_CORE_API_KEY, GITEA_BACKEND_TOKEN]
|
||||
- id: openrouter-llm-connect
|
||||
data_path: platform/data/workloads/activity-core/llm-connect/llm-connect-provider-secrets
|
||||
metadata_path: platform/metadata/workloads/activity-core/llm-connect/llm-connect-provider-secrets
|
||||
owner_repo: railiance-platform
|
||||
fields: null # field set not established -- unknown, not one
|
||||
- id: railiance-backup-offsite-lane
|
||||
data_path: platform/data/workloads/railiance/backup/offsite-lane
|
||||
metadata_path: platform/metadata/workloads/railiance/backup/offsite-lane
|
||||
owner_repo: railiance-platform
|
||||
fields: null # field set not established -- unknown, not one
|
||||
- id: rapp-qonto-keycape-client
|
||||
data_path: platform/data/workloads/rapp-qonto/keycape-client
|
||||
metadata_path: platform/metadata/workloads/rapp-qonto/keycape-client
|
||||
owner_repo: key-cape
|
||||
fields: null # field set not established -- unknown, not one
|
||||
- id: reuse-surface-hub-write-token
|
||||
data_path: platform/data/workloads/reuse/reuse-surface/runtime-secrets
|
||||
metadata_path: platform/metadata/workloads/reuse/reuse-surface/runtime-secrets
|
||||
owner_repo: railiance-platform
|
||||
fields: [REUSE_SURFACE_TOKEN, REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET]
|
||||
- id: scaleway-bootstrap
|
||||
data_path: platform/data/workloads/railiance/scaleway/bootstrap
|
||||
metadata_path: platform/metadata/workloads/railiance/scaleway/bootstrap
|
||||
owner_repo: railiance-platform
|
||||
fields: null # field set not established -- unknown, not one
|
||||
- id: whynot-design-npm-publish
|
||||
data_path: platform/data/workloads/coulomb/whynot-design/npm-publish
|
||||
metadata_path: platform/metadata/workloads/coulomb/whynot-design/npm-publish
|
||||
owner_repo: railiance-platform
|
||||
fields: null # field set not established -- unknown, not one
|
||||
|
|
@ -283,16 +283,9 @@ entries:
|
|||
|
||||
- id: issue-core-ingestion-api-key
|
||||
title: issue-core ingestion API key (OpenBao KV + ESO)
|
||||
# Regraded standard -> high 2026-08-21 (WARDEN-WP-0033-T02). The T05 grade below
|
||||
# was wrong, and wrong systematically: it graded the headline field, not the path.
|
||||
# was: "Ordinary internal workload secret: an ingestion key for a first-party
|
||||
# service. Rotatable, no spend, no tenant data, no admin scope."
|
||||
# CCR-2026-0002 records a deliberate field-set decision to keep GITEA_BACKEND_TOKEN
|
||||
# at this path alongside the ingestion key, and a read discloses every field there.
|
||||
# A Forgejo backend token is not recovered by rotating an ingestion key.
|
||||
# Found by secrets-engine reviewing SECRETS-WP-0006 -- not by us.
|
||||
risk: high
|
||||
fields: [ISSUE_CORE_API_KEY, GITEA_BACKEND_TOKEN] # CCR-2026-0002
|
||||
# Ordinary internal workload secret: an ingestion key for a first-party
|
||||
# service. Rotatable, no spend, no tenant data, no admin scope (WARDEN-WP-0032-T05).
|
||||
risk: standard
|
||||
need_keywords: [issue-core, ingestion, api, key, openbao, issue_core_api_key, eso, external-secrets]
|
||||
owner_repo: railiance-platform
|
||||
subsystem: OpenBao + issue-core + activity-core
|
||||
|
|
@ -330,16 +323,9 @@ entries:
|
|||
|
||||
- id: reuse-surface-hub-write-token
|
||||
title: reuse-surface federation hub write bearer token
|
||||
# Regraded standard -> high 2026-08-21 (WARDEN-WP-0033-T02), same defective T05
|
||||
# pass as issue-core-ingestion-api-key.
|
||||
# was: "Ordinary internal workload secret. Write access to a first-party
|
||||
# federation surface; damaging to forge, but rotatable and internal."
|
||||
# CCR-2026-0005 declares REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET at this path: a
|
||||
# dual-consumer HMAC that must stay aligned with Forgejo org webhook id=1 on
|
||||
# rotation. Disclosure lets an attacker forge webhook deliveries into the
|
||||
# federation hub, which rotating the write token alone does not undo.
|
||||
risk: high
|
||||
fields: [REUSE_SURFACE_TOKEN, REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET] # CCR-2026-0005
|
||||
# Ordinary internal workload secret. Write access to a first-party federation
|
||||
# surface; damaging to forge, but rotatable and internal (WARDEN-WP-0032-T05).
|
||||
risk: standard
|
||||
need_keywords: [reuse-surface, reuse_surface, hub, register, federation, write, token, bearer, REUSE_SURFACE_TOKEN, REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET, reuse.coulomb.social]
|
||||
owner_repo: railiance-platform
|
||||
subsystem: OpenBao + reuse-surface
|
||||
|
|
|
|||
|
|
@ -1,155 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Emit the versioned high-risk data-path artifact (WARDEN-WP-0033-T03).
|
||||
|
||||
`railiance-platform` asked for a generated list of concrete high-risk KV data
|
||||
paths to consume, instead of hand-maintaining the deny set in
|
||||
`agent-high-risk-boundary.hcl`. Hand-maintaining it is what let the two lists
|
||||
drift for four lanes without anyone noticing (`RISK-F-0009`).
|
||||
|
||||
**This artifact is an input, not a policy.** It states which paths ops-warden
|
||||
grades high. It does not say what to deny -- railiance-platform owns that, and
|
||||
`ADR-0002` keeps ops-warden a conduit rather than the author of another repo's
|
||||
control. A consumer is free to deny more, deny less, or disagree with a grade.
|
||||
|
||||
Carries the catalog git revision so a consumer can tell exactly what it was
|
||||
derived from, and regenerate or diff against it. Read-only: it reads the catalog
|
||||
and `git`, never OpenBao and never a secret value.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
CATALOG = REPO / "registry" / "routing" / "catalog.yaml"
|
||||
DEFAULT_OUT = REPO / "registry" / "generated" / "high-risk-data-paths.yaml"
|
||||
|
||||
|
||||
def catalog_revision() -> tuple[str, str]:
|
||||
"""(commit, iso-date) of the last change to the catalog. Never guesses."""
|
||||
try:
|
||||
out = subprocess.run(
|
||||
["git", "log", "-1", "--format=%H %cI", "--", str(CATALOG)],
|
||||
cwd=REPO, capture_output=True, text=True, timeout=15, check=True,
|
||||
).stdout.strip()
|
||||
commit, _, date = out.partition(" ")
|
||||
return commit or "unknown", date or "unknown"
|
||||
except (subprocess.SubprocessError, FileNotFoundError):
|
||||
return "unknown", "unknown"
|
||||
|
||||
|
||||
def dirty() -> bool:
|
||||
"""True if the catalog has uncommitted edits -- the revision would be a lie."""
|
||||
try:
|
||||
out = subprocess.run(
|
||||
["git", "status", "--porcelain", "--", str(CATALOG)],
|
||||
cwd=REPO, capture_output=True, text=True, timeout=15, check=True,
|
||||
).stdout.strip()
|
||||
return bool(out)
|
||||
except (subprocess.SubprocessError, FileNotFoundError):
|
||||
return False
|
||||
|
||||
|
||||
def build() -> tuple[str, int]:
|
||||
import yaml
|
||||
|
||||
entries = yaml.safe_load(CATALOG.read_text())["entries"]
|
||||
commit, date = catalog_revision()
|
||||
|
||||
rows, patternish = [], []
|
||||
for entry in sorted(entries, key=lambda e: e["id"]):
|
||||
if entry.get("risk") != "high":
|
||||
continue
|
||||
template = entry.get("path_template")
|
||||
data_path = _to_data_path(template) if template else None
|
||||
if data_path is None:
|
||||
patternish.append(entry["id"])
|
||||
continue
|
||||
rows.append({
|
||||
"id": entry["id"],
|
||||
"data_path": data_path,
|
||||
"metadata_path": data_path.replace("/data/", "/metadata/", 1),
|
||||
"fields": entry.get("fields"),
|
||||
"owner_repo": entry.get("owner_repo"),
|
||||
})
|
||||
|
||||
lines = [
|
||||
"# GENERATED by scripts/emit_high_risk_paths.py -- do not edit by hand.",
|
||||
"# Concrete KV data paths for lanes ops-warden grades `risk: high`.",
|
||||
"#",
|
||||
"# This is an INPUT, not a policy. ops-warden states which paths it grades",
|
||||
"# high; railiance-platform owns what agent-high-risk-boundary denies and may",
|
||||
"# deny more, deny less, or dispute a grade (ADR-0002, ADR-0008).",
|
||||
"#",
|
||||
"# Grades cover every field a read of the path discloses, not the field the",
|
||||
"# lane is named after (ADR-0008). `fields` is recorded where an owning CCR",
|
||||
"# declares it, and is null where the field set has not been established --",
|
||||
"# null means unknown, never 'one field'.",
|
||||
"",
|
||||
f"generated_at: \"{datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')}\"",
|
||||
"source: ops-warden/registry/routing/catalog.yaml",
|
||||
f"catalog_revision: \"{commit}\"",
|
||||
f"catalog_revision_date: \"{date}\"",
|
||||
f"catalog_dirty: {str(dirty()).lower()}",
|
||||
f"high_risk_lane_count: {len([e for e in entries if e.get('risk') == 'high'])}",
|
||||
f"concrete_path_count: {len(rows)}",
|
||||
"",
|
||||
"# Graded high but not a single KV address -- a routing pattern, a broker",
|
||||
"# grant, or a non-KV lane. Nothing here for a policy to deny.",
|
||||
"no_concrete_path:",
|
||||
]
|
||||
lines += [f" - {i}" for i in sorted(patternish)] or [" []"]
|
||||
lines += ["", "paths:"]
|
||||
for row in rows:
|
||||
lines.append(f" - id: {row['id']}")
|
||||
lines.append(f" data_path: {row['data_path']}")
|
||||
lines.append(f" metadata_path: {row['metadata_path']}")
|
||||
lines.append(f" owner_repo: {row['owner_repo']}")
|
||||
if row["fields"]:
|
||||
lines.append(f" fields: [{', '.join(row['fields'])}]")
|
||||
else:
|
||||
lines.append(" fields: null # field set not established -- unknown, not one")
|
||||
return "\n".join(lines) + "\n", len(rows)
|
||||
|
||||
|
||||
def _to_data_path(template: str) -> str | None:
|
||||
import re
|
||||
if re.search(r"[<>{}*]", template) or " " in template or template.startswith("k8s:"):
|
||||
return None
|
||||
mount, _, rest = template.partition("/")
|
||||
return f"{mount}/data/{rest}" if rest else None
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--out", type=Path, default=DEFAULT_OUT)
|
||||
parser.add_argument("--check", action="store_true",
|
||||
help="exit 1 if the artifact on disk is stale (for CI)")
|
||||
args = parser.parse_args()
|
||||
|
||||
content, count = build()
|
||||
|
||||
if args.check:
|
||||
current = args.out.read_text() if args.out.exists() else ""
|
||||
# generated_at always differs; compare everything else.
|
||||
strip = lambda t: "\n".join(l for l in t.splitlines() if not l.startswith("generated_at:"))
|
||||
if strip(current) != strip(content):
|
||||
print(f"STALE: {args.out} does not match the catalog. Re-run without --check.")
|
||||
return 1
|
||||
print(f"fresh: {args.out} matches the catalog ({count} concrete paths)")
|
||||
return 0
|
||||
|
||||
args.out.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.out.write_text(content)
|
||||
print(f"wrote {args.out} — {count} concrete high-risk data paths")
|
||||
if dirty():
|
||||
print(" ! catalog has uncommitted changes; catalog_revision does not describe it")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
|
@ -98,34 +98,3 @@ class TestAgainstTheRealCatalog:
|
|||
continue
|
||||
resolved = mod.to_data_path(template)
|
||||
assert resolved is None or resolved.count("/data/") == 1, entry["id"]
|
||||
|
||||
|
||||
class TestGeneratedArtifact:
|
||||
"""The artifact railiance-platform consumes (WARDEN-WP-0033-T03).
|
||||
|
||||
A consumer applies this to a live deny set, so staleness is the failure that
|
||||
matters -- a path graded high after the last emit would silently not reach them.
|
||||
"""
|
||||
|
||||
def test_artifact_is_current(self):
|
||||
import subprocess
|
||||
|
||||
result = subprocess.run(
|
||||
["python3", str(REPO / "scripts" / "emit_high_risk_paths.py"), "--check"],
|
||||
capture_output=True, text=True, timeout=60,
|
||||
)
|
||||
assert result.returncode == 0, (
|
||||
f"{result.stdout}{result.stderr}\n"
|
||||
"Re-run scripts/emit_high_risk_paths.py and commit the result."
|
||||
)
|
||||
|
||||
def test_every_concrete_high_risk_lane_is_in_the_artifact(self):
|
||||
import yaml
|
||||
|
||||
catalog = yaml.safe_load((REPO / "registry" / "routing" / "catalog.yaml").read_text())
|
||||
artifact = yaml.safe_load(
|
||||
(REPO / "registry" / "generated" / "high-risk-data-paths.yaml").read_text()
|
||||
)
|
||||
emitted = {row["id"] for row in artifact["paths"]} | set(artifact["no_concrete_path"] or [])
|
||||
graded_high = {e["id"] for e in catalog["entries"] if e.get("risk") == "high"}
|
||||
assert graded_high == emitted, "a high-risk lane is missing from the generated artifact"
|
||||
|
|
|
|||
|
|
@ -543,13 +543,8 @@ def test_high_risk_lanes_classified():
|
|||
assert "railiance-backup-offsite-lane" in high
|
||||
assert "forgejo-admin-api-token" in high
|
||||
assert "openrouter-llm-connect" in high
|
||||
# WARDEN-WP-0033-T02: these two were asserted standard here, and the assertion
|
||||
# held a defective grade still. Both paths carry a second credential the grade
|
||||
# ignored -- GITEA_BACKEND_TOKEN (CCR-2026-0002) and the dual-consumer webhook
|
||||
# HMAC (CCR-2026-0005). A read discloses every field at a path, so the grade
|
||||
# must cover the union, not the headline field.
|
||||
assert "issue-core-ingestion-api-key" in high
|
||||
assert "reuse-surface-hub-write-token" in high
|
||||
# Ordinary workload secrets stay standard unless reclassified.
|
||||
assert catalog.get("issue-core-ingestion-api-key").is_high_risk is False
|
||||
|
||||
|
||||
def test_invalid_risk_rejected(tmp_path):
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ work completed directly; this is none of those.
|
|||
|
||||
```task
|
||||
id: WARDEN-WP-0033-T01
|
||||
status: done
|
||||
status: progress
|
||||
priority: high
|
||||
```
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ applied to ops-warden by someone else, correctly.
|
|||
|
||||
```task
|
||||
id: WARDEN-WP-0033-T02
|
||||
status: done
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
|
|
@ -89,33 +89,9 @@ disclose, and it should.
|
|||
Fix the grade, then fix the model that produced it: record `fields` per lane and
|
||||
grade on the union. Check the other 25 lanes for the same shape.
|
||||
|
||||
**Done 2026-08-21 — and it was two lanes, not one.** While verifying
|
||||
`reuse-surface-hub-write-token` I told secrets-engine their second field was
|
||||
unevidenced and asked them to confirm it. It was evidenced: `CCR-2026-0005`'s
|
||||
`kv_path` block lists both fields and its notes describe the HMAC's alignment
|
||||
with Forgejo org webhook id=1. A truncated grep, and a retraction sent within
|
||||
twenty minutes so they would not spend time on it. That lane was under-graded on
|
||||
exactly the same reasoning, and both had been regraded *down* in the same T05
|
||||
pass — which is what makes this a systematic flaw rather than one bad call.
|
||||
|
||||
Blast radius checked and bounded: of the 8 remaining `standard` lanes, 6 have no
|
||||
KV path at all (SSH, policy check, tunnel, principals, issue-sink, key-cape
|
||||
login) so nothing is disclosed by a read. Two do have paths and no CCR field
|
||||
evidence — `rein-openweights-openrouter-approle` and `coulomb-social-runtime-env`
|
||||
(a whole k8s env Secret, which by shape almost certainly holds several fields).
|
||||
Deliberately **not** regraded: `ADR-0008` §3 says an unknown field set is stated
|
||||
rather than assumed, and grading is operator-sanctioned judgement, not backfill.
|
||||
They are the open item on this task.
|
||||
|
||||
Shipped: both regrades with their evidence and the superseded reasoning kept
|
||||
inline, `fields` recorded with its CCR source, the test that had been holding the
|
||||
wrong answer inverted with an explanation of why it was wrong to trust it, and
|
||||
**`ADR-0008`** — a lane's grade covers every field its path discloses. That is a
|
||||
new binding rule, so it is a record rather than a wiki note.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0033-T03
|
||||
status: done
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
|
|
@ -133,30 +109,9 @@ consumer can tell what it was derived from. Depends on T02 — publishing the de
|
|||
set before fixing the grades would ship the wrong list to a consumer who will
|
||||
apply it.
|
||||
|
||||
**Done 2026-08-21.** `scripts/emit_high_risk_paths.py` →
|
||||
`registry/generated/high-risk-data-paths.yaml`: 19 high-risk lanes, 14 concrete
|
||||
data paths, 5 with no single KV address listed separately so a consumer does not
|
||||
read the absence as an omission. Carries `catalog_revision`, its date, and a
|
||||
`catalog_dirty` flag — a revision that does not describe the file it came from is
|
||||
worse than none.
|
||||
|
||||
The T02 dependency was not theoretical. The two regrades land in this artifact,
|
||||
and `check_agent_read_boundary.py` now reports **2 uncovered** against a policy
|
||||
railiance-platform closed to 0 yesterday. Emitting before regrading would have
|
||||
handed them a list that confirmed a coverage claim that had just stopped being
|
||||
true.
|
||||
|
||||
`fields` is emitted as `null` where no CCR declares the set, never as a
|
||||
single-element guess — `ADR-0008` §3. Two CI tests: the artifact must be current,
|
||||
and every high-risk lane must appear in it, so a lane graded high after the last
|
||||
emit cannot silently fail to reach the consumer.
|
||||
|
||||
Boundary held: the header states this is an input and not a policy, and that
|
||||
railiance-platform may deny more, deny less, or dispute a grade (`ADR-0002`).
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0033-T04
|
||||
status: wait
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
|
|
@ -177,23 +132,6 @@ Note the interaction with `ADR-0004`: the agent read-boundary already depends on
|
|||
side. A real issuance identity is what would make that boundary hold on the
|
||||
OpenBao side too, so ops-warden is an interested consumer, not a bystander.
|
||||
|
||||
**Routed 2026-08-21 to `key-cape` (msg 903b2223); waiting on accept or refuse.**
|
||||
Reasoning given: it is an identity and issuance question about a principal
|
||||
authenticating to OpenBao, which is key-cape/Keycloak's. The precedent is an hour
|
||||
old and runs the same direction — `secrets-engine` declined `key-cape-oidc-login`
|
||||
as ops-warden's to hand them, on the grounds that login and identity-token
|
||||
issuance stay with key-cape. Absorbing this would contradict agreeing with them.
|
||||
|
||||
Named the adjacent parties explicitly rather than leaving them to inference:
|
||||
`zone-engine` has an interest (a coding-agent identity is a strong candidate zone
|
||||
subject) and `user-engine` is **not** involved — this is a machine principal, not
|
||||
an end-user account. Stated so nobody concludes it by elimination.
|
||||
|
||||
Asked for a refusal-with-pointer as an equally good answer. The failure mode to
|
||||
avoid is the 2026-08-17 one recorded in `.claude/rules/finding-routing.md`:
|
||||
ops-warden answered a question well and never routed it, and another repo ended
|
||||
up filing it.
|
||||
|
||||
## Related
|
||||
|
||||
- `secrets-engine` `SECRETS-WP-0006` — catalog admission, decision `ae676382`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue