Ship WARDEN-WP-0030: delegation register for every catalog lane
Every execution position is now explicit. Catalog entries carry delegation.mode (permanent / native / interim) with intended owner and blocker. warden route gaps lists the interim set. Promotion requires the ownership question. Doctrine lives in AccessRouting.md; the register was published to the named owner repos.
This commit is contained in:
parent
8d3706fa06
commit
c93e3c9b43
11 changed files with 619 additions and 29 deletions
18
SCOPE.md
18
SCOPE.md
|
|
@ -123,15 +123,15 @@ Gap analysis: `history/2026-07-01-intent-scope-gap-analysis.md` (current);
|
|||
| NetKingdom evolution reflected in docs | Met |
|
||||
| Non-SSH secrets stay out of ops-warden | Met |
|
||||
| Workload posture / maturity model for secret-flow blockers | Met — two-axis standard + descriptors + conformance checker + dev doubles (WP-0015) |
|
||||
| Every execution position explicitly permanent or interim with a named owner | **Not met** — 2 of 24 lanes carry `exec_owner`; 11 proxy lanes record no intended owner (WP-0030) |
|
||||
| Every execution position explicitly permanent or interim with a named owner | **Met** — every catalog entry carries `delegation:`; `warden route gaps` lists the interim set (WP-0030) |
|
||||
|
||||
**Maturity vector:** `D5 / A5 / C4 / R4` (Discovery / Availability / Completeness / Reliability)
|
||||
**Maturity vector:** `D5 / A5 / C5 / R4` (Discovery / Availability / Completeness / Reliability)
|
||||
|
||||
| Dimension | Level | Meaning today |
|
||||
| --- | --- | --- |
|
||||
| D5 | Discovery | Routing wiki + security map + pointer catalog + NK canon cross-links |
|
||||
| A5 | Availability | CLI + `warden route` + `warden access` advisory & proxy front door + `warden policy` + opt-in policy gate + agent `--json` |
|
||||
| C4 | Completeness | All ops-warden lanes shipped — SSH (prod), routing, access assist, posture conformance, cert_command pilot gate, disclosure hygiene, tenant custody, policy front door. **Down from C5:** delegation is unrecorded on 11 of 24 lanes, so ops-warden's interim positions are not distinguishable from designed ones (WP-0030) |
|
||||
| C5 | Completeness | All ops-warden lanes shipped — SSH (prod), routing, access assist, posture conformance, cert_command pilot gate, disclosure hygiene, tenant custody, policy front door, delegation register (WP-0030) |
|
||||
| R4 | Reliability | Live OpenBao sign + credential-broker policy-gate smoke evidence on Railiance (2026-07-01) |
|
||||
|
||||
---
|
||||
|
|
@ -350,16 +350,16 @@ Remaining production distance is also in other repos' lanes (see Known gaps).
|
|||
- **Policy front door:** WP-0029 shipped — `warden plan "<need>"` (autonomous /
|
||||
founder_required / unroutable), `warden desk` founder interaction surface, declared
|
||||
`organization_posture: build` as a third posture axis, catalog freshness reporting
|
||||
- **Delegation:** 24 catalog lanes — 1 executed by ops-warden (SSH), 2 delegated via
|
||||
`exec_owner`, 11 proxied with **no intended owner recorded**, 10 route-only. Addressed
|
||||
by WP-0030 (proposed)
|
||||
- **Active work:** WP-0027 (`backlog`), WP-0030 (`proposed`); remaining production
|
||||
distance is other repos' lanes
|
||||
- **Delegation:** 27 catalog lanes carry `delegation:` (WP-0030). SSH is
|
||||
`permanent`; owner-fronted lanes are `native`; interim proxies name
|
||||
`intended_owner` + `blocked_on`. Query: `warden route gaps`.
|
||||
- **Active work:** WP-0027 (`backlog`); remaining production distance is other
|
||||
repos' lanes (and retiring interim covers as those owners ship front doors)
|
||||
- **Integration docs:** cert_command migration, token hygiene (broker-first), principals
|
||||
drift (`wiki/playbooks/`)
|
||||
- **Latest assessment:** `history/2026-08-11-delegation-surface-assessment.md`
|
||||
- **Latest workplans:** WP-0029 (policy front door) shipped July 2026; WP-0030
|
||||
(delegation register) proposed 2026-08-11
|
||||
(delegation register) shipped August 2026
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@
|
|||
# status active (surfaced by default) | draft (hidden unless --all)
|
||||
# steps ONLY when warden_executes: true
|
||||
# cert_command ONLY when warden_executes: true
|
||||
# delegation WP-0030 register. mode: native | interim | permanent.
|
||||
# intended_owner required unless permanent; blocked_on required
|
||||
# when interim. Absence is implicit interim with unknown owner.
|
||||
|
||||
version: 1
|
||||
|
||||
|
|
@ -41,6 +44,9 @@ entries:
|
|||
canon_ref: net-kingdom/docs/platform-identity-security-architecture.md#operational-ssh-path
|
||||
reviewed: "2026-06-18"
|
||||
status: active
|
||||
delegation:
|
||||
mode: permanent
|
||||
reviewed: "2026-08-15"
|
||||
cert_command: "warden sign <actor> --pubkey <path>"
|
||||
steps:
|
||||
- "Confirm the actor is in inventory (`warden inventory list`); add with `warden inventory add` if not — see wiki/ActorInventoryPatterns.md."
|
||||
|
|
@ -58,6 +64,10 @@ entries:
|
|||
canon_ref: net-kingdom/docs/platform-identity-security-architecture.md
|
||||
reviewed: "2026-07-01"
|
||||
status: active
|
||||
delegation:
|
||||
mode: native
|
||||
intended_owner: railiance-platform
|
||||
reviewed: "2026-08-15"
|
||||
# Concrete broker lane — RAILIANCE-WP-0005 pilot (live 2026-07-01):
|
||||
# credential exec injects VAULT_TOKEN only into the child process; ops-warden
|
||||
# issues SSH certs and never mints or holds OpenBao tokens.
|
||||
|
|
@ -87,6 +97,11 @@ entries:
|
|||
canon_ref: net-kingdom/docs/platform-identity-security-architecture.md
|
||||
reviewed: "2026-06-27"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: secrets-engine
|
||||
blocked_on: "secrets-engine has not confirmed whether exec --catalog generalizes over arbitrary OpenBao lanes (asked 2026-08-11, msg 7d55d332)"
|
||||
reviewed: "2026-08-11"
|
||||
# Structured handoff (WP-0014) — reference example. Templates only, no values.
|
||||
# ops-warden does not own this secret; it advises and (exec_capable) proxies the
|
||||
# fetch *as the caller* via `warden access`, never holding or persisting the value.
|
||||
|
|
@ -115,6 +130,10 @@ entries:
|
|||
canon_ref: net-kingdom/docs/platform-identity-security-architecture.md
|
||||
reviewed: "2026-06-29"
|
||||
status: active
|
||||
delegation:
|
||||
mode: native
|
||||
intended_owner: secrets-engine
|
||||
reviewed: "2026-08-15"
|
||||
# Concrete, owner-confirmed lane — railiance-platform CCR-2026-0001 (commit 8f617fc):
|
||||
# status=active, access_frontdoor.readiness=ready, resolvable=true; positive fetch
|
||||
# passed and negative (non-whynot) login denied. Zero-placeholder fetch: an automated
|
||||
|
|
@ -152,6 +171,10 @@ entries:
|
|||
canon_ref: net-kingdom/docs/responsibility-map.md
|
||||
reviewed: "2026-06-18"
|
||||
status: active
|
||||
delegation:
|
||||
mode: native
|
||||
intended_owner: flex-auth
|
||||
reviewed: "2026-08-15"
|
||||
|
||||
- id: key-cape-oidc-login
|
||||
title: Interactive login, OIDC token, or MFA
|
||||
|
|
@ -163,6 +186,11 @@ entries:
|
|||
canon_ref: net-kingdom/docs/canon/standards/iam-profile_v0.2.md
|
||||
reviewed: "2026-06-27"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: secrets-engine
|
||||
blocked_on: "secrets-engine has not confirmed whether exec --catalog generalizes over arbitrary OpenBao lanes (asked 2026-08-11, msg 7d55d332)"
|
||||
reviewed: "2026-08-11"
|
||||
# Login lane (WP-0014 T4) — interactive auth bootstrap, not a secret read. No
|
||||
# secret-read gate (you have no identity yet) and no caller-auth precheck (the
|
||||
# point is to obtain one). warden runs it interactively as the caller and never
|
||||
|
|
@ -182,6 +210,10 @@ entries:
|
|||
canon_ref: net-kingdom/docs/platform-identity-security-architecture.md#operational-ssh-path
|
||||
reviewed: "2026-06-24"
|
||||
status: active
|
||||
delegation:
|
||||
mode: native
|
||||
intended_owner: ops-bridge
|
||||
reviewed: "2026-08-15"
|
||||
|
||||
- id: railiance-infra-principals
|
||||
title: Host SSH principal file or force-command deployment
|
||||
|
|
@ -193,6 +225,10 @@ entries:
|
|||
canon_ref: net-kingdom/docs/responsibility-map.md
|
||||
reviewed: "2026-06-18"
|
||||
status: active
|
||||
delegation:
|
||||
mode: native
|
||||
intended_owner: railiance-infra
|
||||
reviewed: "2026-08-15"
|
||||
|
||||
- id: inter-hub-bootstrap-ssh
|
||||
title: Inter-Hub bootstrap SSH envelope
|
||||
|
|
@ -204,6 +240,10 @@ entries:
|
|||
canon_ref: net-kingdom/docs/platform-identity-security-architecture.md#operational-ssh-path
|
||||
reviewed: "2026-06-24"
|
||||
status: active
|
||||
delegation:
|
||||
mode: native
|
||||
intended_owner: railiance-infra
|
||||
reviewed: "2026-08-15"
|
||||
|
||||
- id: activity-core-issue-sink
|
||||
title: activity-core IssueSink → issue-core REST emission
|
||||
|
|
@ -215,6 +255,10 @@ entries:
|
|||
canon_ref: net-kingdom/docs/platform-identity-security-architecture.md
|
||||
reviewed: "2026-06-18"
|
||||
status: active
|
||||
delegation:
|
||||
mode: native
|
||||
intended_owner: activity-core
|
||||
reviewed: "2026-08-15"
|
||||
|
||||
- id: issue-core-ingestion-api-key
|
||||
title: issue-core ingestion API key (OpenBao KV + ESO)
|
||||
|
|
@ -226,6 +270,11 @@ entries:
|
|||
canon_ref: net-kingdom/docs/platform-identity-security-architecture.md
|
||||
reviewed: "2026-07-02"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: secrets-engine
|
||||
blocked_on: "secrets-engine has not confirmed whether exec --catalog generalizes over arbitrary OpenBao lanes (asked 2026-08-11, msg 7d55d332)"
|
||||
reviewed: "2026-08-11"
|
||||
# Concrete, owner-confirmed lane — railiance-platform CCR-2026-0002 / RAILIANCE-WP-0009
|
||||
# (promoted 2026-07-02): policy workload-kv-read-issue-core-runtime and k8s auth role
|
||||
# external-secrets-issue-core applied; ExternalSecret issue-core/issue-core-runtime
|
||||
|
|
@ -258,6 +307,11 @@ entries:
|
|||
canon_ref: reuse-surface/specs/FederationHubAPI.md
|
||||
reviewed: "2026-07-07"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: secrets-engine
|
||||
blocked_on: "secrets-engine has not confirmed whether exec --catalog generalizes over arbitrary OpenBao lanes (asked 2026-08-11, msg 7d55d332)"
|
||||
reviewed: "2026-08-11"
|
||||
# Concrete, owner-confirmed lane — railiance-platform CCR-2026-0005 / RAILIANCE-WP-0011
|
||||
# (promoted 2026-07-07): policy workload-kv-read-reuse-surface-runtime; ExternalSecret
|
||||
# reuse/reuse-surface-runtime SecretSynced to reuse-surface-env on Railiance01;
|
||||
|
|
@ -290,6 +344,11 @@ entries:
|
|||
canon_ref: net-kingdom/docs/platform-identity-security-architecture.md
|
||||
reviewed: "2026-07-02"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: secrets-engine
|
||||
blocked_on: "secrets-engine has not confirmed whether exec --catalog generalizes over arbitrary OpenBao lanes (asked 2026-08-11, msg 7d55d332)"
|
||||
reviewed: "2026-08-11"
|
||||
# High-risk: provider API key with spend impact + prompt-adjacent (WP-0026 T04).
|
||||
risk: high
|
||||
# Concrete, owner-confirmed lane — railiance-platform CCR-2026-0003 / RAILIANCE-WP-0010
|
||||
|
|
@ -325,6 +384,11 @@ entries:
|
|||
canon_ref: railiance-platform/docs/workload-kv-access-lanes.md
|
||||
reviewed: "2026-07-16"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: railiance-platform
|
||||
blocked_on: "Rotation is re-establish, a multi-step procedure ops-warden only describes"
|
||||
reviewed: "2026-08-11"
|
||||
# High-risk: WebDAV upload token + AGE recovery escrow (WP-0026 T04).
|
||||
risk: high
|
||||
# CCR-2026-0004: policy + OIDC role applied; values provisioned 2026-07-07.
|
||||
|
|
@ -365,6 +429,11 @@ entries:
|
|||
canon_ref: railiance-platform/docs/workload-kv-access-lanes.md
|
||||
reviewed: "2026-07-13"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: secrets-engine
|
||||
blocked_on: "secrets-engine has not confirmed whether exec --catalog generalizes over arbitrary OpenBao lanes (asked 2026-08-11, msg 7d55d332)"
|
||||
reviewed: "2026-08-11"
|
||||
# High-risk: site-admin PAT (WP-0026 T04).
|
||||
risk: high
|
||||
# CCR-2026-0006: approved by platform-operator 2026-07-12; policy
|
||||
|
|
@ -402,6 +471,11 @@ entries:
|
|||
canon_ref: railiance-platform/docs/workload-kv-access-lanes.md
|
||||
reviewed: "2026-07-17"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: tenant-engine
|
||||
blocked_on: "Custody at tenants/binky/... but rotation owner is binky-control — split lifecycle, no front door reconciling it"
|
||||
reviewed: "2026-08-11"
|
||||
risk: high
|
||||
# CCR-2026-0007: tenants/ mount + policy + OIDC role applied; founder provisioned
|
||||
# values via UI (version ≥2, not placeholder). Capabilities-safe verify 2026-07-17:
|
||||
|
|
@ -431,6 +505,11 @@ entries:
|
|||
canon_ref: binky-control/integrations/qonto-mcp.md
|
||||
reviewed: "2026-07-21"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: tenant-engine
|
||||
blocked_on: "Same split lifecycle as binky-company-email-imap; no tenant-engine front door"
|
||||
reviewed: "2026-08-11"
|
||||
risk: high
|
||||
# CCR-2026-0008: policy + OIDC role applied; secret at tenants/binky/qonto-api
|
||||
# (fields API_KEY, API_USER). Map to QONTO_API_KEY / QONTO_ORGANIZATION_ID for
|
||||
|
|
@ -461,6 +540,11 @@ entries:
|
|||
canon_ref: key-cape/docs/qonto-runtime-identity-contract.md
|
||||
reviewed: "2026-07-27"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: key-cape
|
||||
blocked_on: "client_secret_basic exchange is a key-cape protocol procedure, not a KV read; rotation already automatable"
|
||||
reviewed: "2026-08-11"
|
||||
risk: high
|
||||
auth_method: "OpenBao platform workload lane; KeyCape client_secret_basic exchange"
|
||||
path_template: "platform/workloads/rapp-qonto/keycape-client"
|
||||
|
|
@ -486,6 +570,11 @@ entries:
|
|||
canon_ref: binky-control/integrations/executor-worker-secrets.md
|
||||
reviewed: "2026-07-17"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: railiance-platform
|
||||
blocked_on: "re-establish plus an alternative host-local key path; two ways in, neither owner-fronted (also agent-harness)"
|
||||
reviewed: "2026-08-11"
|
||||
risk: high
|
||||
# Provisioned 2026-07-17 on railiance01: ed25519 keypair on host, OpenBao copy at
|
||||
# platform/workloads/agent-harness/forgejo-deploy-key, write deploy key on
|
||||
|
|
@ -516,6 +605,11 @@ entries:
|
|||
canon_ref: binky-control/integrations/executor-worker-secrets.md
|
||||
reviewed: "2026-07-17"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: railiance-platform
|
||||
blocked_on: "AppRole is a host-standing credential; no owner front door for minting or rotating role_id+secret_id"
|
||||
reviewed: "2026-08-15"
|
||||
risk: high
|
||||
# Provisioned 2026-07-17: role agent-harness-binky-mail bound to existing policy
|
||||
# workload-kv-read-binky-company-email-imap; role_id/secret_id delivered to
|
||||
|
|
@ -548,6 +642,10 @@ entries:
|
|||
canon_ref: net-kingdom/docs/object-storage-sts-credential-vending.md
|
||||
reviewed: "2026-06-24"
|
||||
status: draft
|
||||
delegation:
|
||||
mode: native
|
||||
intended_owner: net-kingdom
|
||||
reviewed: "2026-08-15"
|
||||
|
||||
- id: database-dynamic-credentials
|
||||
title: Database dynamic credentials (OpenBao secrets engine)
|
||||
|
|
@ -559,6 +657,10 @@ entries:
|
|||
canon_ref: rapp-postgres/docs/canon-drafts/shared-platform-relational-storage_v0.1-draft.md
|
||||
reviewed: "2026-08-10"
|
||||
status: active
|
||||
delegation:
|
||||
mode: native
|
||||
intended_owner: rapp-postgres
|
||||
reviewed: "2026-08-15"
|
||||
risk: high
|
||||
exec_capable: false
|
||||
|
||||
|
|
@ -572,6 +674,11 @@ entries:
|
|||
canon_ref: ops-mason/plans/rein-openweights-openrouter-approle.md
|
||||
reviewed: "2026-07-27"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: ops-mason
|
||||
blocked_on: "AppRole is a host-standing credential; no owner-fronted exec for the OpenRouter key read"
|
||||
reviewed: "2026-08-15"
|
||||
risk: standard
|
||||
# Built 2026-07-27 by ops-mason (MASON-WP-0001-T05), approved by Bernd
|
||||
# Worsch 2026-07-27. Policy + AppRole live; reins/ KV v2 mount created
|
||||
|
|
@ -621,6 +728,11 @@ entries:
|
|||
canon_ref: railiance-platform/docs/apps-pg.md
|
||||
reviewed: "2026-08-09"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: railiance-apps
|
||||
blocked_on: "Runtime Secret applied via railiance-apps make target; OpenBao path planned; confirm whether user-engine should front USER_ENGINE_PROXY_SECRET"
|
||||
reviewed: "2026-08-15"
|
||||
risk: standard
|
||||
# K8s assembly is the live handoff today (same pattern as vergage-teilnahme-env).
|
||||
# OpenBao KV platform/workloads/coulomb/coulomb-social/runtime-env is the
|
||||
|
|
@ -650,6 +762,10 @@ entries:
|
|||
canon_ref: audit-core/docs/operator-runbook.md
|
||||
reviewed: "2026-08-13"
|
||||
status: draft
|
||||
delegation:
|
||||
mode: native
|
||||
intended_owner: ops-mason
|
||||
reviewed: "2026-08-15"
|
||||
auth_method: "in-cluster generated Secret audit-core-senders; later OpenBao KV via Mason wrap-migrate"
|
||||
path_template: "platform/workloads/audit-core/senders"
|
||||
policy_ref: "external-secrets-audit-core"
|
||||
|
|
@ -667,6 +783,11 @@ entries:
|
|||
canon_ref: railiance-platform/docs/workload-kv-access-lanes.md
|
||||
reviewed: "2026-08-12"
|
||||
status: active
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: secrets-engine
|
||||
blocked_on: "secrets-engine has not confirmed whether exec --catalog generalizes over arbitrary OpenBao lanes (asked 2026-08-11, msg 7d55d332)"
|
||||
reviewed: "2026-08-15"
|
||||
risk: high
|
||||
# CCR-2026-0010 approved 2026-08-12; applied same day (EMAIL-WP-0004-T03):
|
||||
# policies external-secrets-email-connect + workload-kv-read-email-connect-transactional,
|
||||
|
|
@ -703,6 +824,11 @@ entries:
|
|||
canon_ref: ops-mason/plans/reef-storage-scaleway-bootstrap.md
|
||||
reviewed: "2026-08-14"
|
||||
status: draft
|
||||
delegation:
|
||||
mode: interim
|
||||
intended_owner: railiance-platform
|
||||
blocked_on: "Founder bootstrap API key; draft until provisioned; no owner-fronted exec"
|
||||
reviewed: "2026-08-15"
|
||||
risk: high
|
||||
# CCR-2026-0011. Values via founder paste-once or local tfvars ingest.
|
||||
# Not the Barman runtime key (platform-pg-backup-s3).
|
||||
|
|
|
|||
|
|
@ -659,6 +659,8 @@ def _entry_summary(entry) -> dict:
|
|||
if entry.has_rotation
|
||||
else {}
|
||||
),
|
||||
# Delegation register (WP-0030) — implicit interim if the block is absent.
|
||||
"delegation": entry.effective_delegation.to_dict(),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -769,6 +771,85 @@ def route_list(
|
|||
)
|
||||
|
||||
|
||||
@route_app.command("gaps")
|
||||
def route_gaps(
|
||||
output_json: Annotated[bool, typer.Option("--json", help="Output JSON")] = False,
|
||||
all_entries: Annotated[bool, typer.Option("--all", help="Include draft entries")] = False,
|
||||
stale_days: Annotated[
|
||||
int,
|
||||
typer.Option(
|
||||
"--stale-days",
|
||||
help="Days since delegation review before an interim lane is stale (default 90)",
|
||||
min=1,
|
||||
),
|
||||
] = 90,
|
||||
) -> None:
|
||||
"""List interim lanes: intended owner, blocker, and age since review."""
|
||||
from warden.routing.catalog import days_since_review
|
||||
|
||||
catalog = _load_catalog()
|
||||
entries = catalog.gaps(include_draft=all_entries)
|
||||
|
||||
if output_json:
|
||||
payload = []
|
||||
for e in entries:
|
||||
d = e.effective_delegation
|
||||
reviewed = d.reviewed or e.reviewed
|
||||
payload.append(
|
||||
{
|
||||
"id": e.id,
|
||||
"title": e.title,
|
||||
"status": e.status,
|
||||
"mode": d.mode,
|
||||
"intended_owner": d.intended_owner,
|
||||
"blocked_on": d.blocked_on,
|
||||
"reviewed": reviewed,
|
||||
"days_since_review": days_since_review(reviewed),
|
||||
"implicit": d.implicit,
|
||||
"stale": days_since_review(reviewed) > stale_days,
|
||||
}
|
||||
)
|
||||
print(json.dumps(payload, indent=2))
|
||||
return
|
||||
|
||||
if not entries:
|
||||
console.print("No interim routing gaps (every execution position is classified).")
|
||||
return
|
||||
|
||||
table = Table(title="Interim delegation register")
|
||||
table.add_column("ID")
|
||||
table.add_column("Owner")
|
||||
table.add_column("Blocked on")
|
||||
table.add_column("Reviewed")
|
||||
table.add_column("Days")
|
||||
table.add_column("Status")
|
||||
for e in entries:
|
||||
d = e.effective_delegation
|
||||
reviewed = d.reviewed or e.reviewed
|
||||
days = days_since_review(reviewed)
|
||||
reviewed_styled = f"[yellow]{reviewed}[/yellow]" if days > stale_days else reviewed
|
||||
days_styled = f"[yellow]{days}[/yellow]" if days > stale_days else str(days)
|
||||
status_styled = e.status if e.status == "active" else f"[yellow]{e.status}[/yellow]"
|
||||
table.add_row(
|
||||
e.id,
|
||||
d.intended_owner or "[yellow]unknown[/yellow]",
|
||||
d.blocked_on or "",
|
||||
reviewed_styled,
|
||||
days_styled,
|
||||
status_styled,
|
||||
)
|
||||
console.print(table)
|
||||
stale_n = sum(
|
||||
1
|
||||
for e in entries
|
||||
if days_since_review(e.effective_delegation.reviewed or e.reviewed) > stale_days
|
||||
)
|
||||
if stale_n:
|
||||
console.print(
|
||||
f"[yellow]{stale_n} interim lane(s) past {stale_days}d review cadence.[/yellow]"
|
||||
)
|
||||
|
||||
|
||||
@route_app.command("show")
|
||||
def route_show(
|
||||
entry_id: Annotated[str, typer.Argument(help="Catalog entry id (see `warden route list`)")],
|
||||
|
|
@ -813,6 +894,17 @@ def route_show(
|
|||
console.print(f" wiki : {entry.wiki_ref}")
|
||||
console.print(f" canon : {entry.canon_ref}")
|
||||
console.print(f" reviewed : {entry.reviewed} status: {entry.status}")
|
||||
d = entry.effective_delegation
|
||||
owner = d.intended_owner or "unknown"
|
||||
if d.mode == "interim":
|
||||
console.print(
|
||||
f" delegation: [yellow]interim[/yellow] → {owner}"
|
||||
+ (f" blocked: {d.blocked_on}" if d.blocked_on else "")
|
||||
)
|
||||
elif d.mode == "native":
|
||||
console.print(f" delegation: native → {owner} already fronts this")
|
||||
else:
|
||||
console.print(" delegation: permanent (ops-warden owns this front door)")
|
||||
|
||||
if entry.warden_executes:
|
||||
console.print("\n[green]ops-warden issues this directly.[/green]")
|
||||
|
|
|
|||
|
|
@ -12,12 +12,13 @@ from warden.routing.catalog import (
|
|||
find_catalog_path,
|
||||
load_catalog,
|
||||
)
|
||||
from warden.routing.models import RouteEntry
|
||||
from warden.routing.models import Delegation, RouteEntry
|
||||
|
||||
__all__ = [
|
||||
"Catalog",
|
||||
"CatalogError",
|
||||
"CatalogFreshness",
|
||||
"Delegation",
|
||||
"RouteEntry",
|
||||
"find_catalog_path",
|
||||
"load_catalog",
|
||||
|
|
|
|||
|
|
@ -23,7 +23,13 @@ from typing import List, Optional
|
|||
|
||||
import yaml
|
||||
|
||||
from warden.routing.models import VALID_RISK, RotationGuide, RouteEntry
|
||||
from warden.routing.models import (
|
||||
VALID_DELEGATION_MODES,
|
||||
VALID_RISK,
|
||||
Delegation,
|
||||
RotationGuide,
|
||||
RouteEntry,
|
||||
)
|
||||
|
||||
# Structured handoff string fields (WP-0014) — templates and pointers only.
|
||||
# Every one is scanned for accidental secret material; see _assert_no_secret_material.
|
||||
|
|
@ -201,6 +207,25 @@ class Catalog:
|
|||
if is_review_stale(e.reviewed, threshold_days=threshold_days, today=today)
|
||||
]
|
||||
|
||||
def gaps(self, include_draft: bool = False) -> List[RouteEntry]:
|
||||
"""Interim lanes — the queryable delegation register (WARDEN-WP-0030)."""
|
||||
return [e for e in self.listed(include_draft=include_draft) if e.is_interim]
|
||||
|
||||
def stale_gaps(
|
||||
self,
|
||||
include_draft: bool = False,
|
||||
threshold_days: int = DEFAULT_STALE_DAYS,
|
||||
*,
|
||||
today: Optional[date] = None,
|
||||
) -> List[RouteEntry]:
|
||||
"""Interim lanes whose delegation review is past the cadence threshold."""
|
||||
out: List[RouteEntry] = []
|
||||
for e in self.gaps(include_draft=include_draft):
|
||||
reviewed = e.effective_delegation.reviewed or e.reviewed
|
||||
if is_review_stale(reviewed, threshold_days=threshold_days, today=today):
|
||||
out.append(e)
|
||||
return out
|
||||
|
||||
def freshness(
|
||||
self,
|
||||
*,
|
||||
|
|
@ -236,6 +261,15 @@ class Catalog:
|
|||
f"{stale_count} catalog entr{'y' if stale_count == 1 else 'ies'} "
|
||||
f"past {stale_threshold_days}d review cadence"
|
||||
)
|
||||
stale_interim = len(self.stale_gaps(
|
||||
include_draft=True, threshold_days=stale_threshold_days, today=today
|
||||
))
|
||||
if stale_interim:
|
||||
warnings.append(
|
||||
f"{stale_interim} interim delegation"
|
||||
f"{'' if stale_interim == 1 else 's'} past "
|
||||
f"{stale_threshold_days}d review — see `warden route gaps`"
|
||||
)
|
||||
|
||||
return CatalogFreshness(
|
||||
path=str(path),
|
||||
|
|
@ -362,6 +396,66 @@ def _parse_rotation(entry_id: str, raw: Optional[dict]) -> Optional[RotationGuid
|
|||
)
|
||||
|
||||
|
||||
def _parse_delegation(entry_id: str, raw: Optional[dict]) -> Optional[Delegation]:
|
||||
"""Parse an optional ``delegation:`` block (WARDEN-WP-0030).
|
||||
|
||||
Absence is allowed: the loader treats it as implicit interim with an
|
||||
unknown owner. When the block *is* present, mode / owner / blocker rules
|
||||
are enforced so a declared answer cannot be incomplete.
|
||||
"""
|
||||
if raw is None:
|
||||
return None
|
||||
if not isinstance(raw, dict):
|
||||
raise CatalogError(f"entry {entry_id!r} `delegation` must be a mapping")
|
||||
|
||||
mode = str(raw.get("mode", "")).strip()
|
||||
if mode not in VALID_DELEGATION_MODES:
|
||||
raise CatalogError(
|
||||
f"entry {entry_id!r} delegation.mode {mode!r} invalid "
|
||||
f"(expected one of {VALID_DELEGATION_MODES})"
|
||||
)
|
||||
|
||||
intended_owner = str(raw.get("intended_owner", "")).strip() or None
|
||||
if mode != "permanent" and not intended_owner:
|
||||
raise CatalogError(
|
||||
f"entry {entry_id!r} delegation.intended_owner is required "
|
||||
f"unless mode is permanent"
|
||||
)
|
||||
|
||||
blocked_on = str(raw.get("blocked_on", "")).strip() or None
|
||||
if mode == "interim" and not blocked_on:
|
||||
raise CatalogError(
|
||||
f"entry {entry_id!r} delegation.blocked_on is required when mode is interim"
|
||||
)
|
||||
|
||||
reviewed = str(raw.get("reviewed", "")).strip() or None
|
||||
if not reviewed:
|
||||
raise CatalogError(f"entry {entry_id!r} delegation.reviewed is required")
|
||||
try:
|
||||
date.fromisoformat(reviewed)
|
||||
except ValueError as e:
|
||||
raise CatalogError(
|
||||
f"entry {entry_id!r} delegation.reviewed {reviewed!r} is not YYYY-MM-DD"
|
||||
) from e
|
||||
|
||||
if intended_owner:
|
||||
_assert_no_secret_material(
|
||||
entry_id, "delegation.intended_owner", intended_owner, prose=True
|
||||
)
|
||||
if blocked_on:
|
||||
_assert_no_secret_material(
|
||||
entry_id, "delegation.blocked_on", blocked_on, prose=True
|
||||
)
|
||||
|
||||
return Delegation(
|
||||
mode=mode,
|
||||
intended_owner=intended_owner,
|
||||
blocked_on=blocked_on,
|
||||
reviewed=reviewed,
|
||||
implicit=False,
|
||||
)
|
||||
|
||||
|
||||
def _parse_entry(raw: dict, index: int) -> RouteEntry:
|
||||
if not isinstance(raw, dict):
|
||||
raise CatalogError(f"entry #{index} is not a mapping")
|
||||
|
|
@ -452,6 +546,7 @@ def _parse_entry(raw: dict, index: int) -> RouteEntry:
|
|||
pointer_command=handoff["pointer_command"],
|
||||
rotation=_parse_rotation(entry_id, raw.get("rotation")),
|
||||
risk=risk,
|
||||
delegation=_parse_delegation(entry_id, raw.get("delegation")),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,40 @@ class RotationGuide:
|
|||
# standard — ordinary workload secrets (ESO-fed, non-escrow); normal least-privilege.
|
||||
VALID_RISK = ("standard", "high")
|
||||
|
||||
# Delegation modes (WARDEN-WP-0030). Absence of a block is implicit interim.
|
||||
# native — intended owner already fronts the lane (route-primary / pointer)
|
||||
# interim — ops-warden covers a gap; intended_owner + blocked_on required
|
||||
# permanent — ops-warden is the designed owner of this front door (SSH only today)
|
||||
VALID_DELEGATION_MODES = ("native", "interim", "permanent")
|
||||
|
||||
IMPLICIT_DELEGATION_BLOCKED_ON = (
|
||||
"unclassified — no delegation block; treat as a question, not a settlement"
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Delegation:
|
||||
"""Who should own this front door, and what is missing (WARDEN-WP-0030).
|
||||
|
||||
Pointer-layer only: names the intended owner and the blocker. Does not
|
||||
restate how that owner will implement their front door.
|
||||
"""
|
||||
|
||||
mode: str # native | interim | permanent
|
||||
intended_owner: Optional[str] = None
|
||||
blocked_on: Optional[str] = None
|
||||
reviewed: Optional[str] = None
|
||||
implicit: bool = False
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"mode": self.mode,
|
||||
"intended_owner": self.intended_owner,
|
||||
"blocked_on": self.blocked_on,
|
||||
"reviewed": self.reviewed,
|
||||
"implicit": self.implicit,
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class RouteEntry:
|
||||
|
|
@ -78,6 +112,8 @@ class RouteEntry:
|
|||
rotation: Optional[RotationGuide] = None
|
||||
# Agent read-boundary risk class (WP-0026 T04). high → agents use wrap/out/exec only.
|
||||
risk: str = "standard" # "standard" | "high"
|
||||
# Delegation register (WP-0030). None → implicit interim with unknown owner.
|
||||
delegation: Optional[Delegation] = None
|
||||
|
||||
@property
|
||||
def is_active(self) -> bool:
|
||||
|
|
@ -111,6 +147,28 @@ class RouteEntry:
|
|||
"""True when an owner-native exec front door is the primary path for this lane."""
|
||||
return bool(self.exec_owner and self.exec_command)
|
||||
|
||||
@property
|
||||
def effective_delegation(self) -> Delegation:
|
||||
"""Declared delegation, or implicit interim with an unknown owner.
|
||||
|
||||
Absence of a ``delegation:`` block is a question (WP-0030), not a
|
||||
settlement that ops-warden owns the front door.
|
||||
"""
|
||||
if self.delegation is not None:
|
||||
return self.delegation
|
||||
return Delegation(
|
||||
mode="interim",
|
||||
intended_owner=None,
|
||||
blocked_on=IMPLICIT_DELEGATION_BLOCKED_ON,
|
||||
reviewed=None,
|
||||
implicit=True,
|
||||
)
|
||||
|
||||
@property
|
||||
def is_interim(self) -> bool:
|
||||
"""True when this lane is a tracked gap (explicit or implicit)."""
|
||||
return self.effective_delegation.mode == "interim"
|
||||
|
||||
@property
|
||||
def has_handoff(self) -> bool:
|
||||
"""True when structured assist fields are present (advisory richness)."""
|
||||
|
|
|
|||
|
|
@ -575,3 +575,137 @@ def test_route_show_json_includes_risk():
|
|||
assert payload["high_risk"] is True
|
||||
assert payload["resolvable"] is True
|
||||
assert payload["status"] == "active"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Delegation register (WARDEN-WP-0030)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_every_catalog_entry_declares_delegation():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
missing = [e.id for e in catalog.entries if e.delegation is None]
|
||||
assert missing == [], f"entries missing delegation block: {missing}"
|
||||
|
||||
|
||||
def test_every_proxy_declares_delegation():
|
||||
"""A new exec_capable proxy cannot land without answering the ownership question."""
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
missing = [
|
||||
e.id
|
||||
for e in catalog.entries
|
||||
if e.exec_capable and not e.warden_executes and e.delegation is None
|
||||
]
|
||||
assert missing == [], f"proxy lanes missing delegation: {missing}"
|
||||
|
||||
|
||||
def test_ssh_lane_is_permanent_delegation():
|
||||
e = load_catalog(_repo_catalog()).get("ssh-cert-host-access")
|
||||
assert e.delegation is not None
|
||||
assert e.delegation.mode == "permanent"
|
||||
assert e.delegation.intended_owner is None
|
||||
assert e.is_interim is False
|
||||
|
||||
|
||||
def test_native_exec_lanes_are_native_delegation():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
for eid, owner in (
|
||||
("whynot-design-npm-publish", "secrets-engine"),
|
||||
("ops-warden-warden-sign-token", "railiance-platform"),
|
||||
):
|
||||
e = catalog.get(eid)
|
||||
assert e.delegation is not None
|
||||
assert e.delegation.mode == "native"
|
||||
assert e.delegation.intended_owner == owner
|
||||
|
||||
|
||||
def test_founder_interim_lanes_classified():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
expected = {
|
||||
"rapp-qonto-keycape-client": "key-cape",
|
||||
"binky-company-email-imap": "tenant-engine",
|
||||
"binky-qonto-api": "tenant-engine",
|
||||
"railiance-backup-offsite-lane": "railiance-platform",
|
||||
"agent-harness-forgejo-deploy": "railiance-platform",
|
||||
}
|
||||
for eid, owner in expected.items():
|
||||
e = catalog.get(eid)
|
||||
assert e is not None and e.delegation is not None
|
||||
assert e.delegation.mode == "interim"
|
||||
assert e.delegation.intended_owner == owner
|
||||
assert e.delegation.blocked_on
|
||||
|
||||
|
||||
def test_missing_delegation_is_implicit_interim(tmp_path):
|
||||
catalog = load_catalog(_write_catalog(tmp_path, [dict(ROUTED_ENTRY)]))
|
||||
e = catalog.get("openbao-api-key")
|
||||
d = e.effective_delegation
|
||||
assert e.delegation is None
|
||||
assert d.implicit is True
|
||||
assert d.mode == "interim"
|
||||
assert d.intended_owner is None
|
||||
assert "unclassified" in (d.blocked_on or "")
|
||||
|
||||
|
||||
def test_interim_without_blocked_on_rejected(tmp_path):
|
||||
bad = dict(
|
||||
ROUTED_ENTRY,
|
||||
delegation={
|
||||
"mode": "interim",
|
||||
"intended_owner": "secrets-engine",
|
||||
"reviewed": "2026-08-15",
|
||||
},
|
||||
)
|
||||
with pytest.raises(CatalogError, match="blocked_on"):
|
||||
load_catalog(_write_catalog(tmp_path, [bad]))
|
||||
|
||||
|
||||
def test_non_permanent_without_owner_rejected(tmp_path):
|
||||
bad = dict(
|
||||
ROUTED_ENTRY,
|
||||
delegation={"mode": "native", "reviewed": "2026-08-15"},
|
||||
)
|
||||
with pytest.raises(CatalogError, match="intended_owner"):
|
||||
load_catalog(_write_catalog(tmp_path, [bad]))
|
||||
|
||||
|
||||
def test_invalid_delegation_mode_rejected(tmp_path):
|
||||
bad = dict(
|
||||
ROUTED_ENTRY,
|
||||
delegation={"mode": "maybe", "intended_owner": "x", "reviewed": "2026-08-15"},
|
||||
)
|
||||
with pytest.raises(CatalogError, match="delegation.mode"):
|
||||
load_catalog(_write_catalog(tmp_path, [bad]))
|
||||
|
||||
|
||||
def test_catalog_gaps_lists_only_interim():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
gap_ids = {e.id for e in catalog.gaps(include_draft=True)}
|
||||
assert "ssh-cert-host-access" not in gap_ids
|
||||
assert "whynot-design-npm-publish" not in gap_ids
|
||||
assert "binky-company-email-imap" in gap_ids
|
||||
assert "openbao-api-key" in gap_ids
|
||||
assert all(catalog.get(i).is_interim for i in gap_ids)
|
||||
|
||||
|
||||
def test_cli_route_gaps_json(repo_catalog_env):
|
||||
result = runner.invoke(app, ["route", "gaps", "--json"])
|
||||
assert result.exit_code == 0
|
||||
data = json.loads(result.stdout)
|
||||
assert data
|
||||
ids = {row["id"] for row in data}
|
||||
assert "binky-company-email-imap" in ids
|
||||
assert "ssh-cert-host-access" not in ids
|
||||
for row in data:
|
||||
assert row["mode"] == "interim"
|
||||
assert "intended_owner" in row
|
||||
assert "blocked_on" in row
|
||||
assert "days_since_review" in row
|
||||
|
||||
|
||||
def test_cli_route_show_includes_delegation(repo_catalog_env):
|
||||
result = runner.invoke(app, ["route", "show", "binky-qonto-api", "--json"])
|
||||
assert result.exit_code == 0
|
||||
data = json.loads(result.stdout)
|
||||
assert data["delegation"]["mode"] == "interim"
|
||||
assert data["delegation"]["intended_owner"] == "tenant-engine"
|
||||
assert data["delegation"]["implicit"] is False
|
||||
|
|
|
|||
|
|
@ -76,6 +76,44 @@ boundary in `OperatorAccessAssist.md`.
|
|||
|
||||
---
|
||||
|
||||
## Interim custodianship
|
||||
|
||||
ops-warden **works with, and never replaces or duplicates**, the NetKingdom
|
||||
components that own identity, custody, authorization, and tenant/user lifecycle
|
||||
(`INTENT.md` §9). Covering a gap is legitimate. Silently becoming the owner of
|
||||
that gap is not.
|
||||
|
||||
The only lane ops-warden executes with its own authority is **SSH issuance**
|
||||
(`ssh-cert-host-access`). Every other execution position — including every
|
||||
`warden access` proxy — is **interim by default**. A catalog entry without a
|
||||
`delegation:` block is treated as interim with an unknown owner: absence is a
|
||||
question, not a settlement.
|
||||
|
||||
| `delegation.mode` | Meaning |
|
||||
| --- | --- |
|
||||
| `permanent` | ops-warden is the designed owner of this front door (SSH only, today) |
|
||||
| `native` | the intended owner already fronts it; ops-warden routes (and may keep a proxy as fallback) |
|
||||
| `interim` | ops-warden covers the gap until `intended_owner` ships the missing front door named in `blocked_on` |
|
||||
|
||||
Delegation targets — the components that should own a front door once they have
|
||||
one:
|
||||
|
||||
| Target | What they should front |
|
||||
| --- | --- |
|
||||
| **secrets-engine** | owner-native secret-exec (`secrets-engine exec --catalog <id>`) |
|
||||
| **tenant-engine** | tenant/client secret custody and tenant-lane front door |
|
||||
| **user-engine** | end-user / account-lifecycle secrets that belong with user identity |
|
||||
| **railiance-platform** | OpenBao cluster, credential broker, platform workload procedure |
|
||||
| **flex-auth** | authorization decisions (already native — ops-warden only points) |
|
||||
| **key-cape** | identity login and client-credential protocol (OIDC, `client_secret_basic`) |
|
||||
|
||||
Query the register with `warden route gaps`. An interim lane is retired by
|
||||
setting `exec_owner` / `exec_command` (the WP-0019 pattern) and flipping
|
||||
`delegation.mode` to `native` once the owner's front door is proven. Do not
|
||||
delete a working proxy on the way.
|
||||
|
||||
---
|
||||
|
||||
## Routing lookup CLI (`warden route`)
|
||||
|
||||
Agents and operators query the pointer catalog directly instead of re-deriving
|
||||
|
|
@ -86,6 +124,7 @@ material.
|
|||
```bash
|
||||
warden route list [--json] [--all] [--tag <keyword>] # active-only unless --all
|
||||
warden route list --stale [--stale-days 90] [--all] [--json] # past review cadence
|
||||
warden route gaps [--json] [--all] # interim register (owner + blocker)
|
||||
warden route show <id> [--json] # owner + pointers; SSH adds steps
|
||||
warden route find "<free text need>" [--json] [--all] # rank by keyword overlap
|
||||
```
|
||||
|
|
@ -145,6 +184,7 @@ owner repo's shipped path.
|
|||
| **On canon change** | When net-kingdom security docs change, review affected `canon_ref` entries immediately |
|
||||
| **On owner ship** | When an owning repo merges a new OpenBao path or playbook, promote `draft` → `active` and bump `reviewed` |
|
||||
| **On agent confusion** | If `warden route find` misses a common query, add `need_keywords` or a playbook — do not restate owner procedure in the catalog |
|
||||
| **On interim review** | Run `warden route gaps` — re-check each `blocked_on` against the intended owner; flip to `native` when their front door exists |
|
||||
|
||||
### Stale check (operators and agents)
|
||||
|
||||
|
|
@ -177,6 +217,7 @@ moved but anchors still resolve.
|
|||
|
||||
- `CredentialRouting.md` — worker decision tree and routing table
|
||||
- `NetKingdomSecurityMap.md` — component literacy
|
||||
- `INTENT.md` — steward mission ("issue SSH, route the rest")
|
||||
- `INTENT.md` — steward mission ("issue SSH, route the rest"); §9 interim custodianship
|
||||
- `workplans/WARDEN-WP-0030-delegation-register.md` — delegation register
|
||||
- `workplans/WARDEN-WP-0010-access-routing-charter.md` — charter + no-double-source rule
|
||||
- `net-kingdom/docs/platform-identity-security-architecture.md` — platform canon
|
||||
|
|
|
|||
|
|
@ -81,7 +81,9 @@ These needs are also carried in the machine-readable pointer catalog
|
|||
The catalog is a **pointer-and-assist layer**: it names the owner, links the doc,
|
||||
and carries secret-free handoff templates for `warden access`. Only the SSH row is
|
||||
something ops-warden executes with its own authority. Non-SSH `exec_capable` rows
|
||||
run the owner's tool as the caller and preserve owner custody.
|
||||
run the owner's tool as the caller and preserve owner custody. Every execution
|
||||
position is classified `permanent` / `native` / `interim` (`warden route gaps`
|
||||
lists the interim set — WARDEN-WP-0030).
|
||||
|
||||
| Catalog `id` | What ops-warden answers | What the worker does next |
|
||||
| --- | --- | --- |
|
||||
|
|
|
|||
|
|
@ -24,10 +24,21 @@ Before changing `status: draft` → `status: active`:
|
|||
| 7 | **Review date** | Update `reviewed:` in catalog entry |
|
||||
| 8 | **Verification** | Positive + negative proof via **`bao token capabilities`** — never `bao kv get` (see below) |
|
||||
| 9 | **Rotation guidance** | Secret-vending lanes carry a `rotation:` block; `warden rotate-guide <id>` returns steps. Enforced by the `catalog_rotation_coverage` scorecard check (WP-0026 T06) |
|
||||
| 10 | **Delegation** | Entry carries a `delegation:` block (WP-0030). `mode: permanent` only for ops-warden's own front door. `mode: native` when the owner already fronts it. `mode: interim` requires `intended_owner` and `blocked_on`; the promotion note must name both and the retirement condition |
|
||||
|
||||
Promotion PR touches: `registry/routing/catalog.yaml`, playbook, optional
|
||||
`tests/test_routing.py`, and a one-line note in `wiki/CredentialRouting.md` draft table.
|
||||
|
||||
If `delegation.mode` is `interim`, the promotion note (PR body or State Hub
|
||||
progress) must state:
|
||||
|
||||
1. who the intended owner is
|
||||
2. what is missing (`blocked_on`)
|
||||
3. what would let ops-warden step back (`exec_owner` + proven owner front door)
|
||||
|
||||
A proxy that works is not enough to promote without answering the ownership
|
||||
question. `warden route gaps` must list the lane after merge if it is interim.
|
||||
|
||||
---
|
||||
|
||||
## Capabilities-safe lane verification (WARDEN-WP-0026 T01)
|
||||
|
|
@ -113,4 +124,6 @@ playbook prose alone.
|
|||
## See also
|
||||
|
||||
- `wiki/CredentialRouting.md` — draft table index
|
||||
- `wiki/playbooks/ops-warden-warden-sign-token.md` — promotion reference
|
||||
- `wiki/playbooks/ops-warden-warden-sign-token.md` — promotion reference
|
||||
- `wiki/AccessRouting.md#interim-custodianship` — delegation register doctrine
|
||||
- `warden route gaps` — queryable interim register
|
||||
|
|
@ -4,13 +4,13 @@ type: workplan
|
|||
title: "Delegation register — make gap-covering interim, visible, and retirable"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: proposed
|
||||
owner: claude
|
||||
status: finished
|
||||
owner: grok
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
planning_order: 30
|
||||
created: "2026-08-11"
|
||||
updated: "2026-08-11"
|
||||
updated: "2026-08-15"
|
||||
state_hub_workstream_id: "29f3fcb3-e3c5-4f9d-bdfd-f76254754e21"
|
||||
---
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ to *"who should own this front door, and what is missing?"*
|
|||
|
||||
```task
|
||||
id: WARDEN-WP-0030-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "3d76f6c2-5007-4ad5-8d6f-360f9303c929"
|
||||
```
|
||||
|
|
@ -103,7 +103,7 @@ targets. Cross-link INTENT.md §9.
|
|||
|
||||
```task
|
||||
id: WARDEN-WP-0030-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "8013020b-d0a5-4e89-8e0b-bc418a761c84"
|
||||
```
|
||||
|
|
@ -123,11 +123,26 @@ Backfill all 24 entries. `exec_owner` lanes become `mode: native`.
|
|||
eleven undelegated proxies are classified per the founder review below — five
|
||||
`interim` now, six held pending secrets-engine's answer.
|
||||
|
||||
**Landed 2026-08-15.** Catalog is now 27 entries. All 27 carry `delegation:`.
|
||||
|
||||
- `permanent` (1): `ssh-cert-host-access`
|
||||
- `native` (10): both `exec_owner` lanes plus the route-only pointers
|
||||
- `interim` (16): the five founder-classified now; the six held pending
|
||||
secrets-engine (still unanswered as of 2026-08-15, msg `7d55d332`) recorded as
|
||||
`interim` / `intended_owner: secrets-engine` / `blocked_on` the generic-vs-per-lane
|
||||
question — **not** `permanent`; plus five new-since-survey lanes drafted the same
|
||||
way (`email-connect-transactional` same held question; two AppRoles;
|
||||
`coulomb-social-runtime-env`; draft `scaleway-bootstrap`)
|
||||
|
||||
The six are not guessed permanent. Interim is the default until secrets-engine
|
||||
answers. Reclassify to `permanent` only if they confirm `exec --catalog` stays
|
||||
per-lane.
|
||||
|
||||
### T03 — `warden route gaps` + conformance test
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0030-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "e7755708-e1bf-4d42-999c-4a60330cf154"
|
||||
```
|
||||
|
|
@ -142,7 +157,7 @@ entries in the existing drift/stale review cadence.
|
|||
|
||||
```task
|
||||
id: WARDEN-WP-0030-T04
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "ddc0268b-1279-4875-b223-0627c97d657a"
|
||||
```
|
||||
|
|
@ -156,7 +171,7 @@ checklist.
|
|||
|
||||
```task
|
||||
id: WARDEN-WP-0030-T05
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "d8796e25-e896-463d-9476-f002e38b6897"
|
||||
```
|
||||
|
|
@ -167,16 +182,29 @@ what ops-warden currently fronts on your behalf, here is what would let us step
|
|||
back. This is the artefact that converts a private ops-warden position into a
|
||||
fleet-visible capability gap.
|
||||
|
||||
**Landed 2026-08-15.** Register sent (no secret values):
|
||||
|
||||
| To | Message |
|
||||
| --- | --- |
|
||||
| secrets-engine | `9c1d753f` — 1 native + 7 interim pending generic-exec answer |
|
||||
| tenant-engine | `17c851b1` — 2 Binky tenant lanes |
|
||||
| user-engine | `38aeccd5` — confirm USER_ENGINE_PROXY_SECRET ownership |
|
||||
| railiance-platform | `e75793e3` — 1 native + 4 interim |
|
||||
| net-kingdom | `3fea09df` — object-storage-sts remains native/draft |
|
||||
| key-cape | `28ded56c` — rapp-qonto-keycape-client (founder-classified interim) |
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [ ] `wiki/AccessRouting.md` states the interim-custodianship boundary and names
|
||||
- [x] `wiki/AccessRouting.md` states the interim-custodianship boundary and names
|
||||
the delegation targets
|
||||
- [ ] All 24 catalog entries carry `delegation`; `warden route gaps` returns the
|
||||
interim set with owner + blocker
|
||||
- [ ] Routing test fails when a proxy lane omits `delegation`
|
||||
- [ ] Promotion playbook gates draft→active on the ownership question
|
||||
- [ ] Founder has reviewed the interim/permanent classification of the eleven
|
||||
- [ ] Register delivered to the named owner repos
|
||||
- [x] All catalog entries carry `delegation`; `warden route gaps` returns the
|
||||
interim set with owner + blocker (27 entries; 15 active interim)
|
||||
- [x] Routing test fails when a proxy lane omits `delegation`
|
||||
- [x] Promotion playbook gates draft→active on the ownership question
|
||||
- [x] Founder has reviewed the interim/permanent classification of the eleven
|
||||
(2026-08-11); the six held lanes stay interim pending secrets-engine, not
|
||||
marked permanent
|
||||
- [x] Register delivered to the named owner repos (T05)
|
||||
|
||||
## Classification of the eleven (founder review, 2026-08-11)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue