Compare commits
29 commits
mason/stat
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 8afcc9c321 | |||
|
|
529feeac49 | ||
| 9770d6ad66 | |||
|
|
31694ab64d | ||
| eddb5d426b | |||
| 4fee839b11 | |||
| 8f01eefb1e | |||
| b4c1d3900a | |||
|
|
4e267179db | ||
|
|
d18d18e313 | ||
| 2e3ff772f4 | |||
| fd08950231 | |||
| 94f32bd160 | |||
| ec625873fb | |||
| f815bb35ca | |||
| 57d39ede0f | |||
|
|
f289465b90 | ||
|
|
a45280f30d | ||
| 61c992923c | |||
| ee94c18938 | |||
| d7f4ebcfe0 | |||
|
|
f766400563 | ||
| 70d8b503f0 | |||
| 85d3078bae | |||
|
|
467635e84b | ||
| 15730bb650 | |||
| 347e47ce8e | |||
| 37c387bd34 | |||
| 030362085a |
35 changed files with 4431 additions and 91 deletions
|
|
@ -16,6 +16,8 @@ distinction that matters here.
|
|||
| `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 |
|
||||
| `ADR-0009` | Adopt security-zones v0.1 as a consumer; membership is compiled, never inferred |
|
||||
| `ADR-0010` | ops-warden is Staff: it owns access lanes, never access rules; doctrine belongs to gate-house |
|
||||
|
||||
### Owned versus inherited — check `owner:` before changing anything
|
||||
|
||||
|
|
|
|||
|
|
@ -2,16 +2,20 @@
|
|||
# Custodian Brief — ops-warden
|
||||
|
||||
**Domain:** infotech
|
||||
**Last synced:** 2026-08-25 18:17 UTC
|
||||
**Last synced:** 2026-08-31 22:49 UTC
|
||||
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
|
||||
|
||||
## Active Workstreams
|
||||
|
||||
### Native lane handoff — review secrets-engine's catalog admission, and fix what it exposed
|
||||
Progress: 5/6 done | workplan_id: `4627d89b-4b00-562a-81e9-76e96f90fa7e`
|
||||
### Layer model v0.7 conformance — state the deadline, bind the agent boundary, steward the estate's newest rule
|
||||
Progress: 0/5 done | workplan_id: `ae3ff76f-883d-5e2f-b6aa-144d61e8fdef`
|
||||
|
||||
**Open tasks:**
|
||||
- ! Tasks `5acac140`
|
||||
- · Tasks `8b3bdb9f`
|
||||
- · Tasks `3318ee1a`
|
||||
- · Tasks `a891b32c`
|
||||
- · Tasks `94e73daa`
|
||||
- · Tasks `7d1b3c82`
|
||||
|
||||
### Tamper-resistant credential governance + mass rotation/lockdown (Strand B)
|
||||
Progress: 2/3 done | workplan_id: `21528e8d-a049-523d-9ae1-da7a27cb8bbf`
|
||||
|
|
@ -21,9 +25,8 @@ Progress: 2/3 done | workplan_id: `21528e8d-a049-523d-9ae1-da7a27cb8bbf`
|
|||
|
||||
## Inbox Hygiene
|
||||
|
||||
**Stale unread:** 9 message(s) older than 3 day(s) — triage at session start.
|
||||
**Missing thread_id:** 7 unread message(s) lack supersession chains.
|
||||
- ! secrets-engine: Re: Need the warden-sign live apply/handoff (FLEX-WP-0007 T4) `80456912`
|
||||
**Stale unread:** 1 message(s) older than 3 day(s) — triage at session start.
|
||||
**Missing thread_id:** 6 unread message(s) lack supersession chains.
|
||||
|
||||
---
|
||||
## MCP Orientation (when available)
|
||||
|
|
|
|||
2360
.repo-manager/index.json
Normal file
2360
.repo-manager/index.json
Normal file
File diff suppressed because it is too large
Load diff
120
INTENT.md
120
INTENT.md
|
|
@ -1,5 +1,68 @@
|
|||
---
|
||||
layer: Staff
|
||||
role: null # Engines only: PDP | PIP | Evidence | Lifecycle
|
||||
pep_shaped: true # §6.4 — issuing a certificate is a protected side effect
|
||||
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
||||
standard_version: "0.7"
|
||||
companion: net-kingdom/SECURITY-COMPANION.md
|
||||
declaration: layer.yaml
|
||||
pep_stance: pep-stance.yaml
|
||||
assent: docs/adr/ADR-0010
|
||||
---
|
||||
|
||||
# INTENT
|
||||
|
||||
> **ops-warden is Staff, and PEP-shaped.** Declared here in its own voice, per
|
||||
> `security-layer-model_v0.7` §11 — a layer stated *about* a repository by another
|
||||
> repository is not a declaration. The standard is **accepted**; its operative form
|
||||
> is `net-kingdom/SECURITY-COMPANION.md`. ops-warden's assent is `ADR-0010`, and its
|
||||
> reviews of v0.4, v0.6 and v0.7 are in `history/`.
|
||||
>
|
||||
> **Staff** because ops-warden's core function is judgement, not computation: it
|
||||
> decides which lane a need belongs to and stewards the paths through the estate's
|
||||
> rules. Its artifacts are runbooks, routing decisions, workplans. **PEP-shaped**
|
||||
> because issuing a certificate is a protected side effect — a shape, not a layer
|
||||
> (§6.4). ops-warden renders no authorization decision and never will; it consumes
|
||||
> them from `access-engine`.
|
||||
>
|
||||
> **The estate's front door for paths.** The companion routes the whole estate here:
|
||||
> *"For how to get something done — which lane, which credential, which route — ask
|
||||
> `ops-warden`. This document says what the rules are; ops-warden stewards the paths
|
||||
> through them."* That is a standing obligation, not a compliment: every rule
|
||||
> gate-house writes needs a path someone can actually walk, and ops-warden owes the
|
||||
> estate that path.
|
||||
>
|
||||
> **The declarations are files, not this note** — prose cannot distinguish a
|
||||
> declaration from a transcribed review (§11):
|
||||
>
|
||||
> | File | Declares | Enforced by |
|
||||
> | --- | --- | --- |
|
||||
> | `layer.yaml` | every Tooling contact, mapped to a §5.1/§5.2/§5.3 shape, plus the non-Tooling clients so the check is total | `scripts/check_layer_conformance.py`, `tests/test_layer_conformance.py` |
|
||||
> | `pep-stance.yaml` | the unreachable-engine stance map (§6.4 obl. 3), total per zone | test asserts the published map **equals** the shipped default |
|
||||
> | `tenancy.yaml` | tenancy posture, and `z1-operational` zone membership | `ADR-0009` |
|
||||
>
|
||||
> Both are cited in the standard as the estate's reference forms (§11, §6.4, §13.1).
|
||||
>
|
||||
> **Two declared engine gaps (§5.3), tracked non-conformance and not conformance.**
|
||||
> `VaultCA` signs over a direct OpenBao client and `warden desk` shells `bao kv put`.
|
||||
> Intended owner **secrets-engine**; blocked on no engine exposing an SSH-CA or
|
||||
> attended-provisioning surface; reviewed quarterly; registered in statute §13.
|
||||
> ops-warden keeps signing while the gap is open — refusing would remove production
|
||||
> host access to close a documentation gap.
|
||||
>
|
||||
> **The agent principal (§3.4).** ops-warden is operated by agents as well as people,
|
||||
> and they share the layer but not the blast radius. No standing credential; tool use
|
||||
> is a conduit or an engine API and there is no third route; **tool availability is
|
||||
> not permission**, which is exactly what `ADR-0004`'s read-boundary enforces; agent
|
||||
> memory is not a state plane. Session semantics belong to `glas-harness`, not here.
|
||||
>
|
||||
> **Evidence (§9.6).** ops-warden's audit trail is **attributive**, not load-bearing:
|
||||
> no control branches on the presence of a signing record. Emission is deliberately
|
||||
> non-atomic so an audit-store failure cannot remove production host access — a trade
|
||||
> the standard sanctions, declared in `wiki/AuditTrail.md`, registered in §13. If any
|
||||
> future control ever gates on this trail, that trade must be revisited before it
|
||||
> ships.
|
||||
|
||||
> This file captures **why this repository exists**, the **direction it is
|
||||
> moving toward**, and the **kind of system it is meant to become**.
|
||||
> It is intentionally **aspirational and stable**, not a description of
|
||||
|
|
@ -77,30 +140,52 @@ owns one lane and points at the rest:
|
|||
|
||||
---
|
||||
|
||||
## NetKingdom Security Literacy
|
||||
## Lane routing — who owns which need
|
||||
|
||||
ops-warden should be fluent in the platform architecture documented in
|
||||
`net-kingdom` — especially:
|
||||
**This is a runbook, not doctrine.** Security doctrine, the authority model, and the
|
||||
security curriculum are **gate-house's** (`security-layer-model_v0.7` §8).
|
||||
ops-warden references them and does not restate them. What follows is lane
|
||||
stewardship: which subsystem owns which need, and what ops-warden does about it.
|
||||
|
||||
| Plane / component | Role in access | ops-warden relationship |
|
||||
| --- | --- | --- |
|
||||
| **key-cape / Keycloak** | Identity — who is the actor, MFA, IAM Profile claims | Instruct identity path; do not re-implement OIDC |
|
||||
| **flex-auth + Topaz** | Authorization — may this actor perform this action | Caller-side policy gate shipped (opt-in); production flip is flex-auth's |
|
||||
| **OpenBao** | Runtime secrets — API keys, dynamic creds, leases, audit | Instruct custody paths; SSH engine is signing backend only; proxy reads as caller when `exec_capable` |
|
||||
| **secrets-engine** | Owner-native secret-exec (`secrets-engine exec`) | Route provisioned exec lanes (e.g. npm publish); ops-warden does not hold tokens |
|
||||
| **railiance-platform** (credential broker) | Scoped lease grants (`credential exec`) | Route `warden-sign` token needs; ops-warden does not mint OpenBao tokens |
|
||||
| **tenant-engine** | Tenant/client secret custody and front door | Route tenant lanes once fronted; ops-warden's current tenant proxies are interim (§9) |
|
||||
| **user-engine** | End-user identity and account lifecycle | No ops-warden lane today; route rather than absorb |
|
||||
| **ops-warden** | Operational SSH certificates — short-lived host access | **Own and issue** this lane |
|
||||
| **ops-bridge** | Tunnel transport — consumes certs via `cert_command` | Primary consumer; document integration |
|
||||
| **railiance-infra** | Host principals, force-command, SSH hardening | Instruct host-side deployment; do not own Ansible |
|
||||
| **railiance-platform** (deploy) | OpenBao/K8s/platform service deployment | Instruct production endpoints; do not deploy clusters |
|
||||
The machine-readable form is `registry/routing/catalog.yaml`, and the executable form
|
||||
is `warden plan "<need>"` / `warden route find`. Prefer either over this table — it is
|
||||
orientation, and the catalog is the source of truth (`ADR-0001`).
|
||||
|
||||
| Component | Layer | Owns | ops-warden relationship |
|
||||
| --- | --- | --- | --- |
|
||||
| **gate-house** | Staff | Security doctrine, invariants, authority ceilings, authority context, conformance review, curriculum | **Route doctrine and authority-model questions here.** Not policy decisions — those go to access-engine |
|
||||
| **access-engine** (`flex-auth`) | Engine | **The policy decision** — whether an actor may act. The only decision point in NetKingdom | Consume decisions; caller-side pre-sign gate. ops-warden never renders or caches one |
|
||||
| **key-cape / Keycloak** | Tooling | Identity — who the actor is, MFA, IAM Profile claims | Instruct the identity path; do not re-implement OIDC |
|
||||
| **OpenBao** | Tooling | Runtime secrets — API keys, dynamic creds, leases, audit | Instruct custody paths; proxy reads as the caller when `exec_capable`. Direct client use is the declared exception above |
|
||||
| **secrets-engine** | Engine | Credential abstraction, custody, lifecycle; owner-native exec | Route provisioned exec lanes (e.g. npm publish). **Intended owner of the SSH-CA surface** |
|
||||
| **tenant-engine** | Engine | Tenant/client secret custody and front door | Route tenant lanes once fronted; current tenant proxies are interim (section 9) |
|
||||
| **user-engine** | Engine | Users, accounts, memberships | No ops-warden lane today; route rather than absorb |
|
||||
| **zone-engine** | Engine | Zone identity and membership | Consume compiled membership; ops-warden declares `z1-operational` (`ADR-0009`) |
|
||||
| **railiance-platform** (broker) | — | Scoped lease grants (`credential exec`) | Route `warden-sign` token needs; ops-warden does not mint OpenBao tokens |
|
||||
| **ops-mason** | Staff | Building and tearing down access routes and perimeters | Peer lane owner; same lane/rule demarcation applies |
|
||||
| **ops-warden** | Staff | **Operational access lanes** — short-lived SSH certificates, routing, stewardship, runbooks | **Own and issue** the SSH lane |
|
||||
| **ops-bridge** | Staff | Tunnel transport — consumes certs via `cert_command` | Primary consumer; document integration |
|
||||
| **railiance-infra** | — | Host principals, force-command, SSH hardening | Instruct host-side deployment; do not own Ansible |
|
||||
| **kings-guard** | Staff | Adaptive defence, observation, containment; publishes posture | Posture may reduce authority, never manufacture it |
|
||||
|
||||
### Access lane versus access rule
|
||||
|
||||
Normative, per `security-layer-model_v0.7` §8 and assented to in `ADR-0010`:
|
||||
|
||||
- **access lane** — ops-warden and ops-mason. *How* a worker reaches a host.
|
||||
- **access rule** — access-engine. *Whether* they may.
|
||||
|
||||
ops-warden owns the route and never the decision. A question about whether an actor
|
||||
may do something is not an ops-warden question, however it arrives.
|
||||
|
||||
Canonical references:
|
||||
|
||||
- `net-kingdom/SECURITY-COMPANION.md` — the operative form; start here
|
||||
- `net-kingdom/canon/standards/security-layer-model_v0.7.md` (accepted; §5 shapes, §6.4 PEP, §8 vocabulary)
|
||||
- `net-kingdom/docs/platform-identity-security-architecture.md`
|
||||
- `net-kingdom/docs/responsibility-map.md`
|
||||
- `wiki/AccessManagementDirective.md` (ops SSH actor model)
|
||||
- `.claude/rules/credential-routing.md` (agent-facing runbook — stays inline by design)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -123,7 +208,8 @@ Canonical references:
|
|||
| Need | Route to |
|
||||
| --- | --- |
|
||||
| OIDC login, MFA, human identity claims | key-cape / Keycloak (NetKingdom IAM Profile) |
|
||||
| Policy decision — may actor X access resource Y | flex-auth |
|
||||
| Security doctrine, invariants, authority model | gate-house |
|
||||
| Policy decision — may actor X access resource Y | access-engine (`flex-auth`) |
|
||||
| API keys, provider secrets, DB creds, object-storage STS | OpenBao (+ flex-auth policy where required) |
|
||||
| Inter-Hub operator keys, LLM provider credentials | OpenBao or approved operator secret store |
|
||||
| Tunnel lifecycle, port forwarding | ops-bridge |
|
||||
|
|
|
|||
29
SCOPE.md
29
SCOPE.md
|
|
@ -85,6 +85,28 @@ cutover, flex-auth publishing the zone-aware pre-sign stance package,
|
|||
the owner-driven WP-0015 canon landing, and — newly named — the missing owner front
|
||||
doors that keep ops-warden holding interim lanes (secrets-engine, tenant-engine).
|
||||
|
||||
### Layer-model conformance (v0.7, accepted)
|
||||
|
||||
ops-warden declares **Staff**, **PEP-shaped**, in `INTENT.md` frontmatter and in its
|
||||
own voice — `security-layer-model_v0.7` §11. Shipped declaration artifacts, both
|
||||
cited in the standard as the estate's reference forms:
|
||||
|
||||
| Artifact | Declares | Status |
|
||||
| --- | --- | --- |
|
||||
| `layer.yaml` | 5 Tooling contacts mapped to §5.1/§5.2/§5.3 shapes + non-Tooling clients so the check is total | shipped; named reference form (§11) |
|
||||
| `pep-stance.yaml` | unreachable-engine stance map, total per zone | shipped; registered in statute §13.1 (§6.4 obl. 3) |
|
||||
| `scripts/check_layer_conformance.py` | every direct Tooling client maps to a declared shape | shipped; CI-enforced |
|
||||
| `tests/test_layer_conformance.py` | the §5.2 no-authority property, and published stance map **equals** shipped default | shipped, 11 tests |
|
||||
|
||||
Conformance state under §11: **declared gap** — tracked non-conformance, not
|
||||
conformance. Two §5.3 contacts (`VaultCA` signing write, `warden desk` `bao kv put`),
|
||||
intended owner `secrets-engine`, registered in statute §13.
|
||||
|
||||
Four ops-warden findings have been adopted into the standard: §9.1's two marks
|
||||
(`pending` vs `declared-gap`), §5's Tooling scope rule, §6.4 obligation 1's second
|
||||
limb, and §13.1's existence. Reviews: `history/2026-08-29-layer-model-v04-review.md`,
|
||||
`-v06-review.md`, `-v07-scope-intent-assessment.md`.
|
||||
|
||||
### Issue vs route
|
||||
|
||||
ops-warden executes exactly one lane with its own authority and routes/assists the rest.
|
||||
|
|
@ -156,6 +178,7 @@ superseding ADR, never an in-place edit.
|
|||
| `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 |
|
||||
| `ADR-0009` | Adopt security-zones v0.1 and compile explicit workload membership; PEP failure mode is per zone |
|
||||
| `ADR-0010` | ops-warden is Staff and PEP-shaped — it owns access lanes, never access rules; the direct OpenBao client is a declared engine gap, not an exemption |
|
||||
|
||||
Rules we follow but do not own — NetKingdom canon, the IAM profile, the
|
||||
credential-management standard, the-custodian's ADR-001 workplan convention — are
|
||||
|
|
@ -433,11 +456,12 @@ Downstream: `ops-bridge` (primary), kaizen agents, CI automations, human operato
|
|||
|
||||
| Repo | Relationship |
|
||||
| --- | --- |
|
||||
| `gate-house` | Owns the security layer model, doctrine, invariants, authority context, and conformance review. ops-warden routes doctrine questions there, and the companion routes the estate's *path* questions back to ops-warden (`ADR-0010`) |
|
||||
| `net-kingdom` | Canonical security architecture; ops-warden aligns to it |
|
||||
| `ops-bridge` | Primary cert_command consumer |
|
||||
| `railiance-infra` | Host-side SSH principals and hardening |
|
||||
| `railiance-platform` | OpenBao deployment and platform secrets |
|
||||
| `flex-auth` | Authorization; policy package shipped (FLEX-WP-0006); runtime deploy FLEX-WP-0007 |
|
||||
| `flex-auth` | Authorization — ruled name `access-engine`; the only policy decision point. Policy package shipped (FLEX-WP-0006); runtime deploy FLEX-WP-0007 |
|
||||
| `key-cape` | Identity / IAM Profile lightweight mode |
|
||||
| `secrets-engine` | Owner-native secret-exec front door (`secrets-engine exec/route`); ops-warden routes provisioned secret lanes to it (WP-0019) and holds 6 more as interim proxies pending its front doors |
|
||||
| `tenant-engine` | Intended owner of tenant/client secret front doors; ops-warden holds 3 tenant lanes as interim proxies (WP-0028 pattern, WP-0030 register) |
|
||||
|
|
@ -486,6 +510,9 @@ keywords: [access, credential, secret, npm, token, api-key, openbao, key-cape, l
|
|||
| `wiki/CredentialRouting.md` | Which subsystem for each credential need |
|
||||
| `wiki/WorkloadSecurityPosture.md` | Secret-store posture, workload maturity, and blocker triage |
|
||||
| `registry/routing/catalog.yaml` | Machine-readable routing pointer catalog |
|
||||
| `net-kingdom/SECURITY-COMPANION.md` | **The estate's operative security rules — start here** |
|
||||
| `layer.yaml` | Layer declaration: every Tooling contact and its §5 shape |
|
||||
| `pep-stance.yaml` | Unreachable-engine stance map (§6.4); equals shipped behaviour by test |
|
||||
| `tenancy.yaml` | Declared tenancy posture (`I1 A1 E0 P n/a R n/a V0`) and why each axis sits where it does |
|
||||
| `wiki/NetKingdomSecurityMap.md` | Platform security component map |
|
||||
| `examples/warden.production.example.yaml` | Production warden.yaml template |
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@
|
|||
|
||||
| Kind | ID | Status | Lane | Source |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| workplan | ADHOC-2026-06-27 | finished | — | workplans/ADHOC-2026-06-27.md |
|
||||
| workplan | ADHOC-2026-06-29 | finished | — | workplans/ADHOC-2026-06-29.md |
|
||||
| workplan | ADHOC-2026-08-11 | finished | — | workplans/ADHOC-2026-08-11.md |
|
||||
| workplan | ADHOC-2026-08-17 | finished | — | workplans/ADHOC-2026-08-17.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-06-27 | finished | — | workplans/ADHOC-2026-06-27.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-06-29 | finished | — | workplans/ADHOC-2026-06-29.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-08-11 | finished | — | workplans/ADHOC-2026-08-11.md |
|
||||
| workplan | WARDEN-WP-ADHOC-2026-08-17 | finished | — | workplans/ADHOC-2026-08-17.md |
|
||||
| workplan | WARDEN-WP-0016 | finished | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
| workplan | WARDEN-WP-0017 | finished | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md |
|
||||
| workplan | WARDEN-WP-0018 | finished | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md |
|
||||
|
|
@ -29,16 +29,19 @@
|
|||
| 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 | finished | — | 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 |
|
||||
| task | ADHOC-2026-08-11-T02 | done | — | workplans/ADHOC-2026-08-11.md |
|
||||
| task | ADHOC-2026-08-11-T03 | done | — | workplans/ADHOC-2026-08-11.md |
|
||||
| task | ADHOC-2026-08-17-T01 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | ADHOC-2026-08-17-T02 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | ADHOC-2026-08-17-T03 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | ADHOC-2026-08-17-T04 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| workplan | WARDEN-WP-0033 | finished | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| workplan | WARDEN-WP-0034 | ready | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| workplan | WARDEN-WP-0035 | finished | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md |
|
||||
| workplan | WARDEN-WP-0036 | finished | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-06-27-T01 | done | — | workplans/ADHOC-2026-06-27.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-06-29-T01 | done | — | workplans/ADHOC-2026-06-29.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-11-T01 | done | — | workplans/ADHOC-2026-08-11.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-11-T02 | done | — | workplans/ADHOC-2026-08-11.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-11-T03 | done | — | workplans/ADHOC-2026-08-11.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-17-T01 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-17-T02 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-17-T03 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | WARDEN-WP-ADHOC-2026-08-17-T04 | done | — | workplans/ADHOC-2026-08-17.md |
|
||||
| task | WARDEN-WP-0016-T01 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
| task | WARDEN-WP-0016-T02 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
| task | WARDEN-WP-0016-T03 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md |
|
||||
|
|
@ -126,6 +129,17 @@
|
|||
| task | WARDEN-WP-0033-T01 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T02 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T03 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T04 | wait | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T04 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T05 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0033-T06 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md |
|
||||
| task | WARDEN-WP-0034-T01 | todo | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T02 | todo | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T03 | todo | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T04 | todo | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0034-T05 | todo | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md |
|
||||
| task | WARDEN-WP-0035-T01 | done | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md |
|
||||
| task | WARDEN-WP-0035-T02 | done | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md |
|
||||
| task | WARDEN-WP-0036-T01 | done | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md |
|
||||
| task | WARDEN-WP-0036-T02 | done | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md |
|
||||
| intake | WARDEN-IN-0001 | closed | — | intakes/intakes.md |
|
||||
| intake | WARDEN-IN-0002 | open | — | intakes/intakes.md |
|
||||
|
|
|
|||
109
docs/adr/ADR-0010-ops-warden-is-staff.md
Normal file
109
docs/adr/ADR-0010-ops-warden-is-staff.md
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
---
|
||||
id: ops-warden-adr-0010
|
||||
type: adr
|
||||
title: "ADR-0010 — ops-warden is Staff: lanes, not rules, and one declared engine gap"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: accepted
|
||||
version: "1.0"
|
||||
revision: "1"
|
||||
owner: ops-warden
|
||||
binds: "ops-warden"
|
||||
created: "2026-08-28"
|
||||
updated: "2026-08-28"
|
||||
last_reviewed: "2026-08-28"
|
||||
review_interval: 3m
|
||||
enforced_by: "INTENT.md layer declaration; docs/adr/ADR-0002; docs/adr/ADR-0003; docs/adr/ADR-0005; registry/routing/catalog.yaml delegation fields"
|
||||
supersedes: ""
|
||||
successor: ""
|
||||
---
|
||||
|
||||
# ADR-0010 — ops-warden is Staff: lanes, not rules, and one declared engine gap
|
||||
|
||||
## Status
|
||||
|
||||
Accepted 2026-08-28, answering intake `WARDEN-IN-0001` from gate-house, which
|
||||
carries decision `GH-DEC-2026-001`. The standard being adopted —
|
||||
`net-kingdom/canon/standards/security-layer-model_v0.1.md` — is `proposed`, and was
|
||||
proposed pending assent from flex-auth, kings-guard, and ops-warden. This ADR is
|
||||
ops-warden's half of that assent.
|
||||
|
||||
## Context
|
||||
|
||||
The estate acquired overlapping claims to the same responsibility, most visibly two
|
||||
repositories describing themselves as the authorization control plane. The layer
|
||||
model resolves the overlap by layering repositories on determinism — Taxonomy,
|
||||
Tooling, Engines, Staff — and by two rules: Staff never touches Tooling directly
|
||||
(§5), and `access-engine` is the only policy decision point (§6).
|
||||
|
||||
ops-warden is assigned Staff. Two demarcations follow that touch this repository:
|
||||
the security curriculum it had been carrying belongs to gate-house, and the words
|
||||
*access lane* and *access rule* are bound to different owners.
|
||||
|
||||
Full reasoning: `history/2026-08-28-security-layer-model-assent.md`.
|
||||
|
||||
## Decision
|
||||
|
||||
**1. ops-warden is Staff and declares it.** `INTENT.md` carries the layer label and
|
||||
the §5 invariant. ops-warden holds no state another layer depends on at runtime and
|
||||
renders no authorization decision — it consumes them.
|
||||
|
||||
**2. Lanes, not rules.** ops-warden owns *how* a worker reaches a host: SSH
|
||||
certificate issuance, the routing catalog, `warden access`, `warden plan`,
|
||||
`cert_command`. It never owns *whether* a worker may — that is `access-engine`
|
||||
(today `flex-auth`), and ops-warden neither renders nor caches that decision. This
|
||||
restates what `ADR-0002` and `ADR-0005` already bind; it is recorded here because
|
||||
the demarcation is now normative estate-wide and other repositories rely on
|
||||
ops-warden holding to it. The ruled rename `flex-auth` → `access-engine` is assented
|
||||
to; ops-warden asks only for a window in which both names resolve.
|
||||
|
||||
**3. Doctrine goes to gate-house; runbooks stay here.** ops-warden does not restate
|
||||
security doctrine, the authority model, or the curriculum. It references
|
||||
gate-house's. It keeps everything operational about the lanes it stewards: which
|
||||
subsystem owns which need, how to obtain a credential lane by lane, and conformance
|
||||
evidence for its own lanes. `.claude/rules/credential-routing.md` is runbook, not
|
||||
curriculum, and stays inlined in this and every other repository.
|
||||
|
||||
**4. One declared engine gap, not an exemption.** `src/warden/vault.py` (`VaultCA`)
|
||||
is a direct OpenBao client performing a write from a Staff repository. It is a §5
|
||||
non-conformance. ops-warden declares it rather than arguing it away:
|
||||
|
||||
- **intended owner:** `secrets-engine` (credential abstraction, custody, lifecycle)
|
||||
- **blocked on:** no engine exposes an SSH certificate signing surface
|
||||
- **review:** with this ADR, every 3 months
|
||||
|
||||
Until that surface exists, ops-warden continues to sign — refusing to would remove
|
||||
production host access to close a documentation gap — and reports the position as
|
||||
open. `warden desk`'s `bao kv put` is declared on the same terms. `taint.py` is
|
||||
metadata-only observation, declared under §5's read-only allowance. `proxy.py`
|
||||
supplies no authority of its own: it runs the owner's tool under the caller's
|
||||
identity and is governed by `ADR-0002`.
|
||||
|
||||
This is `ADR-0003` turned inward. ops-warden has required an intended owner and a
|
||||
blocker on 27 catalog lanes it holds for other repositories; it holds itself to the
|
||||
same record.
|
||||
|
||||
## Consequences
|
||||
|
||||
ops-warden's conformance under §10 is *declared non-conformant with a tracked
|
||||
closure path*, not clean. That is the accurate state and it is the state that gets
|
||||
fixed, because it names an owner who can fix it.
|
||||
|
||||
An amendment to §5 has been offered to gate-house — a second sanctioned shape
|
||||
alongside read-only diagnostics: a declared engine gap carrying intended owner,
|
||||
blocker, and review date, machine-readable so §10 can tell a tracked gap from an
|
||||
undeclared violation. It is offered, not assumed; §5 stays gate-house's to write. If
|
||||
gate-house declines it, ops-warden's position is a plain non-conformance and is
|
||||
reported as one.
|
||||
|
||||
The `NetKingdom Security Literacy` section stops being a prose second source for
|
||||
`registry/routing/catalog.yaml`, which `ADR-0001` had already ruled against for
|
||||
catalog procedure.
|
||||
|
||||
## Related
|
||||
|
||||
- `net-kingdom/canon/standards/security-layer-model_v0.1.md` (proposed, gate-house)
|
||||
- `gate-house/decisions/decisions.md` — `GH-DEC-2026-001`
|
||||
- `history/2026-08-28-security-layer-model-assent.md`
|
||||
- `ADR-0001`, `ADR-0002`, `ADR-0003`, `ADR-0005`, `ADR-0009`
|
||||
- `WARDEN-IN-0001`
|
||||
|
|
@ -71,3 +71,4 @@ and the publication is a defect.
|
|||
| `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 |
|
||||
| `ADR-0009` | Adopt security-zones v0.1; compile explicit membership and select PEP failure mode per zone | ops-warden |
|
||||
| `ADR-0010` | ops-warden is Staff: it owns access lanes, never access rules; the direct OpenBao client is a declared engine gap | ops-warden, and gate-house as the standard's owner |
|
||||
|
|
|
|||
171
history/2026-08-28-security-layer-model-assent.md
Normal file
171
history/2026-08-28-security-layer-model-assent.md
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
# Security layer model — ops-warden's assent (WARDEN-IN-0001)
|
||||
|
||||
**Date:** 2026-08-28
|
||||
**Intake:** `WARDEN-IN-0001`
|
||||
**Requested by:** gate-house, ratified as `GH-DEC-2026-001`
|
||||
**Standard:** `net-kingdom/canon/standards/security-layer-model_v0.1.md` (proposed)
|
||||
**Outcome:** assent to all three items; one declared non-conformance and one
|
||||
proposed amendment to the standard.
|
||||
|
||||
---
|
||||
|
||||
## What was asked
|
||||
|
||||
gate-house asked ops-warden to assent to three boundary items:
|
||||
|
||||
1. **ops-warden is Staff**, bound by §5 — Staff acts only through Engine APIs and
|
||||
never holds a direct Tooling client.
|
||||
2. **Doctrine versus runbook** — the security curriculum moves to gate-house; the
|
||||
`NetKingdom Security Literacy` section in `INTENT.md` becomes lane-specific
|
||||
runbooks that reference gate-house doctrine rather than restating it.
|
||||
3. **The access lane / access rule demarcation** (§8) — ops-warden and ops-mason own
|
||||
*lanes* (how a worker reaches a host); access-engine owns *rules* (whether they
|
||||
may). This is the condition attached to renaming flex-auth to access-engine, so
|
||||
ops-warden effectively holds a veto on that name.
|
||||
|
||||
Plus: add gate-house to the literacy and routing tables, and say so if moving the
|
||||
curriculum out leaves ops-warden unable to instruct its own workers.
|
||||
|
||||
---
|
||||
|
||||
## Item 1 — Staff, and the §5 problem it exposes
|
||||
|
||||
**Assent to the layer.** Staff is the right assignment and not a demotion.
|
||||
ops-warden's artifacts are exactly what §3.4 describes: routing decisions,
|
||||
workplans, runbooks, an audit trail. Its one production lane is non-deterministic
|
||||
in the sense that matters — it is an operator front door, not a contract.
|
||||
|
||||
**But §5 is violated today, and by the one lane ops-warden permanently owns.**
|
||||
The rule is deliberately greppable, so grepping is the honest response:
|
||||
|
||||
| Path | Tooling contact | Kind | Whose credential |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/warden/vault.py` (`VaultCA.sign`) | `POST <bao>/v1/<mount>/sign/<role>` | **write** | broker-issued token held by ops-warden's process |
|
||||
| `src/warden/desk.py` | `bao kv put` (paste-once provisioning) | **write** | founder's, at the desk |
|
||||
| `src/warden/taint.py` | `bao kv metadata get` | read (metadata only, never data) | caller's |
|
||||
| `src/warden/proxy.py` (`warden access --fetch/--exec/--wrap`) | catalog `fetch_command` | read | **the caller's own** |
|
||||
|
||||
Two of these are not really ops-warden's clients. `proxy.py` runs the owner's tool
|
||||
under the caller's identity and supplies no authority of its own — that is
|
||||
`ADR-0002`, conduit not broker, and it is arguably outside §5's target. `taint.py`
|
||||
reads metadata only, and fits §5's read-only-observation allowance once declared.
|
||||
|
||||
**`VaultCA` does not have that defence.** It is a direct OpenBao client, in a Staff
|
||||
repository, performing a write, presenting a token from its own environment. It is
|
||||
production-verified and it is the SSH lane — the single thing ops-warden owns
|
||||
permanently. Under §5 as written, adopting this standard puts ops-warden's core
|
||||
lane in violation on the day it is adopted.
|
||||
|
||||
The escape hatch §5 offers does not fit: it covers *read-only observation for
|
||||
diagnostics*, and signing is a write. The route §5 prescribes does fit —
|
||||
|
||||
> *A Staff repository needing a capability no engine exposes MUST raise that as an
|
||||
> engine gap, not solve it locally.*
|
||||
|
||||
— and no engine exposes SSH certificate signing. `secrets-engine` owns credential
|
||||
abstraction, custody and lifecycle, which is the layer this belongs in, but it
|
||||
fronts no SSH-CA API today.
|
||||
|
||||
**So ops-warden assents and declares the non-conformance rather than negotiating an
|
||||
exemption.** `VaultCA` is recorded in `INTENT.md` as a declared §5 exception with a
|
||||
named intended owner (`secrets-engine`), a blocker (no SSH-CA engine surface), and a
|
||||
review date. That is `ADR-0003` — cover gaps, never silently own them — applied to
|
||||
ops-warden itself instead of to someone else's lane.
|
||||
|
||||
### Proposed amendment to the standard
|
||||
|
||||
§5 has exactly one shape for a Staff repository that legitimately touches Tooling:
|
||||
read-only diagnostics. That shape is too narrow to describe the estate as it exists,
|
||||
and a rule with no lane for a real, sanctioned case gets satisfied by relabelling
|
||||
rather than by closing the gap.
|
||||
|
||||
Recommend §5 gain a second shape: a **declared engine gap** — a Staff repository MAY
|
||||
hold a Tooling client for a capability no engine exposes, provided it is declared in
|
||||
`INTENT.md` with an intended owner, the blocker, and a review date, and provided the
|
||||
declaration is machine-readable so the conformance check in §10 can distinguish a
|
||||
tracked gap from an undeclared violation.
|
||||
|
||||
ops-warden already runs this machinery for other repositories' lanes: 27 catalog
|
||||
entries carry `delegation:` with `intended_owner` and `blocked_on`, and
|
||||
`warden route gaps` lists them (WP-0030). It is offered, not imposed — the standard
|
||||
is gate-house's.
|
||||
|
||||
---
|
||||
|
||||
## Item 2 — Doctrine versus runbook
|
||||
|
||||
**Assent.** The `NetKingdom Security Literacy` section is what gate-house says it is:
|
||||
evidence that the curriculum had no owner, so it accreted in whatever `INTENT.md`
|
||||
was open. That is the same failure `risk-nexus` names for findings and the same one
|
||||
`ADR-0001` prevents for catalog procedure. ops-warden has argued this rule twice
|
||||
against other repositories; it applies here.
|
||||
|
||||
The boundary, drawn precisely:
|
||||
|
||||
| Moves to gate-house | Stays with ops-warden |
|
||||
| --- | --- |
|
||||
| Why the planes are separated; the authority model | Which subsystem owns which credential need |
|
||||
| What "posture", "zone", "authority ceiling" mean | How to obtain a cert, a lease, a login — per lane |
|
||||
| The security curriculum a worker is taught | The runbook a worker executes |
|
||||
| Doctrine a lane must conform to | Evidence of conformance for ops-warden's lanes |
|
||||
|
||||
**gate-house's test question, answered: no, it does not leave ops-warden unable to
|
||||
instruct its workers — and the reason is worth recording.** What actually instructs
|
||||
an ops-warden worker is not the prose in `INTENT.md`. It is `warden plan "<need>"`,
|
||||
`warden route find`, and `.claude/rules/credential-routing.md`, which is inlined into
|
||||
every repository's agent instructions precisely because credential routing is
|
||||
high-frequency and high-risk. That surface is executable, lane-specific, and
|
||||
unambiguously runbook. It does not depend on the literacy table, and moving doctrine
|
||||
out does not weaken it.
|
||||
|
||||
If anything the move improves it: the literacy table has been a second, prose copy of
|
||||
what `registry/routing/catalog.yaml` states machine-readably, which is the
|
||||
double-source failure `ADR-0001` exists to stop.
|
||||
|
||||
**One thing must not move with it.** `.claude/rules/credential-routing.md` stays
|
||||
inline in this repository and in every other. It is not doctrine and not a
|
||||
curriculum; it is the anti-pattern list an agent needs *before* it acts, and a
|
||||
reference to a document in another repository would not be read in time.
|
||||
|
||||
---
|
||||
|
||||
## Item 3 — Access lane versus access rule
|
||||
|
||||
**Assent, unconditionally, and the veto on `access-engine` is not exercised.**
|
||||
|
||||
ops-warden is already built this way. `ADR-0005` implements one lane narrowly and
|
||||
routes everything else; `ADR-0002` makes it a conduit that never decides; `ADR-0009`
|
||||
has ops-warden compile membership attributes and apply a zone's failure mode while
|
||||
flex-auth owns the stance. ops-warden consumes decisions; it has never rendered one.
|
||||
The demarcation costs nothing because it describes what is already true.
|
||||
|
||||
`access-engine` is also the better name. ops-warden's own routing table has had to
|
||||
say "authorization" for the decision and "access" for the route for a year, and the
|
||||
collision is visible in every playbook.
|
||||
|
||||
**One operational condition, on execution rather than on the ruling.** The rename is
|
||||
598 references across 82 files in this repository alone — catalog `owner:` fields,
|
||||
`registry/flex-auth/`, `src/warden/policy.py`, the production registry snapshot
|
||||
builder, playbooks, and the `.claude/rules/` files that other repositories inline.
|
||||
Ops-warden asks for a deprecation window in which both names resolve, rather than a
|
||||
flag day; ops-warden will do its own migration inside that window. This is a request
|
||||
about sequencing, not a reservation about the name.
|
||||
|
||||
---
|
||||
|
||||
## Item 4 — gate-house is missing from every table
|
||||
|
||||
Correct, and fixed in this pass. gate-house is added to the literacy/routing table
|
||||
in `INTENT.md` as the owner of doctrine, invariants, authority context, and
|
||||
conformance review — with the routing rule stated explicitly: **doctrine and
|
||||
authority-model questions go to gate-house; policy decisions continue to go to
|
||||
access-engine.** Those are different questions and the distinction is the whole
|
||||
point of §6.
|
||||
|
||||
---
|
||||
|
||||
## Recorded as
|
||||
|
||||
- `ADR-0010` — ops-warden is Staff; lanes not rules; the declared §5 exception
|
||||
- `INTENT.md` — layer declaration, reworked routing table, gate-house row
|
||||
- `WARDEN-IN-0001` — closed, outcome `assented`
|
||||
136
history/2026-08-29-layer-model-v04-review.md
Normal file
136
history/2026-08-29-layer-model-v04-review.md
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
# Security Layer Model v0.4 — ops-warden's review
|
||||
|
||||
**Date:** 2026-08-29
|
||||
**Reviewed:** `net-kingdom/canon/standards/security-layer-model_v0.4.md` (accepted)
|
||||
**Prior position:** `ADR-0010`, assent to v0.1 (`WARDEN-IN-0001`)
|
||||
**Outcome:** no objection to the ruling; three findings, one of them against ops-warden.
|
||||
|
||||
---
|
||||
|
||||
## What v0.4 did with ops-warden's amendment
|
||||
|
||||
Both §5 asks from `ADR-0010` were adopted.
|
||||
|
||||
**§5.3 declared engine gap** is the amendment ops-warden offered, adopted with the
|
||||
four fields intact (`capability`, `intended_owner`, `blocked_on`, `review`), the
|
||||
rationale preserved — *a rule offering no lane for a real sanctioned case gets
|
||||
satisfied by relabelling rather than by closing the gap* — and the framing that
|
||||
matters most kept explicit: **a declared gap is tracked non-conformance, not
|
||||
conformance**. ops-warden's delegation machinery is cited as prior art.
|
||||
|
||||
**§5.2 conduit** resolves the question ops-warden flagged rather than assumed. The
|
||||
test is the supplied-authority property, which is the right test: it turns on what
|
||||
the repository presents, not on what it touches. *"A conduit that presents its own
|
||||
token is not a conduit"* is a sharper statement of `ADR-0002` than `ADR-0002` makes.
|
||||
|
||||
**This created an obligation ops-warden had not met.** §5.3 requires the fields
|
||||
*machine-readably* and §11 makes the mapping a mechanical check; ops-warden's
|
||||
declaration was prose in `INTENT.md`. Fixed in this pass: `layer.yaml`,
|
||||
`scripts/check_layer_conformance.py`, `tests/test_layer_conformance.py`. The
|
||||
checker found three undeclared modules on first run, all false positives — help
|
||||
text, a docstring, and the doubles library that *simulates* `bao` — which is why
|
||||
it now matches invocation shapes rather than the word.
|
||||
|
||||
---
|
||||
|
||||
## Finding 1 — §9.1 and §5.3 disagree, and ops-warden's §4 row is the instance
|
||||
|
||||
§9.1: *a Staff repository MUST NOT be catalogued in §4 as owning a capability that
|
||||
requires a Tooling contact no engine exposes*; where intended but unbuilt, the
|
||||
entry **MUST be marked pending** and the gap declared under §5.3.
|
||||
|
||||
ops-warden's §4 row reads `operational access lanes, stewardship, runbooks; SSH
|
||||
certificate issuance` — with no pending mark. And §13 lists *SSH-CA signing write
|
||||
(`VaultCA`, `bao kv put`) — declared by ops-warden — intended owner secrets-engine*.
|
||||
|
||||
So the catalog asserts ownership of a capability that requires a Tooling contact no
|
||||
engine exposes, unmarked. By §9.1's own text that is a defect. But the available
|
||||
fix is worse than the defect: **marking it pending would be false.** SSH issuance is
|
||||
production-verified and in daily use. `pending` would tell a reader ops-warden does
|
||||
not yet do the one thing it demonstrably does.
|
||||
|
||||
The root cause is that §9.1 collapses two different states:
|
||||
|
||||
| State | Example | Capability today |
|
||||
| --- | --- | --- |
|
||||
| No route exists at all | kings-guard containment (§9.2) | **zero** |
|
||||
| Route exists via a declared §5.3 gap | ops-warden SSH issuance | **working, tracked** |
|
||||
|
||||
§5.3 exists precisely to sanction the second. §9.1 was written for the first — it
|
||||
was raised by kings-guard, about containment, and correctly fixed *for that case*.
|
||||
Applied to the adjacent case it produces a false catalog.
|
||||
|
||||
**Recommendation:** give §9.1 two marks rather than one — `pending` where no route
|
||||
exists, and `declared-gap` where the capability is discharged under §5.3 and
|
||||
registered in §13. Both are honest; today's binary forces a choice between a false
|
||||
label and an unmarked violation.
|
||||
|
||||
This is the §12 loop working as designed, and §12 already says so: a finding that a
|
||||
rule is unsatisfiable is a success of the loop.
|
||||
|
||||
---
|
||||
|
||||
## Finding 2 — §5's scope is undefined for infrastructure §4 does not catalogue
|
||||
|
||||
§5 forbids *a direct client for a Tooling-layer system*. §4 catalogues the security
|
||||
estate, and only `key-cape` and `OpenBao` are Tooling rows.
|
||||
|
||||
ops-warden holds an HTTP client for the **State Hub** and for **llm-connect**
|
||||
(`src/warden/worker.py`). Neither appears in §4. Both are infrastructure a Staff
|
||||
repository holds a direct client for.
|
||||
|
||||
The question is not rhetorical, because the answers diverge sharply:
|
||||
|
||||
- **If they are Tooling**, then every Staff repository in the estate is in
|
||||
undeclared violation on adoption day — they all write progress events — and
|
||||
§11's second mechanical check fails estate-wide.
|
||||
- **If they are not**, §5 should say so, because *"a Tooling-layer system"* reads
|
||||
considerably broader than *"a repository in the §4 Tooling rows"*.
|
||||
|
||||
ops-warden has recorded both under `non_tooling_clients` in `layer.yaml` with the
|
||||
reasoning stated, rather than resolving it unilaterally. The scope is gate-house's
|
||||
to set.
|
||||
|
||||
---
|
||||
|
||||
## Finding 3 — §9.6 lands on ops-warden, and ops-warden does not satisfy it
|
||||
|
||||
This is the one against us, and it is the most consequential item in the review.
|
||||
|
||||
§9.6 consequence 1: *any system whose evidence is load-bearing MUST make emission
|
||||
atomic with the state change it records. An archive cannot retrofit completeness.*
|
||||
|
||||
**ops-warden's audit emission is deliberately non-atomic.** `src/warden/ca.py:90`
|
||||
carries `pass # audit must not block signing`, and `wiki/AuditTrail.md` states the
|
||||
trail *"never blocks the primary action"*. If the audit append fails, the
|
||||
certificate is still issued and the event is simply lost — a suppressed event that
|
||||
leaves the chain perfectly intact, which is the exact failure §9.6 describes.
|
||||
|
||||
That was a considered availability choice: an audit-disk problem should not remove
|
||||
production host access. §9.6 now makes it a conformance question, and the trade is
|
||||
real in both directions:
|
||||
|
||||
- make emission atomic → an audit write failure fails the sign, and the estate's
|
||||
operational access lane acquires a new dependency on its own evidence store;
|
||||
- leave it → signing evidence cannot be treated as complete, and anything reasoning
|
||||
from *"there is no record of a sign"* is unsound.
|
||||
|
||||
**ops-warden has not changed it, and is not going to decide this alone** — §9.6 is
|
||||
estate doctrine and the question is whether SSH signing evidence is load-bearing in
|
||||
gate-house's sense. What ops-warden can say is that the second horn is currently
|
||||
true and undocumented: `wiki/AuditTrail.md` does not warn that absence of a record
|
||||
is not evidence of absence. That correction is ops-warden's regardless of the
|
||||
ruling, and is the smaller half of the fix.
|
||||
|
||||
Note also that §5.2 requires a conduit action to be *"reconstructable as the
|
||||
caller's action in audit"* — an audit-dependent claim, and therefore bounded by
|
||||
§9.6. Worth a cross-reference so the two rules do not drift apart.
|
||||
|
||||
---
|
||||
|
||||
## Offered
|
||||
|
||||
`layer.yaml` + `check_layer_conformance.py` + `test_layer_conformance.py` is a
|
||||
working reference implementation of §5.3 and of §11's second mechanical check. Eight
|
||||
of fifteen estate repositories have yet to declare (§14). If it is useful as a
|
||||
pattern to point them at, it is offered — as the delegation machinery was.
|
||||
156
history/2026-08-29-layer-model-v06-review.md
Normal file
156
history/2026-08-29-layer-model-v06-review.md
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# Security Layer Model v0.6 — ops-warden's review
|
||||
|
||||
**Date:** 2026-08-29
|
||||
**Reviewed:** `security-layer-model_v0.6.md` (proposed), plus v0.5 and the companion
|
||||
**Prior positions:** `ADR-0010` (v0.1 assent); `history/2026-08-29-layer-model-v04-review.md`
|
||||
**Outcome:** no objection; one conformance action taken, two findings, one accepted SHOULD.
|
||||
|
||||
---
|
||||
|
||||
## Disposition of ops-warden's v0.4 findings
|
||||
|
||||
All three were acted on, two of them exactly as recommended.
|
||||
|
||||
| Finding | Outcome |
|
||||
| --- | --- |
|
||||
| §9.1 forces a false `pending` onto working capability | **Adopted** — v0.5 split it into `pending` and `declared-gap`, credited to ops-warden |
|
||||
| §5 scope undefined for uncatalogued infrastructure | **Adopted** — "Tooling-layer system" now means a §4 Tooling row; the State Hub case is recorded, not policed |
|
||||
| §9.6 atomicity lands on ops-warden's signing lane | **Ruled** — the load-bearing / attributive distinction, with ops-warden's `# audit must not block signing` named as the estate's live example |
|
||||
|
||||
The §9.6 ruling deserves a note, because it went in ops-warden's favour and that is
|
||||
a reason to check it rather than accept it. The test is *"no control branches on
|
||||
its presence"*. Verified: the only consumer of `audit.jsonl` is `warden activity`
|
||||
(`cli.py`), which displays. Nothing gates on a signing record — not the agent
|
||||
read-boundary, not `warden plan`, not the scorecard. The lane is genuinely
|
||||
attributive and the trade is legitimate on the standard's own terms. The two
|
||||
obligations that attach — declare it, never claim completeness — were already met
|
||||
in `wiki/AuditTrail.md`, now updated to record the ruling rather than the open
|
||||
question. **If a future ops-warden control ever gates on this trail, the trade has
|
||||
to be revisited before that ships**, and that is recorded there.
|
||||
|
||||
`layer.yaml` is named in §11 as the estate's reference declaration form, including
|
||||
the "record non-Tooling clients so the check is total" property. Offered again to
|
||||
the repositories that have yet to declare.
|
||||
|
||||
---
|
||||
|
||||
## Conformance action taken — the stance map was not published
|
||||
|
||||
§6.4 obligation 3 requires a declared unreachable-engine stance that is total, per
|
||||
zone, with no implicit default, *"published rather than held in code comments"* —
|
||||
and §6.4 requires **every** PEP-shaped consumer to publish its map so the maps can
|
||||
be inventoried. `ADR-0009` is named as the reference shape.
|
||||
|
||||
ops-warden was not doing this. The map lived in `PolicyConfig.failure_modes`, a
|
||||
dataclass default in `src/warden/config.py`. That is not a code *comment*, but it
|
||||
is not published either — it is merely written down, and a consumer of the estate
|
||||
had no way to read ops-warden's stance without reading ops-warden's source.
|
||||
|
||||
Published as `pep-stance.yaml`, with the property that makes publishing worth
|
||||
anything: `tests/test_layer_conformance.py` asserts the published map is **equal to
|
||||
the shipped default**. A published map that may drift from the code is worse than
|
||||
no map, because it invites reliance it cannot support. The file also records the
|
||||
obligation-2 position (verdict never cached; input claims cached under their own
|
||||
freshness rules) and the obligation-4 bound (§9.6 attributive).
|
||||
|
||||
---
|
||||
|
||||
## Finding 1 — §6.4 obligation 1 contradicts obligation 3, and ops-warden is the instance
|
||||
|
||||
> **1. No side effect without a decision record.** A PEP MUST NOT perform the
|
||||
> protected action unless it holds a decision from `access-engine` identifying the
|
||||
> request it was rendered for.
|
||||
|
||||
> **3. A declared unreachable-engine stance (§9.3):** total, per zone... `ops-warden`
|
||||
> `ADR-0009` is the reference shape.
|
||||
|
||||
These cannot both be absolute. ops-warden's declared stance — blessed by §9.3 as
|
||||
*"the only thing left"* when there is no engine to ask — is `fail_open` for `z0`–`z2`
|
||||
and `unknown`. Applying it means issuing a certificate **without holding a
|
||||
decision**, which obligation 1 forbids without qualification.
|
||||
|
||||
So the same section names ops-warden as the reference shape for obligation 3 while
|
||||
obligation 1 makes ops-warden's shipped behaviour a violation. §9.3 settled the
|
||||
substance; §6.4 restates it in a form that takes it back.
|
||||
|
||||
**Recommendation.** Bound obligation 1 by obligation 3:
|
||||
|
||||
> A PEP MUST NOT perform the protected action unless it holds a decision from
|
||||
> `access-engine` identifying the request it was rendered for, **or its declared
|
||||
> §9.3 stance for the applicable scope permits proceeding without one and the
|
||||
> application of that stance is recorded in place of the decision**.
|
||||
|
||||
This is not a weakening. It is stricter than today's text in the case that matters:
|
||||
it makes the *recorded application of the stance* mandatory, rather than leaving
|
||||
"no decision record" as a silent state. ops-warden already does this — `ca.py`
|
||||
writes `policy_zone`, `policy_failure_mode` and `policy_decision_id` (present only
|
||||
where a decision was rendered) into both the signatures log and `audit.jsonl`, per
|
||||
`ADR-0009` rule 4: *a fail-open signing result is metadata, not silence*.
|
||||
|
||||
This is the same shape as the v0.4 §9.1 finding: a rule written for the clean case,
|
||||
correct there, producing a false result on the adjacent case the standard has
|
||||
already sanctioned elsewhere.
|
||||
|
||||
---
|
||||
|
||||
## Finding 2 — §6.4 creates a register that §13 does not implement
|
||||
|
||||
§6.4: *"Every PEP-shaped consumer MUST publish its stance map, and those maps MUST
|
||||
be inventoried — in `maturity-engine` once it exists, **in §13 until then**."*
|
||||
|
||||
§13 contains no stance-map rows. It records declared contacts and unowned
|
||||
capabilities; there is no column, row, or section for a PEP stance. So the
|
||||
obligation names a register that does not exist yet, and the failure mode §6.4
|
||||
itself warns about — *"`z0`–`z2` and unknown fail open" becoming the estate's real
|
||||
policy without anyone having compiled it* — is exactly what the missing register
|
||||
permits.
|
||||
|
||||
**Recommendation.** Either add a stance-map table to §13 with the same
|
||||
state/owner-status discipline the gap table has, or state that the inventory waits
|
||||
for `maturity-engine` and mark the obligation pending under §9.1's own logic — a
|
||||
requirement whose register does not exist is a capability catalogued without a
|
||||
surface. ops-warden's row is ready to paste:
|
||||
|
||||
| PEP | Protected action | Scope | Stance | Published |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `ops-warden` | SSH certificate issuance | security-zone | open `z0`–`z2`+unknown, closed `z3`/n-a | `ops-warden/pep-stance.yaml` |
|
||||
|
||||
The second half matters more than the first: **ops-warden is currently the only
|
||||
PEP that has published one**, so an inventory today would contain one row and that
|
||||
is itself the finding. `ops-mason` is named PEP-shaped in the same paragraph.
|
||||
|
||||
---
|
||||
|
||||
## Accepted, not yet done — §9.6 emission cadence
|
||||
|
||||
§9.6: *"A source SHOULD declare an expected emission cadence, and a drop below it
|
||||
SHOULD become a finding in its own right."*
|
||||
|
||||
ops-warden declares none. This is a genuine SHOULD and the reasoning behind it is
|
||||
sound — it converts the suppression blind spot into something detectable without
|
||||
any Tooling contact, because the source publishes its own stream. It is not done
|
||||
here because a cadence asserted without evidence is worse than none: ops-warden's
|
||||
signing volume is operator-driven and bursty, and a fabricated baseline would
|
||||
generate findings that mean nothing. Deriving one from the existing trail is
|
||||
tractable and is recorded as ops-warden's to do, not gate-house's to chase.
|
||||
|
||||
---
|
||||
|
||||
## On the pace
|
||||
|
||||
Six versions in two days, with four repositories' findings absorbed and credited,
|
||||
is the §12 loop working at a rate the estate has not seen before. Two cautions,
|
||||
offered as an interested consumer rather than as objections:
|
||||
|
||||
1. **§13 already says it should not be statute, and it is right.** The register has
|
||||
grown every version. Moving it to `maturity-engine` is the stated plan; until
|
||||
that exists, each version of the standard is also a snapshot of a backlog, and
|
||||
the two have very different review intervals.
|
||||
2. **The standard is `proposed` again at v0.6**, and the four repositories that
|
||||
assented did so to v0.1. ops-warden's `ADR-0010` assent covers the three
|
||||
boundary items, and nothing in v0.2–v0.6 has disturbed them — the layer, the
|
||||
lane/rule demarcation, and doctrine-versus-runbook all stand. But the
|
||||
`assented_by` list carries assent forward across five revisions, and a reader
|
||||
could take it as assent to the current text. Worth distinguishing *assented to
|
||||
the boundary* from *reviewed the current revision*; ops-warden has now done
|
||||
both, and this note is the second.
|
||||
157
history/2026-08-29-v07-scope-intent-assessment.md
Normal file
157
history/2026-08-29-v07-scope-intent-assessment.md
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
# v0.7 conformance — INTENT vs SCOPE gap assessment
|
||||
|
||||
**Date:** 2026-08-29
|
||||
**Standard:** `security-layer-model_v0.7.md` (**accepted**) + `SECURITY-COMPANION.md` v0.2
|
||||
**Prior:** `ADR-0010`; v0.4 and v0.6 reviews in `history/`
|
||||
**Method:** each v0.7 obligation checked against shipped code, not against intent.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
ops-warden is **conformant on every obligation it can discharge alone except three**,
|
||||
and holds two declared §5.3 gaps that are tracked, registered and owned elsewhere.
|
||||
The three genuine gaps are §9.7.2 (no stated revocation visibility deadline — a MUST),
|
||||
§3.4 rule 1 (the agent read-boundary keys on an honour-system marker rather than an
|
||||
issued identity), and §9.6's cadence, which is a SHOULD for an attributive source and
|
||||
remains undone for an honest reason.
|
||||
|
||||
One new obligation is not a rule at all but a role: the companion routes the entire
|
||||
estate to ops-warden for *how to get something done*. Nothing in the repo answers a
|
||||
layer or declaration question today, and that is now a discoverability gap.
|
||||
|
||||
Four ops-warden findings were adopted into the standard between v0.4 and v0.7 — §9.1's
|
||||
two marks, §5's Tooling scope rule, §6.4 obligation 1's second limb, and §13.1's
|
||||
existence. That is the conformance loop working; it is not a reason to assume the next
|
||||
pass finds nothing.
|
||||
|
||||
---
|
||||
|
||||
## Obligation-by-obligation
|
||||
|
||||
### Conformant, shipped, evidenced
|
||||
|
||||
| Obligation | Evidence |
|
||||
| --- | --- |
|
||||
| §11 declare layer in own voice, machine-readably | `INTENT.md` frontmatter (`layer: Staff`, `pep_shaped: true`) + `layer.yaml` — cited in §11 as the estate's reference form |
|
||||
| §5 every Tooling contact maps to a shape; non-Tooling recorded so the check is total | `layer.yaml` 5 contacts + 2 exclusions; `scripts/check_layer_conformance.py` |
|
||||
| §5.2 conduit supplies no authority | `proxy.py::_caller_env`; `tests/test_layer_conformance.py::test_conduit_supplies_no_authority_of_its_own` |
|
||||
| §6.4 obl. 1 no side effect without a decision **or a recorded stance** | `ca.py` writes `policy_zone`, `policy_failure_mode`, `policy_decision_id` (present only where rendered). ops-warden is the named reference for limb two |
|
||||
| §6.4 obl. 2 no verdict recaching | `policy.py` caches nothing — verified by inspection, not by claim |
|
||||
| §6.4 obl. 3 stance map published, at a path named in the declaration, equal to shipped behaviour, asserted by test | `pep-stance.yaml`, named in `layer.yaml`; test asserts equality with `PolicyConfig().failure_modes`; registered in statute §13.1 |
|
||||
| §9.3 stance total, per zone, no implicit default | 7 rows covering every zone plus `unknown` and `not-applicable` |
|
||||
| §9.6 evidence claims bounded | `wiki/AuditTrail.md` declares the attributive trade and states absence is not evidence of absence |
|
||||
| §9.7.1 every allow has an explicit lifetime | TTL enforced per `ActorType` — `adm` 48h, `agt` 24h, `atm` 8h |
|
||||
| §3.4 rule 2 tool use is a conduit or engine API | `warden access` is the conduit; `ADR-0004` enforces that tool availability is not permission |
|
||||
|
||||
### Declared gaps — tracked non-conformance, owned elsewhere
|
||||
|
||||
Both registered in statute §13, intended owner `secrets-engine`, reviewed quarterly.
|
||||
Neither is closable by ops-warden: closing them means another repository shipping a
|
||||
surface.
|
||||
|
||||
- **`VaultCA` signing write** — no engine exposes SSH-CA signing.
|
||||
- **`warden desk` `bao kv put`** — no engine exposes attended provisioning.
|
||||
|
||||
Nothing in v0.7 changes their status. The right ops-warden behaviour is to keep them
|
||||
declared, keep the review dates honest, and not quietly grow a third.
|
||||
|
||||
---
|
||||
|
||||
## The three real gaps
|
||||
|
||||
### G1 — §9.7.2: no stated revocation visibility deadline (MUST)
|
||||
|
||||
> *A **PEP** has one boundary and MUST state one deadline… an unstated deadline is
|
||||
> an unbounded replay window.*
|
||||
|
||||
ops-warden states none, and the honest answer is uncomfortable: **the effective
|
||||
window is the certificate TTL — up to 48 hours.** A certificate issued under an allow
|
||||
stays valid for its full TTL even if the decision that authorized it is revoked or
|
||||
superseded the next minute. ops-warden has no revocation channel for an issued cert:
|
||||
there is no CRL, no KRL distribution, and host-side `auth_principals` is
|
||||
`railiance-infra`'s.
|
||||
|
||||
This is not a documentation gap. It is a design property that has never been written
|
||||
down, and §9.7.2 exists precisely to force it into the open. Two things follow:
|
||||
|
||||
1. The deadline must be **stated** — `adm` 48h / `agt` 24h / `atm` 8h — in
|
||||
`pep-stance.yaml`, as what it is rather than as an aspiration.
|
||||
2. Whether 48h is *acceptable* is a separate question, and it is partly
|
||||
`railiance-infra`'s (KRL distribution) and partly ours (TTL policy). Stating it is
|
||||
ours and is cheap; shortening it is a joint change.
|
||||
|
||||
Stating a bad number is better than stating none: an unstated deadline is an
|
||||
unbounded replay window, and this one is bounded and already implemented.
|
||||
|
||||
### G2 — §3.4 rule 1: the agent boundary rests on an honour-system marker
|
||||
|
||||
> *No standing credential. Authority is issued per task, time-bounded under §9.7,
|
||||
> and attributable to the principal on whose behalf it acts.*
|
||||
|
||||
`ADR-0004`'s read-boundary triggers when `WARDEN_AGENT_ID` is set — an environment
|
||||
variable the agent sets **about itself**. An agent that does not set it is not
|
||||
recognised as an agent. ops-warden has known this (`WARDEN-WP-0033-T04` recorded it
|
||||
as "an honour-system marker on the ops-warden side"), and it was tolerable while no
|
||||
issued agent identity existed.
|
||||
|
||||
One now does. `key-cape` accepted issuance ownership in `KEY-WP-0009-T03`:
|
||||
`codex-railiance-platform`, subject `service:codex:railiance-platform`, role
|
||||
`coding-agent`, scope `openbao:login`, 15-minute lifetime. The OpenBao side is
|
||||
enforced by `railiance-platform`'s policy, which is the half that actually holds.
|
||||
|
||||
So the gap is narrower than it looks and worth stating precisely: **the OpenBao-side
|
||||
boundary is real; the ops-warden-side boundary is advisory.** ops-warden should key
|
||||
its read-boundary on the issued identity where one is present, and treat
|
||||
`WARDEN_AGENT_ID` as a fallback that fails *toward* the boundary rather than away
|
||||
from it. That is a change in this repo and does not need another repo to move.
|
||||
|
||||
### G3 — §9.6 emission cadence (SHOULD, for an attributive source)
|
||||
|
||||
Unchanged from the v0.6 review and still honest: ops-warden declares no expected
|
||||
cadence because its signing volume is operator-driven and bursty, and a fabricated
|
||||
baseline generates findings that mean nothing. v0.7 makes cadence a **MUST for
|
||||
load-bearing sources**; ops-warden's trail is attributive, so it remains a SHOULD.
|
||||
|
||||
Deriving a real baseline from the existing trail is tractable and is ops-warden's to
|
||||
do. It should be derived and declared, or explicitly deferred with a reason — not
|
||||
left silent, which is what it is today.
|
||||
|
||||
---
|
||||
|
||||
## The role the companion assigns, and what it costs
|
||||
|
||||
> *"For how to get something done in NetKingdom — which lane, which credential, which
|
||||
> route — ask `ops-warden`. This document says what the rules are; ops-warden stewards
|
||||
> the paths through them."*
|
||||
|
||||
This is the largest change in ops-warden's INTENT surface and it is not a rule, so it
|
||||
does not appear in any conformance check. The estate has been told to come here.
|
||||
|
||||
**Today the repo answers credential questions and no others.** `warden route` and
|
||||
`warden plan` cover lanes, owners and acts. Nothing answers *"which layer am I"*,
|
||||
*"how do I declare"*, *"I am PEP-shaped, what do I owe"* — the questions the companion
|
||||
and the standard's adoption status (eight of fifteen repositories undeclared) actually
|
||||
generate.
|
||||
|
||||
ops-warden has already built the reference artifacts those repositories need, and the
|
||||
standard points at them by name in §11 and §6.4. What is missing is the path: a
|
||||
discoverable route from *"I read the companion"* to *"here is the file to copy and the
|
||||
check to run"*. That is exactly the stewardship ops-warden claims, applied to the
|
||||
estate's newest rule rather than to its credential lanes.
|
||||
|
||||
Also worth noting, and not ops-warden's to fix: §13.1's register has one row, and
|
||||
`ops-mason` — catalogued PEP-shaped in the same paragraph — has published nothing.
|
||||
The standard says one row is itself the finding.
|
||||
|
||||
---
|
||||
|
||||
## What does not need doing
|
||||
|
||||
- **No new ADR.** `ADR-0010` holds: Staff, lanes not rules, declared gaps not
|
||||
exemptions. v0.2–v0.7 refined the rules around it and disturbed none of its three
|
||||
positions. The reviews extend it; a superseding record would add ceremony without
|
||||
changing a decision.
|
||||
- **No change to the two §5.3 gaps.** They are correctly declared and owned elsewhere.
|
||||
- **No re-assent.** ops-warden assented to the boundary in `ADR-0010` and has now
|
||||
reviewed three revisions on their merits, which is the stronger position.
|
||||
93
intakes/intakes.md
Normal file
93
intakes/intakes.md
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# Intake records
|
||||
|
||||
## WARDEN-IN-0001 — Assent requested: Staff layer, doctrine vs runbook, and the access lane/rule demarcation
|
||||
|
||||
```yaml
|
||||
id: WARDEN-IN-0001
|
||||
kind: intake
|
||||
title: 'Assent requested: Staff layer, doctrine vs runbook, and the access lane/rule
|
||||
demarcation'
|
||||
status: closed
|
||||
outcome: assented
|
||||
origin: cross-repo
|
||||
origin_ref: gate-house GH-DEC-2026-001
|
||||
priority: medium
|
||||
owner: ops-warden
|
||||
requested_by: gate-house
|
||||
standard: net-kingdom/canon/standards/security-layer-model_v0.1.md
|
||||
description: 'gate-house asks ops-warden to assent to three boundary items. (1) ops-warden
|
||||
is Staff, bound by the rule that Staff acts only through Engine APIs and never touches
|
||||
Tooling directly (standard section 5). (2) Doctrine versus runbook: the NetKingdom
|
||||
Security Literacy section in ops-warden INTENT is evidence the security curriculum
|
||||
had no owner; it now has one in gate-house. Proposal is that doctrine and curriculum
|
||||
move to gate-house and that section becomes lane-specific runbooks referencing gate-house
|
||||
doctrine rather than restating it. ops-warden keeps the lanes it stewards and everything
|
||||
operational about them. (3) The access lane/rule demarcation, normative in standard
|
||||
section 8: ops-warden and ops-mason own access lanes — how a worker reaches a host;
|
||||
access-engine owns access rules — whether they may. This demarcation is the condition
|
||||
attached to renaming flex-auth to access-engine, so ops-warden effectively holds
|
||||
a veto on that name. Also requested: add gate-house to the Security Literacy and
|
||||
routing tables — currently every plane is listed and gate-house appears nowhere
|
||||
— routing doctrine and authority-model questions there while continuing to route
|
||||
policy decisions to access-engine. If moving the curriculum out leaves ops-warden
|
||||
unable to instruct its own workers, say so; the boundary is wrong if it does.'
|
||||
notes: 'Assented to all three items in ADR-0010, with reasoning in
|
||||
history/2026-08-28-security-layer-model-assent.md. (1) Staff accepted; the section 5
|
||||
binding rule exposed a real non-conformance — src/warden/vault.py is a direct
|
||||
OpenBao client performing a write, as is warden desk''s bao kv put. Declared in
|
||||
INTENT.md as an engine gap with intended owner secrets-engine and blocker "no engine
|
||||
exposes an SSH-CA surface", not negotiated as an exemption; taint.py declared under
|
||||
the read-only allowance; warden access proxies run under the caller''s identity.
|
||||
An amendment is offered back to gate-house: a second sanctioned shape in section 5 for
|
||||
a declared engine gap carrying intended owner, blocker and review date, machine-readable
|
||||
so section 10 can tell a tracked gap from an undeclared violation. (2) Doctrine versus
|
||||
runbook accepted; the literacy section is now a lane routing runbook referencing
|
||||
gate-house doctrine. Answering gate-house''s test question: it does not leave ops-warden
|
||||
unable to instruct its workers, because what instructs them is warden plan / warden route
|
||||
and .claude/rules/credential-routing.md, which stays inline by design. (3) The lane/rule
|
||||
demarcation assented unconditionally and the access-engine veto not exercised — ops-warden
|
||||
already consumes decisions and renders none. One request on sequencing only: a deprecation
|
||||
window in which both names resolve (598 references across 82 files here). gate-house added
|
||||
to the routing tables in INTENT.md and SCOPE.md.'
|
||||
created: '2026-08-28T19:30:28.087109Z'
|
||||
updated: '2026-08-28T21:05:00Z'
|
||||
state_hub_intake_id: "01a049ed-bbbc-7520-bc7c-6b0912ca534a"
|
||||
```
|
||||
|
||||
## WARDEN-IN-0002 — Review requested: security layer model v0.3 — and does maturity-engine absorb warden route gaps?
|
||||
|
||||
```yaml
|
||||
id: WARDEN-IN-0002
|
||||
kind: intake
|
||||
title: 'Review requested: security layer model v0.3 — and does maturity-engine absorb
|
||||
warden route gaps?'
|
||||
status: open
|
||||
origin: cross-repo
|
||||
origin_ref: net-kingdom security-layer-model_v0.3
|
||||
priority: medium
|
||||
owner: ops-warden
|
||||
requested_by: gate-house
|
||||
description: 'v0.3 is proposed and changes sections 4, 9 and 13 only; the v0.2 assent
|
||||
record stands. Two new engines: approval-engine (section 9.4) and maturity-engine
|
||||
(section 9.5). THE QUESTION FOR YOU concerns section 5.3, which exists because you
|
||||
offered the amendment. v0.3 gives declared gaps an owner: maturity-engine takes
|
||||
the gap register with intended_owner, blocked_on and review dates, and section 13
|
||||
now says the register in the standard is interim and should not outlive that engine.
|
||||
You offered warden route gaps and the 27 delegation catalog entries as reusable
|
||||
prior art. So the question is whether that machinery should MOVE, be MIRRORED, or
|
||||
STAY. Our tentative reading, which we want tested rather than accepted: routing
|
||||
is yours and stays yours — warden route find answers where a credential need goes,
|
||||
and that is lane knowledge, not maturity. What might move is the readiness half:
|
||||
whether a declared gap is still within its review date, and whether an intended
|
||||
owner has an engine surface yet. If splitting those creates two sources for one
|
||||
fact, that is worse than either option and we would rather hear it now. Your SSH-CA
|
||||
signing write would be tracked in maturity-engine as a declared gap with intended
|
||||
owner secrets-engine and a review date — that is reporting your own non-conformance
|
||||
to an engine, so we would rather you assent to it than discover it. Also note approval-engine
|
||||
(section 9.4): it owns the approval object, not the approval workflow, so ops-warden
|
||||
lanes needing approval consume a claim rather than implementing one. Assent, revision,
|
||||
or rejection acceptable.'
|
||||
created: '2026-08-28T20:40:24.957468Z'
|
||||
updated: '2026-08-28T20:40:24.957468Z'
|
||||
state_hub_intake_id: "01a04d97-94cd-7b49-8019-a91c7fce8adb"
|
||||
```
|
||||
128
layer.yaml
Normal file
128
layer.yaml
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
# ops-warden — NetKingdom security layer declaration
|
||||
#
|
||||
# Framework: net-kingdom/canon/standards/security-layer-model_v0.4.md
|
||||
# Assent: docs/adr/ADR-0010 (ops-warden's own voice, per §11 "who must declare")
|
||||
# Validate: python3 scripts/check_layer_conformance.py
|
||||
#
|
||||
# §11 makes one check mechanical: "every direct Tooling client in a Staff
|
||||
# repository maps to a declared §5.1, §5.2, or §5.3 entry". This file is that
|
||||
# map. It is machine-readable because §5.3 requires it to be — ops-warden
|
||||
# proposed that shape and is implementing it rather than declaring in prose.
|
||||
#
|
||||
# Conformance rule inherited from tenancy.yaml: accuracy, not altitude. A
|
||||
# declared gap is TRACKED NON-CONFORMANCE (§11), never a claim of conformance.
|
||||
|
||||
schema_version: "0.1"
|
||||
framework: netkingdom-security-layer-model
|
||||
standard_version: "0.4"
|
||||
repository: ops-warden
|
||||
layer: staff
|
||||
declared_by: docs/adr/ADR-0010
|
||||
declared_at: "2026-08-29"
|
||||
|
||||
# §6.4 — ops-warden is PEP-shaped (it causes a protected side effect: issuing a
|
||||
# certificate). Its unreachable-engine stance map is published separately, and
|
||||
# asserted equal to shipped behaviour by tests/test_layer_conformance.py.
|
||||
pep_stance: pep-stance.yaml
|
||||
|
||||
# Every direct contact with a Tooling-layer system (§4), one entry each.
|
||||
tooling_contacts:
|
||||
|
||||
- id: ssh-ca-signing-write
|
||||
shape: "5.3" # declared engine gap
|
||||
module: src/warden/vault.py
|
||||
symbol: VaultCA.sign
|
||||
tooling: OpenBao
|
||||
operation: "HTTP POST <addr>/v1/<mount>/sign/<role> with X-Vault-Token"
|
||||
write: true
|
||||
capability: "Sign a short-lived SSH certificate for an adm/agt/atm actor"
|
||||
intended_owner: secrets-engine
|
||||
blocked_on: >-
|
||||
No engine exposes an SSH certificate signing surface. secrets-engine owns
|
||||
credential abstraction, custody and lifecycle, which is the layer this
|
||||
belongs in, but fronts no SSH-CA API today.
|
||||
review: "2026-11-28"
|
||||
note: >-
|
||||
Production-verified and in daily use. This is the one lane ops-warden owns
|
||||
permanently (§4). Signing continues while the gap is open: refusing would
|
||||
remove production host access to close a documentation gap.
|
||||
|
||||
- id: desk-paste-once-provision
|
||||
shape: "5.3"
|
||||
module: src/warden/desk.py
|
||||
symbol: _provision_to_openbao
|
||||
tooling: OpenBao
|
||||
operation: "bao kv put <path> <field>=- (value on stdin, never argv)"
|
||||
write: true
|
||||
capability: "Founder paste-once provisioning of a secret straight into OpenBao"
|
||||
intended_owner: secrets-engine
|
||||
blocked_on: >-
|
||||
No engine exposes an attended provisioning surface for a value the founder
|
||||
holds and no automated path can produce.
|
||||
review: "2026-11-28"
|
||||
note: >-
|
||||
Attended and founder-operated (WP-0029). The value reaches OpenBao without
|
||||
passing through a terminal, an argv, or the audit log.
|
||||
|
||||
- id: taint-metadata-read
|
||||
shape: "5.1" # read-only diagnostic observation
|
||||
module: src/warden/taint.py
|
||||
symbol: fetch_taint_status
|
||||
tooling: OpenBao
|
||||
operation: "bao kv metadata get -format=json <path>"
|
||||
write: false
|
||||
capability: "Report EXPOSED taint (custom_metadata) without reading secret data"
|
||||
intended_owner: secrets-engine
|
||||
blocked_on: >-
|
||||
No engine exposes a disclosure-taint query. Metadata-only by construction —
|
||||
reading the data would be the 2026-07-16 vector this exists to avoid.
|
||||
review: "2026-11-28"
|
||||
|
||||
- id: access-proxy-conduit
|
||||
shape: "5.2" # conduit
|
||||
module: src/warden/proxy.py
|
||||
symbol: proxy_fetch, proxy_attended_login_exec
|
||||
tooling: OpenBao, key-cape
|
||||
operation: "Runs the catalog-declared owner fetch_command as a child process"
|
||||
write: false
|
||||
capability: "warden access --fetch/--exec/--out/--wrap for exec_capable lanes"
|
||||
supplied_authority: none
|
||||
evidence:
|
||||
no_own_credential: src/warden/proxy.py::_caller_env
|
||||
test: tests/test_proxy.py::test_conduit_supplies_no_authority_of_its_own
|
||||
audit: "audit.jsonl records the caller, the lane, and the outcome; never a value"
|
||||
note: >-
|
||||
The §5.2 test is the supplied-authority property: ops-warden presents no
|
||||
credential of its own, cannot widen what the caller could already do, and
|
||||
the action reconstructs as the caller's. Governed by ADR-0002.
|
||||
|
||||
- id: caller-identity-token
|
||||
shape: "5.2"
|
||||
module: src/warden/caller_identity.py
|
||||
symbol: resolve_caller_token
|
||||
tooling: OpenBao
|
||||
operation: "Runs the operator-configured caller_auth command, or reads token env"
|
||||
write: false
|
||||
capability: "Establish the caller's own identity for the pre-sign policy gate"
|
||||
supplied_authority: none
|
||||
detection: voluntary # runs an operator-configured command, so no fixed
|
||||
# argv shape to scan for; declared rather than omitted
|
||||
note: >-
|
||||
Obtains the CALLER's credential by the operator's configured means; adds no
|
||||
authority. Never mints, and never persists what it resolves.
|
||||
|
||||
# Contacts that are deliberately NOT Tooling contacts, recorded so the check is
|
||||
# total rather than silently selective.
|
||||
non_tooling_clients:
|
||||
|
||||
- module: src/warden/policy.py
|
||||
target: access-engine (flex-auth)
|
||||
rationale: "Engine API — §5 permits it; this is the shape §5 prescribes."
|
||||
|
||||
- module: src/warden/worker.py
|
||||
target: state-hub, llm-connect
|
||||
rationale: >-
|
||||
Not catalogued in §4. The layer catalog scopes the security estate, and
|
||||
neither the State Hub nor llm-connect appears in it, so no §5 shape applies
|
||||
on the standard's own terms. Raised with gate-house 2026-08-29 as a scope
|
||||
question rather than resolved unilaterally — see the assessment note.
|
||||
69
pep-stance.yaml
Normal file
69
pep-stance.yaml
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# ops-warden — PEP unreachable-engine stance map
|
||||
#
|
||||
# Framework: net-kingdom/canon/standards/security-layer-model_v0.6.md §6.4, §9.3
|
||||
# Rule of record: docs/adr/ADR-0009
|
||||
# Validate: pytest tests/test_layer_conformance.py -k stance
|
||||
#
|
||||
# §6.4 obligation 3 requires a declared unreachable-engine stance that is total,
|
||||
# scoped per zone, carries no implicit default and no per-call discretion, and is
|
||||
# "published rather than held in code comments". §6.4 further requires every
|
||||
# PEP-shaped consumer to PUBLISH its map so the maps can be inventoried. This
|
||||
# file is ops-warden's, published because a map that lives only in a dataclass
|
||||
# default is not published — it is merely written down.
|
||||
#
|
||||
# The property that makes this worth reading: it is asserted equal to the shipped
|
||||
# default in src/warden/config.py (PolicyConfig.failure_modes) by
|
||||
# tests/test_layer_conformance.py. A published map that may drift from the code
|
||||
# is worse than none, because it invites reliance it cannot support.
|
||||
|
||||
schema_version: "0.1"
|
||||
framework: netkingdom-security-layer-model
|
||||
standard_version: "0.6"
|
||||
repository: ops-warden
|
||||
pep_shape: true
|
||||
declared_by: docs/adr/ADR-0009
|
||||
|
||||
protected_action: "SSH certificate issuance (warden sign / cert_command)"
|
||||
decision_engine: access-engine # flex-auth until the governed rename
|
||||
scope: security-zone # security-zones_v0.1 membership of the TARGET workload
|
||||
|
||||
# Total by construction: every zone in security-zones_v0.1, plus the two
|
||||
# non-zone outcomes. No implicit default — an unlisted value is a config error,
|
||||
# not a permissive fallback.
|
||||
stance:
|
||||
z0-experimental: fail_open
|
||||
z1-operational: fail_open
|
||||
z2-protected: fail_open
|
||||
z2-continuity: fail_open
|
||||
z3-critical: fail_closed
|
||||
unknown: fail_open # versioned build profile (ADR-0009); explicit, never inferred
|
||||
not-applicable: fail_closed
|
||||
|
||||
# What happens when the stance is applied. §6.4 obligation 1 requires a decision
|
||||
# record for a protected side effect; where the engine is unreachable there is no
|
||||
# decision to hold, so ops-warden records the APPLICATION OF THE STANCE instead.
|
||||
# See the assessment note: obligation 1 as written admits no such case.
|
||||
on_apply:
|
||||
recorded_fields:
|
||||
- policy_zone
|
||||
- policy_failure_mode
|
||||
- policy_decision_id # present only where a decision was actually rendered
|
||||
- outcome
|
||||
written_to:
|
||||
- "signatures log (src/warden/ca.py)"
|
||||
- "audit.jsonl (src/warden/audit.py)"
|
||||
never_recorded: "any secret material, any certificate private key"
|
||||
|
||||
# §6.4 obligation 2 — the verdict is never cached. Input claims (zone membership,
|
||||
# compiled from the flex-auth registry snapshot) are cached under their own
|
||||
# freshness rules; the answer is not.
|
||||
verdict_caching: none
|
||||
input_claim_caching: "registry/flex-auth/production_registry_snapshot.json, rebuilt by scripts/build_flex_auth_registry.py"
|
||||
|
||||
# §6.4 obligation 4 — reconstructability, bounded by §9.6. ops-warden's audit
|
||||
# emission on this lane is deliberately non-atomic and therefore ATTRIBUTIVE, not
|
||||
# load-bearing: no control branches on the presence of a signing record
|
||||
# (`warden activity` displays it; nothing gates on it). Registered in §13.
|
||||
reconstructability:
|
||||
bound: "§9.6 attributive — completeness is not claimed"
|
||||
declared_at: wiki/AuditTrail.md
|
||||
|
|
@ -10,19 +10,21 @@
|
|||
# declares it, and is null where the field set has not been established --
|
||||
# null means unknown, never 'one field'.
|
||||
|
||||
generated_at: "2026-08-22T23:31:10Z"
|
||||
generated_at: "2026-08-31T22:46:47Z"
|
||||
source: ops-warden/registry/routing/catalog.yaml
|
||||
catalog_revision: "0fae0904ce8d8694338dd53a8a79abec5fec788d"
|
||||
catalog_revision_date: "2026-08-23T01:31:05+02:00"
|
||||
catalog_revision: "4fee839b1138c60642bd6e0210cf8bf541333747"
|
||||
catalog_revision_date: "2026-09-01T00:46:28+02:00"
|
||||
catalog_dirty: false
|
||||
high_risk_lane_count: 21
|
||||
concrete_path_count: 14
|
||||
high_risk_lane_count: 24
|
||||
concrete_path_count: 15
|
||||
|
||||
# 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
|
||||
- net-kingdom-lldap-bind-credential
|
||||
- net-kingdom-privacyidea-admin-token
|
||||
- object-storage-sts
|
||||
- openbao-api-key
|
||||
- openbao-platform-admin-login
|
||||
|
|
@ -75,6 +77,11 @@ paths:
|
|||
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: policy-nexus-forgejo-source-read
|
||||
data_path: platform/data/workloads/policy-nexus/forgejo-source-read
|
||||
metadata_path: platform/metadata/workloads/policy-nexus/forgejo-source-read
|
||||
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
|
||||
|
|
|
|||
|
|
@ -242,6 +242,42 @@ entries:
|
|||
- "Write it back: `bao kv put platform/workloads/coulomb/whynot-design/npm-publish NPM_AUTH_TOKEN=@file` (value from a mode-0600 file)."
|
||||
- "Verify capabilities-safe, then confirm publish works via `secrets-engine exec --catalog whynot-design-npm-publish -- npm whoami` (value used, not printed)."
|
||||
|
||||
- id: policy-nexus-forgejo-source-read
|
||||
title: Policy Nexus Forgejo private-source repository read token
|
||||
# Read-only at Forgejo, but disclosure grants estate-wide private source access.
|
||||
# Agent callers therefore remain inside Warden's sanctioned transport boundary.
|
||||
risk: high
|
||||
workload_ref:
|
||||
applicability: applicable
|
||||
unknown_reason: "policy-nexus-actions has not published an authoritative workload identity declaration."
|
||||
need_keywords: [policy-nexus, policy, nexus, forgejo, private, source, repository, read, token, actions, FORGEJO_SOURCE_TOKEN]
|
||||
owner_repo: railiance-platform
|
||||
subsystem: OpenBao + Forgejo Actions
|
||||
warden_executes: false
|
||||
wiki_ref: wiki/playbooks/policy-nexus-forgejo-source-read.md#worker-checklist
|
||||
canon_ref: railiance-platform/credential-change-requests/CCR-2026-0014-policy-nexus-forgejo-source-read.yaml
|
||||
reviewed: "2026-09-01"
|
||||
status: active
|
||||
delegation:
|
||||
mode: native
|
||||
intended_owner: railiance-platform
|
||||
reviewed: "2026-09-01"
|
||||
verified: source-read
|
||||
auth_method: "bao login -method=oidc -path=netkingdom role=policy-nexus-forgejo-source-workload-kv-read"
|
||||
path_template: "platform/workloads/policy-nexus/forgejo-source-read"
|
||||
fetch_command: "bao kv get -field=FORGEJO_SOURCE_TOKEN platform/workloads/policy-nexus/forgejo-source-read"
|
||||
policy_ref: "flex-auth check secret.read:policy-nexus"
|
||||
exec_capable: true
|
||||
lane: secret
|
||||
rotation:
|
||||
method: rotate
|
||||
owner: railiance-platform
|
||||
automatable: false
|
||||
steps:
|
||||
- "Mint a replacement PAT for the restricted policy-nexus-source identity with scope exactly read:repository; retain the predecessor until verification passes."
|
||||
- "Use the attended railiance-platform bootstrap to update OpenBao and the coulomb/policy-nexus FORGEJO_SOURCE_TOKEN Actions secret without exposing the value."
|
||||
- "Pass one exact-commit candidate workflow, then revoke the predecessor PAT and record bounded non-secret evidence in CCR-2026-0014."
|
||||
|
||||
- id: flex-auth-policy-check
|
||||
title: Authorization decision — may this actor perform this action
|
||||
# Returns an authorization decision; no credential flows (WARDEN-WP-0032-T05).
|
||||
|
|
@ -281,8 +317,8 @@ entries:
|
|||
delegation:
|
||||
mode: interim
|
||||
intended_owner: key-cape
|
||||
blocked_on: "REFUSED by secrets-engine 2026-08-21: login, MFA and identity-token issuance are key-cape/Keycloak's; secrets-engine may consume OIDC for OpenBao auth but does not own the login capability. ops-warden agrees — intended_owner corrected from secrets-engine to key-cape. Not yet asked of key-cape."
|
||||
reviewed: "2026-08-21"
|
||||
blocked_on: "REFUSED by secrets-engine 2026-08-21: login, MFA and identity-token issuance are key-cape/Keycloak's; secrets-engine may consume OIDC for OpenBao auth but does not own the login capability. ops-warden agrees — intended_owner corrected from secrets-engine to key-cape. Asked of key-cape 2026-08-28; KEY-WP-0009 accepting issuance ownership for machine identities is the precedent that makes it answerable."
|
||||
reviewed: "2026-08-28"
|
||||
verified: asked-and-waiting
|
||||
# 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
|
||||
|
|
@ -710,9 +746,9 @@ entries:
|
|||
delegation:
|
||||
mode: interim
|
||||
intended_owner: key-cape
|
||||
blocked_on: "client_secret_basic exchange is a key-cape protocol procedure, not a KV read; KEY-WP-0008 finished 2026-08-15 without a key-cape-native exchange/rotation command, and the workplan that would add one is not yet opened (key-cape acked interim 2026-08-15)"
|
||||
reviewed: "2026-08-17"
|
||||
verified: unverified
|
||||
blocked_on: "client_secret_basic exchange is a key-cape protocol procedure, not a KV read; still no key-cape-native exchange/rotation command. Re-checked against key-cape source 2026-08-28: KEY-WP-0009 finished 2026-08-23 and did add bounded service-auth (per-client tokenLifetime, docs/openbao-service-auth-contract.md), but that is client_credentials JWT issuance for OpenBao machine login — it does not front this client_secret_basic exchange or its rotation. The server advertises client_secret_basic (src/internal/server/oidc/discovery.go) without exposing an owner command for it. Blocker stands."
|
||||
reviewed: "2026-08-28"
|
||||
verified: source-read
|
||||
risk: high
|
||||
workload_ref:
|
||||
applicability: applicable
|
||||
|
|
|
|||
164
scripts/check_layer_conformance.py
Normal file
164
scripts/check_layer_conformance.py
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Check ops-warden against the NetKingdom security layer model (§5, §11).
|
||||
|
||||
Read-only. Makes §11's second mechanical check real:
|
||||
|
||||
every direct Tooling client in a Staff repository maps to a declared
|
||||
§5.1, §5.2, or §5.3 entry
|
||||
|
||||
The failure this catches is a *new* direct OpenBao contact appearing in
|
||||
src/warden/ without an entry in layer.yaml — an undeclared violation (§11),
|
||||
which is a finding rather than a tracked gap. It deliberately does NOT check
|
||||
the review dates: a date-triggered failure breaks the build on a calendar day
|
||||
with no code change (the reasoning recorded in WARDEN-WP-0033-T05), so
|
||||
staleness is reported and left to `--report`, never to CI.
|
||||
|
||||
Exit 0 clean, 1 undeclared contact found, 2 declaration malformed.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SRC = ROOT / "src" / "warden"
|
||||
DECL = ROOT / "layer.yaml"
|
||||
|
||||
VALID_SHAPES = {"5.1", "5.2", "5.3"}
|
||||
|
||||
# A direct Tooling contact is an *invocation*, not a mention. Matching the word
|
||||
# "bao" caught help text, a docstring, and the dev-tier doubles library that
|
||||
# simulates bao rather than calling it — three false positives on first run.
|
||||
# So match the two shapes that actually execute:
|
||||
# 1. an HTTP request built against the OpenBao address
|
||||
# 2. an argv list whose first element is the bao binary
|
||||
TOOLING_PATTERNS = (
|
||||
# httpx call whose URL is built from the configured OpenBao/Vault address
|
||||
re.compile(r"""\bhttpx\.\w+\(|url\s*=\s*f?["'].*\{self\._cfg\.addr\}"""),
|
||||
# argv construction: [bao_bin, ...] / ["bao", ...] / [bao_binary, ...]
|
||||
re.compile(r"""\[\s*(?:["']bao["']|bao_bin\b|bao_binary\b)\s*,"""),
|
||||
)
|
||||
|
||||
# httpx alone is not a Tooling contact — policy.py calls an Engine and worker.py
|
||||
# calls the State Hub. A module matching only the httpx pattern counts as a
|
||||
# contact only if it also references the OpenBao address configuration.
|
||||
ADDR_HINT = re.compile(r"""_cfg\.addr|VAULT_ADDR|BAO_ADDR""")
|
||||
|
||||
# Modules that talk to an Engine or to something outside the §4 catalog. Listed
|
||||
# in layer.yaml under non_tooling_clients and excluded from the scan with it.
|
||||
def _excluded(decl: dict) -> set[str]:
|
||||
return {e["module"].split("/")[-1] for e in decl.get("non_tooling_clients", [])}
|
||||
|
||||
|
||||
def load_declaration() -> dict:
|
||||
if not DECL.exists():
|
||||
print(f"MISSING: {DECL} — ops-warden must declare in its own voice (§11)")
|
||||
raise SystemExit(2)
|
||||
decl = yaml.safe_load(DECL.read_text())
|
||||
for key in ("layer", "repository", "standard_version", "tooling_contacts"):
|
||||
if key not in decl:
|
||||
print(f"MALFORMED: layer.yaml has no {key!r}")
|
||||
raise SystemExit(2)
|
||||
for c in decl["tooling_contacts"]:
|
||||
if c.get("shape") not in VALID_SHAPES:
|
||||
print(f"MALFORMED: {c.get('id')} has shape {c.get('shape')!r}, not one of {sorted(VALID_SHAPES)}")
|
||||
raise SystemExit(2)
|
||||
# §5.3 carries four fields, machine-readably. That is the whole point of
|
||||
# the shape; a gap missing them is prose wearing a schema.
|
||||
if c["shape"] == "5.3":
|
||||
for field in ("capability", "intended_owner", "blocked_on", "review"):
|
||||
if not c.get(field):
|
||||
print(f"MALFORMED: §5.3 entry {c['id']!r} is missing {field!r}")
|
||||
raise SystemExit(2)
|
||||
# §5.2's test is the supplied-authority property.
|
||||
if c["shape"] == "5.2" and c.get("supplied_authority") != "none":
|
||||
print(f"MALFORMED: §5.2 conduit {c['id']!r} must declare supplied_authority: none")
|
||||
raise SystemExit(2)
|
||||
return decl
|
||||
|
||||
|
||||
def scan_modules() -> dict[str, list[int]]:
|
||||
"""Return {module_name: [line numbers]} for direct Tooling contacts."""
|
||||
found: dict[str, list[int]] = {}
|
||||
for path in sorted(SRC.rglob("*.py")):
|
||||
if path.name.startswith("test_"):
|
||||
continue
|
||||
text = path.read_text()
|
||||
hits: list[int] = []
|
||||
for n, line in enumerate(text.splitlines(), 1):
|
||||
stripped = line.strip()
|
||||
if stripped.startswith("#") or stripped.startswith('"'):
|
||||
continue
|
||||
if any(p.search(line) for p in TOOLING_PATTERNS):
|
||||
hits.append(n)
|
||||
if hits:
|
||||
# An httpx-only match needs the OpenBao address to be a Tooling
|
||||
# contact; otherwise it is an Engine or non-catalogued call.
|
||||
argv_shape = any(TOOLING_PATTERNS[1].search(ln) for ln in text.splitlines())
|
||||
if argv_shape or ADDR_HINT.search(text):
|
||||
found[path.name] = hits
|
||||
return found
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--report", action="store_true", help="also print the declaration and gap review dates")
|
||||
args = ap.parse_args()
|
||||
|
||||
decl = load_declaration()
|
||||
declared = {c["module"].split("/")[-1] for c in decl["tooling_contacts"]}
|
||||
excluded = _excluded(decl)
|
||||
found = scan_modules()
|
||||
|
||||
undeclared = {m: lines for m, lines in found.items() if m not in declared and m not in excluded}
|
||||
# A voluntary declaration has no fixed argv shape to detect (an
|
||||
# operator-configured command). Over-declaring is safe; not reporting it as
|
||||
# stale keeps the signal meaningful.
|
||||
voluntary = {
|
||||
c["module"].split("/")[-1]
|
||||
for c in decl["tooling_contacts"]
|
||||
if c.get("detection") == "voluntary"
|
||||
}
|
||||
stale_decls = declared - set(found) - voluntary
|
||||
|
||||
if args.report:
|
||||
print(f"{decl['repository']} — layer: {decl['layer']} (model v{decl['standard_version']})")
|
||||
print(f"declared by {decl['declared_by']}\n")
|
||||
for c in decl["tooling_contacts"]:
|
||||
line = f" §{c['shape']} {c['id']:<28} {c['module']}"
|
||||
if c["shape"] == "5.3":
|
||||
overdue = str(c["review"]) < date.today().isoformat()
|
||||
line += f" -> {c['intended_owner']} review {c['review']}"
|
||||
if overdue:
|
||||
line += " [REVIEW OVERDUE]"
|
||||
print(line)
|
||||
gaps = [c for c in decl["tooling_contacts"] if c["shape"] == "5.3"]
|
||||
print(f"\n{len(gaps)} declared gap(s) — tracked non-conformance, not conformance (§11).")
|
||||
|
||||
ok = True
|
||||
if undeclared:
|
||||
ok = False
|
||||
print("\nUNDECLARED TOOLING CONTACT — a finding under §11, not a tracked gap:")
|
||||
for m, lines in sorted(undeclared.items()):
|
||||
print(f" src/warden/{m}: line(s) {', '.join(map(str, lines[:6]))}")
|
||||
print("\nAdd a §5.1/§5.2/§5.3 entry to layer.yaml, or route it through an engine.")
|
||||
|
||||
if stale_decls:
|
||||
print("\nNote: declared but no contact found (module removed or refactored?):")
|
||||
for m in sorted(stale_decls):
|
||||
print(f" {m}")
|
||||
|
||||
if ok and not args.report:
|
||||
print(f"PASS — {len(found)} module(s) with Tooling contact, all declared.")
|
||||
elif ok:
|
||||
print("\nPASS — every direct Tooling contact maps to a declared shape.")
|
||||
return 0 if ok else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
|
@ -12,8 +12,9 @@ intact. Three guardrails are enforced here in code:
|
|||
the tool with inherited stdout/stderr so the value never enters warden's memory;
|
||||
sanctioned exec/file transports hold it only for their bounded handoff. The
|
||||
high-risk attended-login lane is stricter: it captures every client byte inside
|
||||
an isolated helper session, permits no output, self-revokes, and cleans up. Audit
|
||||
records are metadata only.
|
||||
an isolated helper session, never returns that output, requires successful
|
||||
persistence to a private token helper, self-revokes, and cleans up. Audit records
|
||||
are metadata only.
|
||||
* **G3 — policy gate before fetch.** The CLI runs ``check_fetch_policy`` before
|
||||
calling anything here; this module refuses to run an unresolved command template.
|
||||
|
||||
|
|
@ -380,9 +381,11 @@ def proxy_attended_login_exec(
|
|||
"""Run an attended login and one silent child inside a private helper home.
|
||||
|
||||
The default home is proven writable before the OIDC client starts. Login,
|
||||
child, and revocation output are captured and discarded. Any non-empty output,
|
||||
persistence defect, or non-zero result fails closed; any possibly issued token
|
||||
is revoked before the isolated helper directory is removed.
|
||||
child, and revocation output are captured and discarded. A successful login
|
||||
may return client output only after the private helper has been populated;
|
||||
persistence defects and non-zero results fail closed. The reviewed child must
|
||||
remain silent. Any possibly issued token is revoked before the isolated helper
|
||||
directory is removed.
|
||||
"""
|
||||
if not child_argv:
|
||||
raise ProxyError(
|
||||
|
|
@ -400,6 +403,10 @@ def proxy_attended_login_exec(
|
|||
root, session, root_created = _prepare_attended_login_home()
|
||||
helper = session / _TOKEN_HELPER_NAME
|
||||
env = _caller_env()
|
||||
if not env.get("WARDEN_CONFIG"):
|
||||
caller_config = Path.home() / ".config" / "warden" / "warden.yaml"
|
||||
if caller_config.is_file():
|
||||
env["WARDEN_CONFIG"] = str(caller_config)
|
||||
env["HOME"] = str(session)
|
||||
env.pop("BAO_TOKEN", None)
|
||||
env.pop("VAULT_TOKEN", None)
|
||||
|
|
@ -428,7 +435,7 @@ def proxy_attended_login_exec(
|
|||
except (OSError, ProxyError):
|
||||
helper_valid = False
|
||||
|
||||
if login.returncode != 0 or login_output.strip() or not helper_valid:
|
||||
if login.returncode != 0 or not helper_valid:
|
||||
revoked = _revoke_contained(
|
||||
resolved.argv[0], env=env, possible_output=login_output
|
||||
)
|
||||
|
|
|
|||
133
tests/test_layer_conformance.py
Normal file
133
tests/test_layer_conformance.py
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
"""Layer-model conformance (security-layer-model_v0.4 §5, §11).
|
||||
|
||||
Two things are checked here. §11 makes one of them mechanical: every direct
|
||||
Tooling client maps to a declared shape. §5.2 asks for the other: the conduit's
|
||||
supplied-authority property covered by a test.
|
||||
|
||||
Deliberately absent: any assertion on a §5.3 review date. A date-triggered
|
||||
failure breaks the build on a calendar day with no code change, punishing
|
||||
whoever commits next rather than whoever owns the gap — the same reasoning
|
||||
recorded in WARDEN-WP-0033-T05 for blocker staleness.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def _decl() -> dict:
|
||||
return yaml.safe_load((ROOT / "layer.yaml").read_text())
|
||||
|
||||
|
||||
class TestDeclaration:
|
||||
def test_declares_staff_layer_in_its_own_voice(self):
|
||||
d = _decl()
|
||||
assert d["repository"] == "ops-warden"
|
||||
assert d["layer"] == "staff"
|
||||
# §11: "only the repository's own file, in its own voice, conforms."
|
||||
assert d["declared_by"] == "docs/adr/ADR-0010"
|
||||
|
||||
def test_every_tooling_contact_maps_to_a_declared_shape(self):
|
||||
"""§11 mechanical check — the guard against a new undeclared client."""
|
||||
result = subprocess.run(
|
||||
[sys.executable, str(ROOT / "scripts" / "check_layer_conformance.py")],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
assert result.returncode == 0, (
|
||||
f"undeclared Tooling contact — a finding under §11, not a tracked gap:\n"
|
||||
f"{result.stdout}{result.stderr}"
|
||||
)
|
||||
|
||||
def test_declared_gaps_carry_all_four_fields(self):
|
||||
"""§5.3 is machine-readable or it is prose wearing a schema."""
|
||||
for c in _decl()["tooling_contacts"]:
|
||||
if c["shape"] == "5.3":
|
||||
for field in ("capability", "intended_owner", "blocked_on", "review"):
|
||||
assert c.get(field), f"{c['id']} missing {field}"
|
||||
|
||||
def test_gaps_are_not_counted_as_conformance(self):
|
||||
"""§11: a declared gap is tracked non-conformance. Keep that visible."""
|
||||
text = (ROOT / "layer.yaml").read_text()
|
||||
assert "TRACKED NON-CONFORMANCE" in text.upper()
|
||||
|
||||
|
||||
class TestConduitSuppliesNoAuthority:
|
||||
"""§5.2: 'MUST NOT present its own credential, MUST NOT widen what the
|
||||
caller could already do.' The standard says this SHOULD be covered by a
|
||||
test; this is that test."""
|
||||
|
||||
def test_conduit_supplies_no_authority_of_its_own(self, monkeypatch):
|
||||
from warden import proxy
|
||||
|
||||
monkeypatch.setenv("VAULT_TOKEN", "caller-own-token")
|
||||
monkeypatch.setenv("HOME", "/home/nobody")
|
||||
before = dict(os.environ)
|
||||
|
||||
env = proxy._caller_env()
|
||||
|
||||
# The child environment IS the caller's environment — nothing added,
|
||||
# nothing removed, no ops-warden credential injected.
|
||||
assert env == before, (
|
||||
"conduit altered the caller's environment; §5.2 requires it to "
|
||||
"supply no authority of its own"
|
||||
)
|
||||
assert env["VAULT_TOKEN"] == "caller-own-token"
|
||||
|
||||
def test_conduit_declares_supplied_authority_none(self):
|
||||
conduits = [c for c in _decl()["tooling_contacts"] if c["shape"] == "5.2"]
|
||||
assert conduits, "no §5.2 conduit declared — proxy.py is one"
|
||||
for c in conduits:
|
||||
assert c["supplied_authority"] == "none"
|
||||
|
||||
def test_proxy_holds_no_credential_constant(self):
|
||||
"""A conduit that presents its own token is not a conduit (§5.2)."""
|
||||
src = (ROOT / "src" / "warden" / "proxy.py").read_text()
|
||||
# It may name token ENV VARS to detect caller auth; it must not carry a
|
||||
# token value or mint one.
|
||||
for forbidden in ("X-Vault-Token", "auth/approle/login", "token create"):
|
||||
assert forbidden not in src, (
|
||||
f"proxy.py references {forbidden!r} — that is presenting or "
|
||||
f"minting authority, not conducting the caller's"
|
||||
)
|
||||
|
||||
|
||||
class TestPepStanceMap:
|
||||
"""§6.4: every PEP-shaped consumer MUST publish its unreachable-engine
|
||||
stance map, total and per zone, 'published rather than held in code'.
|
||||
ADR-0009 is named as the reference shape, so it should actually hold."""
|
||||
|
||||
def _stance(self) -> dict:
|
||||
return yaml.safe_load((ROOT / "pep-stance.yaml").read_text())
|
||||
|
||||
def test_published_map_equals_shipped_behaviour(self):
|
||||
"""The whole point. A published map that may drift from the code is
|
||||
worse than none, because it invites reliance it cannot support."""
|
||||
from warden.config import PolicyConfig
|
||||
|
||||
assert self._stance()["stance"] == PolicyConfig().failure_modes
|
||||
|
||||
def test_stance_is_total_over_the_zone_model(self):
|
||||
"""§6.4 obligation 3: total, no implicit default."""
|
||||
stance = self._stance()["stance"]
|
||||
required = {
|
||||
"z0-experimental", "z1-operational", "z2-protected",
|
||||
"z2-continuity", "z3-critical", "unknown", "not-applicable",
|
||||
}
|
||||
assert required <= set(stance), f"stance not total; missing {required - set(stance)}"
|
||||
assert set(stance.values()) <= {"fail_open", "fail_closed"}
|
||||
|
||||
def test_critical_zone_fails_closed(self):
|
||||
"""ADR-0009's one non-negotiable row."""
|
||||
assert self._stance()["stance"]["z3-critical"] == "fail_closed"
|
||||
|
||||
def test_verdict_is_never_cached(self):
|
||||
"""§6.4 obligation 2: caching an input claim is permitted; caching the
|
||||
answer is a second decision point deciding early (§6.1)."""
|
||||
assert self._stance()["verdict_caching"] == "none"
|
||||
|
|
@ -391,6 +391,70 @@ def test_attended_login_unexpected_output_is_contained_revoked_and_cleaned(
|
|||
assert not (tmp_path / ".warden-attended-login").exists()
|
||||
|
||||
|
||||
def test_attended_login_contained_success_output_never_escapes(monkeypatch, tmp_path, capsys):
|
||||
monkeypatch.setattr(Path, "home", lambda: tmp_path)
|
||||
sentinel = "hvs.NONPRODUCTION_CONTAINED_LOGIN"
|
||||
child_ran = False
|
||||
|
||||
def fake_run(argv, **kw):
|
||||
nonlocal child_ran
|
||||
helper = Path(kw["env"]["HOME"]) / ".vault-token"
|
||||
if argv[:2] == ["bao", "login"]:
|
||||
helper.write_text(sentinel)
|
||||
helper.chmod(0o600)
|
||||
return subprocess.CompletedProcess(
|
||||
argv,
|
||||
0,
|
||||
stdout=json.dumps({"auth": {"client_token": sentinel}}).encode(),
|
||||
stderr=b"",
|
||||
)
|
||||
if argv == ["reviewed-child"]:
|
||||
child_ran = True
|
||||
return subprocess.CompletedProcess(argv, 0, stdout=b"", stderr=b"")
|
||||
if argv[:3] == ["bao", "token", "revoke"]:
|
||||
return subprocess.CompletedProcess(argv, 0, stdout=b"", stderr=b"")
|
||||
raise AssertionError(argv)
|
||||
|
||||
monkeypatch.setattr("warden.proxy.subprocess.run", fake_run)
|
||||
assert proxy_attended_login_exec(
|
||||
ResolvedFetch(argv=["bao", "login", "-no-print"]),
|
||||
child_argv=["reviewed-child"],
|
||||
) == 0
|
||||
captured = capsys.readouterr()
|
||||
assert child_ran is True
|
||||
assert sentinel not in captured.out
|
||||
assert sentinel not in captured.err
|
||||
assert not (tmp_path / ".warden-attended-login").exists()
|
||||
|
||||
|
||||
def test_attended_login_preserves_caller_warden_config_for_reviewed_child(
|
||||
monkeypatch, tmp_path
|
||||
):
|
||||
monkeypatch.setattr(Path, "home", lambda: tmp_path)
|
||||
monkeypatch.delenv("WARDEN_CONFIG", raising=False)
|
||||
caller_config = tmp_path / ".config" / "warden" / "warden.yaml"
|
||||
caller_config.parent.mkdir(parents=True)
|
||||
caller_config.write_text("backend: local\n")
|
||||
seen_config = None
|
||||
|
||||
def fake_run(argv, **kw):
|
||||
nonlocal seen_config
|
||||
helper = Path(kw["env"]["HOME"]) / ".vault-token"
|
||||
if argv[:2] == ["bao", "login"]:
|
||||
helper.write_text("non-production-test-double")
|
||||
helper.chmod(0o600)
|
||||
if argv == ["reviewed-child"]:
|
||||
seen_config = kw["env"].get("WARDEN_CONFIG")
|
||||
return subprocess.CompletedProcess(argv, 0, stdout=b"", stderr=b"")
|
||||
|
||||
monkeypatch.setattr("warden.proxy.subprocess.run", fake_run)
|
||||
assert proxy_attended_login_exec(
|
||||
ResolvedFetch(argv=["bao", "login", "-no-print"]),
|
||||
child_argv=["reviewed-child"],
|
||||
) == 0
|
||||
assert seen_config == str(caller_config)
|
||||
|
||||
|
||||
def test_real_catalog_login_entry_is_login_lane():
|
||||
from warden.routing import load_catalog
|
||||
e = load_catalog(_repo_catalog()).get("key-cape-oidc-login")
|
||||
|
|
|
|||
|
|
@ -153,6 +153,32 @@ def test_whynot_design_npm_lane_is_concrete_and_resolvable():
|
|||
assert "platform/workloads/coulomb/whynot-design/npm-publish" in e.fetch_command
|
||||
|
||||
|
||||
def test_policy_nexus_source_read_lane_is_exact_high_risk_and_resolvable():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
entry = catalog.get("policy-nexus-forgejo-source-read")
|
||||
assert entry is not None and entry.is_active and entry.exec_capable
|
||||
assert entry.resolvable is True
|
||||
assert entry.risk == "high"
|
||||
assert entry.owner_repo == "railiance-platform"
|
||||
assert entry.fetch_command == (
|
||||
"bao kv get -field=FORGEJO_SOURCE_TOKEN "
|
||||
"platform/workloads/policy-nexus/forgejo-source-read"
|
||||
)
|
||||
assert entry.path_template == "platform/workloads/policy-nexus/forgejo-source-read"
|
||||
assert entry.auth_method.endswith(
|
||||
"role=policy-nexus-forgejo-source-workload-kv-read"
|
||||
)
|
||||
assert entry.delegation is not None and entry.delegation.mode == "native"
|
||||
|
||||
|
||||
def test_route_find_policy_nexus_source_read_prefers_concrete_lane():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
matches = catalog.find(
|
||||
"policy nexus Forgejo private source repository read token Actions", limit=1
|
||||
)
|
||||
assert matches[0].id == "policy-nexus-forgejo-source-read"
|
||||
|
||||
|
||||
def test_generic_and_template_lanes_not_resolvable():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
# generic openbao lane has <FIELD>/<path_template>; login lane has <domain>.
|
||||
|
|
|
|||
|
|
@ -13,8 +13,10 @@ def test_repo_catalog_uses_only_explicit_workload_references():
|
|||
report = build(ROOT / "registry/routing/catalog.yaml", Path.home())
|
||||
assert report["ok"] is True
|
||||
assert len(report["resolved"]) == 3
|
||||
assert len(report["unknown"]) == 17
|
||||
assert len(report["not_applicable"]) == 9
|
||||
assert len(report["unknown"]) == 18
|
||||
# 11 since WARDEN-WP-0033: the two NetKingdom SSO lanes (c374d41) are
|
||||
# provider/control-plane credentials, not workload delivery lanes.
|
||||
assert len(report["not_applicable"]) == 11
|
||||
assert {row["lane"] for row in report["resolved"]} == {
|
||||
"ops-warden-warden-sign-token",
|
||||
"issue-core-ingestion-api-key",
|
||||
|
|
|
|||
|
|
@ -32,6 +32,20 @@ fresh file starts.
|
|||
high-entropy runs). Signing and proxy paths swallow audit failures so gatekeeping
|
||||
never blocks the primary action — but tests prove values cannot be written.
|
||||
|
||||
> **Absence of a record is not evidence of absence.** Because emission never
|
||||
> blocks the primary action (`src/warden/ca.py`), a failed append loses the event
|
||||
> while the action still happens. This trail proves that the records it holds were
|
||||
> not altered or truncated; it does **not** prove that every action produced one.
|
||||
> Do not reason from a missing entry. This is the estate-wide bound in
|
||||
> `security-layer-model_v0.4` §9.6 — completeness is the source's obligation, and
|
||||
> **Ruled 2026-08-29** (`security-layer-model_v0.6` §9.6): this trail is
|
||||
> **attributive**, not load-bearing — no control branches on the presence of a
|
||||
> signing record — so the non-atomic trade is legitimate, and the obligations are
|
||||
> to declare it (this note) and never to claim completeness. Atomicity is required
|
||||
> only where a control's soundness depends on an event being present or absent.
|
||||
> Registered in the standard's §13 open-gap table as self-declared. If a future
|
||||
> control ever gates on this trail, the trade must be revisited before it ships.
|
||||
|
||||
---
|
||||
|
||||
## Query
|
||||
|
|
|
|||
55
wiki/playbooks/policy-nexus-forgejo-source-read.md
Normal file
55
wiki/playbooks/policy-nexus-forgejo-source-read.md
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# Policy Nexus Forgejo source-read token
|
||||
|
||||
Date: 2026-09-01
|
||||
Catalog: `policy-nexus-forgejo-source-read` (status `active`, `resolvable: true`)
|
||||
Owner: `railiance-platform` (OpenBao and credential lifecycle)
|
||||
|
||||
This lane carries the dedicated Forgejo PAT used by Policy Nexus Actions to
|
||||
fetch exact archives from private owner repositories. The Forgejo identity is
|
||||
restricted to organization-wide repository-code read and the PAT scope is
|
||||
exactly `read:repository`. It has no repository write, package, organization
|
||||
administration, instance administration, cluster, or deployment authority.
|
||||
|
||||
The authoritative lifecycle and evidence record is
|
||||
`railiance-platform/credential-change-requests/CCR-2026-0014-policy-nexus-forgejo-source-read.yaml`.
|
||||
Warden is a governed conduit and never owns, persists, caches, or logs the PAT.
|
||||
|
||||
## Owner-confirmed lane
|
||||
|
||||
| Field | Value |
|
||||
| --- | --- |
|
||||
| OpenBao path | `platform/workloads/policy-nexus/forgejo-source-read` |
|
||||
| Primary field | `FORGEJO_SOURCE_TOKEN` |
|
||||
| Read policy | `workload-kv-read-policy-nexus-forgejo-source` |
|
||||
| OIDC role | `policy-nexus-forgejo-source-workload-kv-read` |
|
||||
| Forgejo identity | `policy-nexus-source` |
|
||||
| Forgejo team | `policy-nexus-source-readers` |
|
||||
| Actions consumer | `coulomb/policy-nexus` secret `FORGEJO_SOURCE_TOKEN` |
|
||||
|
||||
## Worker checklist
|
||||
|
||||
1. Authenticate as an approved operator through the exact OIDC role. Do not
|
||||
substitute the Forgejo admin PAT or a broader OpenBao identity.
|
||||
|
||||
2. Confirm the route before use:
|
||||
|
||||
```bash
|
||||
warden route show policy-nexus-forgejo-source-read --json | jq .resolvable
|
||||
```
|
||||
|
||||
The result must be `true`, and the rendered fetch must contain no placeholder.
|
||||
|
||||
3. Agent callers must use a sanctioned high-risk transport. Pass the value only
|
||||
to the bounded source-consuming child:
|
||||
|
||||
```bash
|
||||
warden access policy-nexus-forgejo-source-read \
|
||||
--field FORGEJO_SOURCE_TOKEN --exec -- <reviewed-source-read-command>
|
||||
```
|
||||
|
||||
Do not use raw `--fetch`, place the value on argv, or write it to chat, Git,
|
||||
State Hub, workflow logs, or a persistent temporary file.
|
||||
|
||||
4. For rotation or compromise, follow CCR-2026-0014. A replacement is not active
|
||||
until its scope and negative permissions are verified and one exact-commit
|
||||
Policy Nexus candidate workflow succeeds; revoke the predecessor afterward.
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
id: ADHOC-2026-06-27
|
||||
id: WARDEN-WP-ADHOC-2026-06-27
|
||||
type: workplan
|
||||
title: "Ad Hoc Tasks — 2026-06-27"
|
||||
domain: infotech
|
||||
|
|
@ -9,7 +9,7 @@ owner: claude
|
|||
topic_slug: custodian
|
||||
created: "2026-06-27"
|
||||
updated: "2026-06-27"
|
||||
state_hub_workstream_id: "142b171b-c34b-4a45-91a5-c77e6d07ec6f"
|
||||
state_hub_workstream_id: "a222c91f-3bb5-58a4-b6b2-f0fb18cdd5c3"
|
||||
---
|
||||
|
||||
# Ad Hoc Tasks — 2026-06-27
|
||||
|
|
@ -19,10 +19,10 @@ Low-risk opportunistic fixes completed directly during the consolidation session
|
|||
### T01 — Fix stale `warden` CLI install + make it usable outside the repo
|
||||
|
||||
```task
|
||||
id: ADHOC-2026-06-27-T01
|
||||
id: WARDEN-WP-ADHOC-2026-06-27-T01
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "867c72c9-9904-400f-8542-04264e5856c2"
|
||||
state_hub_task_id: "9176b560-8ca5-5143-888d-479857fe60f0"
|
||||
```
|
||||
|
||||
issue-core reported (msg `70bcf238`) that the `warden` CLI on `~/.local/bin` lacked
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
id: ADHOC-2026-06-29
|
||||
id: WARDEN-WP-ADHOC-2026-06-29
|
||||
type: workplan
|
||||
title: "Ad Hoc Tasks — 2026-06-29"
|
||||
domain: infotech
|
||||
|
|
@ -9,7 +9,7 @@ owner: claude
|
|||
topic_slug: custodian
|
||||
created: "2026-06-29"
|
||||
updated: "2026-06-29"
|
||||
state_hub_workstream_id: "1c0460b7-bc8a-48db-96d4-681bce18ac91"
|
||||
state_hub_workstream_id: "13fa845f-852e-55ec-a2a5-2296996e0216"
|
||||
---
|
||||
|
||||
# Ad Hoc Tasks — 2026-06-29
|
||||
|
|
@ -17,10 +17,10 @@ state_hub_workstream_id: "1c0460b7-bc8a-48db-96d4-681bce18ac91"
|
|||
### T01 — Joint-smoke mode for the deployed flex-auth (assist FLEX-WP-0007 T4)
|
||||
|
||||
```task
|
||||
id: ADHOC-2026-06-29-T01
|
||||
id: WARDEN-WP-ADHOC-2026-06-29-T01
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "371235cc-b9d3-4103-b09f-e4e01cc83c5b"
|
||||
state_hub_task_id: "62540533-f4ca-5176-9237-32adbeb292ee"
|
||||
```
|
||||
|
||||
flex-auth (msg `ea00620b`) asked ops-warden to help close FLEX-WP-0007 T4 (joint OpenBao
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
id: ADHOC-2026-08-11
|
||||
id: WARDEN-WP-ADHOC-2026-08-11
|
||||
type: workplan
|
||||
title: "Ad Hoc Tasks — 2026-08-11"
|
||||
domain: infotech
|
||||
|
|
@ -9,7 +9,7 @@ owner: claude
|
|||
topic_slug: custodian
|
||||
created: "2026-08-11"
|
||||
updated: "2026-08-15"
|
||||
state_hub_workstream_id: "bc6dd3e3-ab2b-567a-9574-30d2650f20a2"
|
||||
state_hub_workstream_id: "9f99cc64-4682-5f20-b13e-89af2b6f7c70"
|
||||
---
|
||||
|
||||
# Ad Hoc Tasks — 2026-08-11
|
||||
|
|
@ -17,10 +17,10 @@ state_hub_workstream_id: "bc6dd3e3-ab2b-567a-9574-30d2650f20a2"
|
|||
### T01 — Repair stale `rapp-qonto-keycape-client` wiki anchor (restore green routing suite)
|
||||
|
||||
```task
|
||||
id: ADHOC-2026-08-11-T01
|
||||
id: WARDEN-WP-ADHOC-2026-08-11-T01
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "ddd0c95c-1196-5251-a4ca-6ef441c2f377"
|
||||
state_hub_task_id: "0771d121-278c-556e-9509-841cf6e657c3"
|
||||
```
|
||||
|
||||
rapp-postgres (msg `96907986`, residual from RAPP-POSTGRES-WP-0002-T04) reported the
|
||||
|
|
@ -39,10 +39,10 @@ an anchor that does not exist. The intended heading is `## Routing catalog index
|
|||
### T02 — Triage the stale ops-warden inbox (11 unread, C-28/C-29)
|
||||
|
||||
```task
|
||||
id: ADHOC-2026-08-11-T02
|
||||
id: WARDEN-WP-ADHOC-2026-08-11-T02
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "fda35ad4-f526-5012-a2be-ef6b5dcbc8af"
|
||||
state_hub_task_id: "0ed58145-732f-5102-b6a8-b931d9b6ba08"
|
||||
```
|
||||
|
||||
`fix-consistency` flagged 11 unread messages older than 3 days, two of them as possible
|
||||
|
|
@ -73,10 +73,10 @@ read. Inbox is now empty.
|
|||
### T03 — warden-sign AppRole: PARKED pending WP-0027 break-glass + ops-bridge cutover
|
||||
|
||||
```task
|
||||
id: ADHOC-2026-08-11-T03
|
||||
id: WARDEN-WP-ADHOC-2026-08-11-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "7ef4b6b0-26bf-5456-8429-8cf8458c2ddc"
|
||||
state_hub_task_id: "337ae793-c6b0-59e9-8a07-3a7ccba237aa"
|
||||
```
|
||||
|
||||
secrets-engine (msg `80456912`, 2026-06-29) is holding a validated non-mutating dry-run
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
id: ADHOC-2026-08-17
|
||||
id: WARDEN-WP-ADHOC-2026-08-17
|
||||
type: workplan
|
||||
title: "Ad Hoc Tasks — 2026-08-17"
|
||||
domain: infotech
|
||||
|
|
@ -9,7 +9,7 @@ owner: claude
|
|||
topic_slug: custodian
|
||||
created: "2026-08-17"
|
||||
updated: "2026-08-17"
|
||||
state_hub_workstream_id: "8376eb89-36f2-52b0-a59a-2954b2e49349"
|
||||
state_hub_workstream_id: "5c6c2bbb-b944-5afd-b89c-20d865518849"
|
||||
---
|
||||
|
||||
# Ad Hoc Tasks — 2026-08-17
|
||||
|
|
@ -21,10 +21,10 @@ workload-identity owner.
|
|||
### T01 — Answer flex-auth: how should `/v1/check` authenticate its callers?
|
||||
|
||||
```task
|
||||
id: ADHOC-2026-08-17-T01
|
||||
id: WARDEN-WP-ADHOC-2026-08-17-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b980d1f7-2fcc-58dd-97d8-6e9b9ba57bc9"
|
||||
state_hub_task_id: "04a2f8f9-e70b-5eed-ad87-343c8f9ef501"
|
||||
```
|
||||
|
||||
flex-auth (msg `130a148c`, FLEX-WP-0015 T02) reported that `POST /v1/check` and
|
||||
|
|
@ -69,10 +69,10 @@ Their four questions answered in `wiki/NetKingdomSecurityMap.md`
|
|||
### T02 — user-engine: USER_ENGINE_PROXY_SECRET stays railiance-apps; record consumer-only
|
||||
|
||||
```task
|
||||
id: ADHOC-2026-08-17-T02
|
||||
id: WARDEN-WP-ADHOC-2026-08-17-T02
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "e76b9b3e-189b-5a4f-8815-4ccf2057507c"
|
||||
state_hub_task_id: "0e815282-2fad-5c8d-be34-398e492737d0"
|
||||
```
|
||||
|
||||
user-engine (msg `2af4a124`) answered the open confirm question on
|
||||
|
|
@ -95,10 +95,10 @@ consumes it and has no authority over custody, rotation, or issuance.
|
|||
### T03 — key-cape: `rapp-qonto-keycape-client` interim accepted; refresh the blocker
|
||||
|
||||
```task
|
||||
id: ADHOC-2026-08-17-T03
|
||||
id: WARDEN-WP-ADHOC-2026-08-17-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "edfb0626-5022-5f49-aaf9-08e0d1002b90"
|
||||
state_hub_task_id: "e21781d9-a35d-5916-b335-d12131f97a22"
|
||||
```
|
||||
|
||||
key-cape (msg `099b7cba`) acknowledged the lane staying interim on ops-warden.
|
||||
|
|
@ -118,10 +118,10 @@ workplan.
|
|||
### T04 — Session hygiene
|
||||
|
||||
```task
|
||||
id: ADHOC-2026-08-17-T04
|
||||
id: WARDEN-WP-ADHOC-2026-08-17-T04
|
||||
status: done
|
||||
priority: low
|
||||
state_hub_task_id: "62109af6-f095-5e7b-9258-0fcec29d30e8"
|
||||
state_hub_task_id: "b15724e0-c27a-5260-a810-4dd25bff2228"
|
||||
```
|
||||
|
||||
- [x] `uv run pytest -q` → 338 passed, 4 deselected (routing anchor + no-double-source
|
||||
|
|
|
|||
|
|
@ -222,6 +222,39 @@ test results, and infra acceptance. T02 remains `progress` until
|
|||
that owner gate is open; acceptance will permit preparation of a new scenario,
|
||||
not execution or reuse of the terminal one.
|
||||
|
||||
**Owner gate CLOSED — accepted 2026-08-23, found 2026-08-28.**
|
||||
`railiance-platform` accepted the exact revision `0fae0904`. Recorded in their
|
||||
`RPF-WP-0017-attended-login-output-containment.md` (`status: finished`), which
|
||||
also records railiance-infra's independent approval at `186b030` and marks all
|
||||
five acceptance criteria met. The receipt digest was verified here rather than
|
||||
taken on trust: `docs/evidence/RAILIANCE-WP-0026-T01-ops-warden-receipt.json` at
|
||||
ops-warden `bc1966da` hashes to
|
||||
`d2ba444ed16989590325697e69d25283dc75a9432c29a72e627e80bf9fd987e4`, matching
|
||||
their record exactly.
|
||||
|
||||
Note the identifier: the remediation interface recorded above as
|
||||
`RAILIANCE-WP-0026-T01` is `RPF-WP-0017-T01` in the owner's repo. Searching for
|
||||
the cited id finds an unrelated workplan, which is part of why this sat unnoticed.
|
||||
|
||||
**Their acceptance is source acceptance only and authorizes no live OIDC or
|
||||
drill** — their words, and the boundary holds. So T02's state changes but its
|
||||
`Done when` does not: what was blocked was *preparing a new scenario*, and that
|
||||
is now permitted. The terminal NO-GO scenario and its receipts remain unusable.
|
||||
|
||||
**Third instance of the same failure this session.** The acceptance existed for
|
||||
five days; no message reached ops-warden. Identically, `key-cape` accepted the
|
||||
WP-0033-T04 question on 2026-08-23 with no message, and nine unread messages
|
||||
were sitting on already-superseded threads. The `verified:` field added by
|
||||
WP-0033-T05 was built for exactly this and it works — what does not work is
|
||||
waiting for a counterparty to tell you. Re-checking a blocker means reading the
|
||||
owner's repository.
|
||||
|
||||
**Remaining to close T02:** one attended production emergency seal/unseal drill,
|
||||
requiring a new scenario id, fresh owner receipts from platform/infra/master, a
|
||||
fully parameterized green preflight, and a new human GO. It is executed by the
|
||||
platform owner, never by a coding agent. That is an operator decision, not an
|
||||
agent one, so T02 stays `progress` and the decision is surfaced rather than taken.
|
||||
|
||||
## Task: Tamper-evident policy governance + reconcile
|
||||
|
||||
```task
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ type: workplan
|
|||
title: "Native lane handoff — review secrets-engine's catalog admission, and fix what it exposed"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: active
|
||||
status: finished
|
||||
owner: ops-warden
|
||||
topic_slug: netkingdom
|
||||
planning_priority: P1
|
||||
depends_on_workplans:
|
||||
- WARDEN-WP-0030
|
||||
created: "2026-08-21"
|
||||
updated: "2026-08-23"
|
||||
updated: "2026-08-28"
|
||||
state_hub_workstream_id: "4627d89b-4b00-562a-81e9-76e96f90fa7e"
|
||||
---
|
||||
|
||||
|
|
@ -160,7 +160,7 @@ railiance-platform may deny more, deny less, or dispute a grade (`ADR-0002`).
|
|||
|
||||
```task
|
||||
id: WARDEN-WP-0033-T04
|
||||
status: wait
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "5acac140-a586-5db3-b231-bbf236710786"
|
||||
```
|
||||
|
|
@ -212,6 +212,33 @@ accept that target identity with an authoritative workplan/interface, or refuse
|
|||
and name the actual owner. T04 remains `wait` until one of those two answers is
|
||||
recorded; the live AppRole is operational evidence, not an ownership answer.
|
||||
|
||||
**Answered — accepted. Closed 2026-08-28.** `key-cape` accepted issuance
|
||||
ownership in `KEY-WP-0009-T03` (`status: done`, 2026-08-23): the non-secret static
|
||||
registration `codex-railiance-platform` is published in
|
||||
`key-cape/config/service-clients.example.yaml` — subject
|
||||
`service:codex:railiance-platform`, tenant `tenant:coulomb`, role `coding-agent`,
|
||||
scope `openbao:login`, `client_credentials`, 15-minute lifetime — with the
|
||||
service-auth claims, renewal, expiry and failure semantics in
|
||||
`key-cape/docs/openbao-service-auth-contract.md` (`T02`). The split is exactly the
|
||||
one the routing asked for: KeyCape owns JWT issuance and client disablement,
|
||||
railiance-platform owns the exact-bound OpenBao role and policy, OpenBao owns
|
||||
enforcement, and no secret value enters either repository.
|
||||
|
||||
**The answer was found by reading their repo, not by receiving it.**
|
||||
`KEY-WP-0009-T04` records replying to ops-warden; no such message exists in the
|
||||
ops-warden inbox — 0 messages from `key-cape`, read or unread. The acceptance had
|
||||
been sitting done for five days while this task sat `wait` on it.
|
||||
|
||||
That is the T05 lesson landing on T04: a blocker is a claim about the world at a
|
||||
date, and this one had stopped being true. `verified: source-read` is doing real
|
||||
work here — it is the difference between "we asked" and "we checked". The
|
||||
mechanism is right; what it needs is for someone to run it, which is why the
|
||||
lanes below were re-verified in the same pass rather than date-bumped.
|
||||
|
||||
Consequence for `ADR-0004`: the honour-system `WARDEN_AGENT_ID` marker now has a
|
||||
real issuance identity behind it on the OpenBao side. ops-warden remains a
|
||||
consumer of that identity and does not own it.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0033-T05
|
||||
status: done
|
||||
|
|
|
|||
171
workplans/WARDEN-WP-0034-layer-model-v07-conformance.md
Normal file
171
workplans/WARDEN-WP-0034-layer-model-v07-conformance.md
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
---
|
||||
id: WARDEN-WP-0034
|
||||
type: workplan
|
||||
title: "Layer model v0.7 conformance — state the deadline, bind the agent boundary, steward the estate's newest rule"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: ready
|
||||
owner: ops-warden
|
||||
topic_slug: netkingdom
|
||||
planning_priority: P1
|
||||
depends_on_workplans:
|
||||
- WARDEN-WP-0030
|
||||
created: "2026-08-29"
|
||||
updated: "2026-08-29"
|
||||
state_hub_workstream_id: "ae3ff76f-883d-5e2f-b6aa-144d61e8fdef"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0034 — Layer model v0.7 conformance
|
||||
|
||||
`security-layer-model_v0.7` is **accepted**. ops-warden declared Staff and PEP-shaped,
|
||||
shipped the two declaration artifacts the standard now cites as estate reference forms,
|
||||
and had four findings adopted into the text between v0.4 and v0.7.
|
||||
|
||||
The assessment in `history/2026-08-29-v07-scope-intent-assessment.md` checked every
|
||||
v0.7 obligation against shipped code rather than intent. Three gaps survive, plus a
|
||||
role the companion assigns that no conformance check will ever catch.
|
||||
|
||||
## Why a workplan and not an adhoc
|
||||
|
||||
T01 is a `MUST` that is currently unstated. T02 changes an enforcement boundary and
|
||||
touches `ADR-0004`. T04 is a cross-repo stewardship commitment against a standard eight
|
||||
repositories have yet to adopt. The convention reserves adhocs for low-risk work
|
||||
completed directly; none of these qualify.
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0034-T01
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "8b3bdb9f-d2c2-5b3e-89e2-417bf3e37484"
|
||||
```
|
||||
|
||||
**State the revocation visibility deadline (§9.7.2, a MUST).**
|
||||
|
||||
ops-warden states none, and the honest value is the certificate TTL: **up to 48 hours**.
|
||||
A cert issued under an allow remains valid for its full TTL even if the authorizing
|
||||
decision is revoked the next minute. There is no CRL, no KRL distribution, and host-side
|
||||
`auth_principals` belongs to `railiance-infra`.
|
||||
|
||||
Add the deadline to `pep-stance.yaml` as what it is — `adm` 48h / `agt` 24h / `atm` 8h —
|
||||
with the mechanism named (TTL expiry, no revocation channel) rather than implied. Assert
|
||||
it against the shipped `ActorType` TTL policy by test, the same way the stance map is
|
||||
asserted equal to shipped behaviour: a stated deadline free to drift from the code has
|
||||
the same defect as a stated stance free to drift.
|
||||
|
||||
**Done when:** the deadline is published, test-bound to the TTL policy, and the absence
|
||||
of a revocation channel is stated rather than left to inference.
|
||||
|
||||
**Not in scope:** shortening it. Whether 48h is acceptable is a joint question with
|
||||
`railiance-infra` (KRL distribution) and is T05's to raise, not this task's to decide.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0034-T02
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "3318ee1a-b5d9-5d39-baf7-9c42a8bc7b55"
|
||||
```
|
||||
|
||||
**Bind the agent read-boundary to an issued identity (§3.4 rule 1).**
|
||||
|
||||
`ADR-0004`'s boundary triggers on `WARDEN_AGENT_ID` — a variable the agent sets about
|
||||
itself. An agent that omits it is not recognised as one. §3.4 rule 1 now requires
|
||||
authority to be *issued* per task and attributable to the principal acted for.
|
||||
|
||||
The identity exists as of `KEY-WP-0009-T03`: `codex-railiance-platform`, subject
|
||||
`service:codex:railiance-platform`, role `coding-agent`, 15-minute lifetime, with
|
||||
`railiance-platform` enforcing the OpenBao-side policy.
|
||||
|
||||
Key the boundary on the issued identity where one is present; keep `WARDEN_AGENT_ID` as
|
||||
a fallback that fails **toward** the boundary, never away from it. State plainly in the
|
||||
ADR trail which half is enforced and which is advisory: the OpenBao-side deny is real,
|
||||
the ops-warden-side refusal is a courtesy that a determined caller can decline.
|
||||
|
||||
**Done when:** an agent presenting the issued identity is recognised without setting
|
||||
`WARDEN_AGENT_ID`, the fallback still refuses on `risk: high` lanes, and the
|
||||
enforced/advisory split is written down.
|
||||
|
||||
**Watch:** do not turn this into ops-warden validating a token — that is verifying an
|
||||
identity claim, adjacent to deciding, and `ADR-0002`/§6 both point away from it. Read
|
||||
the identity; do not adjudicate it.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0034-T03
|
||||
status: todo
|
||||
priority: medium
|
||||
state_hub_task_id: "a891b32c-b0a7-59f6-a5cd-977be65c09ca"
|
||||
```
|
||||
|
||||
**Derive an emission cadence, or defer it with a reason (§9.6).**
|
||||
|
||||
ops-warden's trail is attributive, so cadence is a SHOULD rather than v0.7's MUST for
|
||||
load-bearing sources. It has been silent through two reviews, which is the one outcome
|
||||
that is not defensible.
|
||||
|
||||
Derive a baseline from the existing `audit.jsonl` and signatures log. If the signal is
|
||||
too bursty to support a threshold — plausible, since volume is operator-driven — record
|
||||
that as the finding with the distribution that shows it, and declare the deferral in
|
||||
`pep-stance.yaml`. A measured "no useful baseline" is a result; silence is not.
|
||||
|
||||
**Done when:** either a declared cadence with its derivation, or a declared deferral
|
||||
carrying the data that justifies it.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0034-T04
|
||||
status: todo
|
||||
priority: medium
|
||||
state_hub_task_id: "94e73daa-f74d-51fd-8639-68896a4066ee"
|
||||
```
|
||||
|
||||
**Answer the question the companion sends the estate here to ask.**
|
||||
|
||||
> *"For how to get something done — which lane, which credential, which route — ask
|
||||
> `ops-warden`."*
|
||||
|
||||
Today the repo answers credential questions and no others. `warden route` and
|
||||
`warden plan` cover lanes, owners and acts. Nothing answers *"which layer am I"*, *"how
|
||||
do I declare"*, *"I am PEP-shaped, what do I owe"* — and eight of fifteen catalogued
|
||||
repositories have yet to declare.
|
||||
|
||||
Provide the path, not the doctrine (that boundary is `ADR-0010`'s and does not move):
|
||||
a routing entry and a short playbook that carry a reader from the companion to the files
|
||||
to copy — `layer.yaml`, `pep-stance.yaml`, `check_layer_conformance.py`,
|
||||
`test_layer_conformance.py` — and the check to run. The standard already names these in
|
||||
§11 and §6.4; what is missing is the route to them.
|
||||
|
||||
**Done when:** `warden route find "how do I declare my layer"` resolves, and the
|
||||
playbook is reachable from the catalog. **Not** a restatement of the companion — a
|
||||
pointer layer, per `ADR-0001`.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0034-T05
|
||||
status: todo
|
||||
priority: low
|
||||
state_hub_task_id: "7d1b3c82-9b96-5087-a53a-496212909029"
|
||||
```
|
||||
|
||||
**Two things to raise rather than absorb.**
|
||||
|
||||
Both are other repositories' to own; ops-warden's obligation is to route them, not to
|
||||
fix them (`ADR-0003`, `ADR-0005`).
|
||||
|
||||
1. **`ops-mason` has published no stance map.** §13.1's register has one row and the
|
||||
standard says that is itself the finding. `ops-mason` is catalogued PEP-shaped in
|
||||
the same paragraph and is ops-warden's peer lane owner. Offer the reference form;
|
||||
do not write their map.
|
||||
2. **The 48-hour replay window from T01.** Once stated, raise with `railiance-infra`
|
||||
whether KRL distribution is worth building, and with `access-engine` whether a
|
||||
decision lifetime shorter than the cert TTL is meaningful when nothing can recall
|
||||
the cert. State the question; let the owners answer.
|
||||
|
||||
**Done when:** both are routed with reasoning, and the answers recorded either way —
|
||||
including a refusal, which is an equally good answer.
|
||||
|
||||
## Related
|
||||
|
||||
- `history/2026-08-29-v07-scope-intent-assessment.md` — the gap analysis behind this plan
|
||||
- `history/2026-08-29-layer-model-v04-review.md`, `-v06-review.md` — the two prior reviews
|
||||
- `security-layer-model_v0.7.md` §3.4, §6.4, §9.6, §9.7, §11, §13.1
|
||||
- `net-kingdom/SECURITY-COMPANION.md` v0.2
|
||||
- `ADR-0002`, `ADR-0003`, `ADR-0004`, `ADR-0005`, `ADR-0009`, `ADR-0010`
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
id: WARDEN-WP-0035
|
||||
type: workplan
|
||||
title: "Register the Policy Nexus Forgejo source-read route"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: policy-nexus-forgejo-source-read
|
||||
created: "2026-09-01"
|
||||
updated: "2026-09-01"
|
||||
state_hub_workstream_id: "45aec8d3-94b3-586e-b019-a47e656efafa"
|
||||
---
|
||||
|
||||
## Register the exact high-risk lane
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0035-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "dd84f2be-0143-540c-9c16-74f0fd129260"
|
||||
```
|
||||
|
||||
Add the exact OpenBao path, field, OIDC role, owner pointer, and rotation
|
||||
boundary from railiance-platform CCR-2026-0014. The entry must be concrete and
|
||||
resolvable while remaining subject to Warden's high-risk agent read boundary.
|
||||
|
||||
## Verify routing and governed use
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0035-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "1fa8f778-3e46-5f44-86c4-cab8628b7e60"
|
||||
```
|
||||
|
||||
Pass catalog, route-selection, proxy, and policy tests; reinstall the CLI; prove
|
||||
the installed route resolves and can hand the value only to a sanctioned child
|
||||
transport without printing or persisting it.
|
||||
|
||||
Completed 2026-09-01. All 406 selected tests passed, including the generated
|
||||
high-risk data-path boundary. The no-cache installed CLI resolves the exact
|
||||
lane, and `warden plan` returns only sanctioned `--exec`, `--out`, and `--wrap`
|
||||
transports for an agent caller. Policy Nexus Actions run 32 separately proved
|
||||
the installed credential against the complete private-source fetch and release
|
||||
path without exposing the value.
|
||||
43
workplans/WARDEN-WP-0036-attended-login-openbao-output.md
Normal file
43
workplans/WARDEN-WP-0036-attended-login-openbao-output.md
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
id: WARDEN-WP-0036
|
||||
type: workplan
|
||||
title: "Accept contained OpenBao login output only after helper persistence"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: attended-login-openbao-output
|
||||
created: "2026-09-01"
|
||||
updated: "2026-09-01"
|
||||
state_hub_workstream_id: "d844c96e-152d-53fa-bff6-e072125ef66c"
|
||||
---
|
||||
|
||||
## Repair attended-login handoff
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0036-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "7eb8b9c9-1285-5ada-a17b-1d5bfbb8ba59"
|
||||
```
|
||||
|
||||
Allow a successful OpenBao login to proceed when its output is fully contained
|
||||
and the private mode-0600 token helper is populated. Continue failing closed on
|
||||
non-zero login, missing persistence, child output, revocation failure, or cleanup
|
||||
failure.
|
||||
|
||||
## Verify live contained operation
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0036-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "d22bab05-c38b-561f-95de-6c146ce7c6cf"
|
||||
```
|
||||
|
||||
Run the proxy regression suite, reinstall the CLI, and complete one governed
|
||||
OpenBao platform-admin operation with deterministic self-revocation.
|
||||
|
||||
Completed 2026-09-01. The installed CLI completed the governed Policy Nexus
|
||||
Forgejo source bootstrap with all child output contained, then revoked and
|
||||
removed its isolated helper session.
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
id: ADHOC-2026-07-07
|
||||
id: WARDEN-WP-ADHOC-2026-07-07
|
||||
type: workplan
|
||||
title: "Ad Hoc Tasks — 2026-07-07"
|
||||
domain: infotech
|
||||
|
|
@ -9,7 +9,7 @@ owner: grok
|
|||
topic_slug: custodian
|
||||
created: "2026-07-07"
|
||||
updated: "2026-07-07"
|
||||
state_hub_workstream_id: "2e8bc783-2e37-4b86-a691-177b18329783"
|
||||
state_hub_workstream_id: "90568b1e-8395-5c67-9c69-851ed08ff3d3"
|
||||
---
|
||||
|
||||
> **Terminology note:** Historical text in this archived workplan may use the legacy term "workstream". The fleet term is **workplan** (`canon/standards/workplan-terminology-fleet_v0.1.md`).
|
||||
|
|
@ -19,10 +19,10 @@ state_hub_workstream_id: "2e8bc783-2e37-4b86-a691-177b18329783"
|
|||
### T01 — Roll out proxy pipe fix (be3b4a2)
|
||||
|
||||
```task
|
||||
id: ADHOC-2026-07-07-T01
|
||||
id: WARDEN-WP-ADHOC-2026-07-07-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "55b6de52-b958-4b72-94eb-4ba1b8da2629"
|
||||
state_hub_task_id: "bf985c95-bea6-5057-94f9-9cfa7e1c9dd8"
|
||||
```
|
||||
|
||||
`warden access` failed on `reuse-surface-hub-write-token` because `shlex.split`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue