gate-house asked ops-warden to assent to three boundary items ratified in
GH-DEC-2026-001. All three are assented in ADR-0010.
Staff: accepted. Grepping section 5 as it invites turned up a real
non-conformance — src/warden/vault.py is a direct OpenBao client performing a
write, and so is `warden desk`'s `bao kv put`. Section 5's only escape hatch is
read-only diagnostics, which does not cover a signing write, so both are
declared in INTENT.md as an engine gap with intended owner secrets-engine and
the blocker "no engine exposes an SSH-CA surface" — ADR-0003 turned inward
rather than an exemption argued for. taint.py is metadata-only and declared
under the read-only allowance; `warden access` proxies run under the caller's
identity and supply no authority of their own.
Doctrine versus runbook: accepted. NetKingdom Security Literacy becomes a lane
routing runbook that references gate-house doctrine instead of restating it. It
had also become a prose second source for registry/routing/catalog.yaml, which
ADR-0001 already rules against.
Lane versus rule: assented unconditionally, and the access-engine veto is not
exercised. One request on sequencing only — a window where both names resolve.
gate-house added to the routing tables in INTENT.md and SCOPE.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBMovyFoy9RRrfL7zKvPJ
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
secrets-engine reviewed our catalog metadata while drafting their five entries
and graded issue-core-ingestion-api-key and reuse-surface-hub-write-token high.
We had both as standard, and had deliberately regraded them DOWN on 2026-08-19.
They are right. Both paths carry a second credential our grade never looked at --
GITEA_BACKEND_TOKEN (CCR-2026-0002, a deliberate field-set decision) and a
dual-consumer webhook HMAC (CCR-2026-0005). Neither is recovered by rotating the
credential the lane is named after.
The defect is structural: we graded the lane by its headline field, but a read
returns every field at the path. Worse, the evidence was already in the CCRs we
cite as authoritative -- not missing, unread -- and a test asserted the wrong
answer, so a correct first-pass grade got overruled by it.
ADR-0008 records the rule: a grade covers every field its path discloses.
ADR-0007 is unchanged and still governs; this says what the grade is of.
Six of the remaining standard lanes have no KV path. Two have paths and no field
evidence; per ADR-0008 they are stated as unknown rather than assumed, and left
for operator-sanctioned grading.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Closes the RISK-F-0003 exposure. All 14 ungraded lanes now carry an explicit
risk grade with its justification in the entry: 17 high, 10 standard, 0
ungraded. The agent read-boundary now fires (exit 7) on lanes that were silently
outside it.
Graded on merit rather than defensively. A first pass marked two ordinary
internal workload secrets high; test_high_risk_lanes_classified asserted the
opposite and was right, so both were regraded down. high means disclosure into a
logged context is damaging beyond what rotation recovers. inter-hub-bootstrap-ssh
is high conservatively, with the reason in the entry so it is regraded with
evidence rather than assumed down.
ADR-0007 records the rule the grading rests on: build-stage permissiveness
applies to controls that gate work, not to controls that prevent credential
disclosure. The test is friction, not severity — the read-boundary blocks nobody,
since --out/--exec/--wrap remain available, so relaxing it buys nothing. A
blocked operation is recovered by retrying; a credential in a logged transcript
is not recovered by rotation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
net-kingdom ruled that zone membership rides tenancy.yaml under a reserved
zones: key, and ops-warden had no such file — so declaring zones later implies
declaring the six-axis vector first. This is that file.
Current: I1 A1 E0 P n/a R n/a V0, validated against the canon schema.
Graded honestly against the standard's own worked examples rather than
flatteringly. A1 not A2: there is a single choke point on the signing path, but
it binds an actor to principals, not a request to the tenants it may act for,
and tenant context is a constant. E0 is accurate and is not a defect to
remediate — ops-warden holds no tenant-keyed data because ADR-0002 forbids it
custody, and claiming E1 on the strength of OpenBao's enforcement would be
someone else's control counted as ours. V0 because the code path for a local-CA
fallback exists but has never been exercised, and §13 does not accept "the code
path exists" as evidence.
implemented: A3 is the one place ops-warden is ahead of its current level —
flex-auth delegation is built and was verified live against the enforcing pin
(decision:f3f7c88f9585582a). It is not current because ADR-0006 defers it.
The zones: key is deliberately absent with the reason written in: no zone
vocabulary exists yet, so any value would be fabricated.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
zone-engine is seeded and owns the security zone model as ZONE-WP-0001. Under
ADR-0005 ops-warden implements one lane narrowly and routes the rest, and an
estate-wide enforcement model is not a lane to absorb — it was ops-warden's
deferred flip that exposed the gap, not ops-warden's model to define.
WARDEN-WP-0032 is rewritten as the consumer side: hand the estate inputs to
ZONE-WP-0001-T02 (27 catalog lanes, the actor inventory, the three posture axes,
the three controls the model must express, and the compiled-registry path),
then replace policy.enabled with a zone-aware control and amend ADR-0006 to say
ops-warden follows the model rather than owning it.
ADR-0006 and SCOPE updated to point at zone-engine, which joins the related
repositories table.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
flex-auth enforced its ops-warden pin (FLEX-WP-0016 T03) and the gate verified
clean against it: readiness exits 0, decision:f3f7c88f9585582a, anonymous
/v1/check now 401. Everything needed to set policy.enabled: true was in place.
It stays false, by decision. policy.enabled is a single repo-wide boolean, and
with fail_closed: true it makes flex-auth a hard dependency of every warden
sign — including the certs the ops-bridge tunnels depend on, one of which
carries the policy call itself. Uniform enforcement across an estate being
actively rebuilt hardens the access needed to perform the rebuild.
The repo already refuses one-dimensional posture: WP-0015 shipped environment
and maturity axes, WP-0029 added organization_posture. A global flag ignores all
three. ADR-0006 records that enforcement belongs to a zone, and binds future
work — a zone-blind enforcement flag is out of order, not merely unwise.
WARDEN-WP-0032 drafts the zone model, leading with the ownership question:
whether this is ops-warden's to own or NetKingdom canon to consume (ADR-0005).
WP-0031 is finished with T05 cancelled and resuming as WP-0032-T05.
Also replaces the hand-run kubectl port-forward with a managed ops-bridge
tunnel, flex-auth-ops-warden-railiance01 (-L 19090:10.43.1.165:8080).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
flex-auth's flex-auth-ops-warden pin (FLEX-WP-0016) TokenReviews the caller and
binds resource.system: ops-warden to system:serviceaccount:ops-warden:ops-warden.
policy.py posted /v1/check with no Authorization header, so the pin logs
"caller authentication warning" and can only run callerAuth.mode: warn — which,
under ADHOC-2026-08-17-T01, is exactly what blocks policy.enabled: true.
- policy.caller_auth (none | file | env | command) + src/warden/caller_identity.py:
token resolved per call, never cached, written, or logged (ADR-0002)
- both check_sign_policy and check_fetch_policy attach the bearer header; an
unobtainable token fails closed rather than retrying anonymously
- scripts/check_policy_caller_identity.py: read-only gate, prints length and a
truncated fingerprint only, distinguishes 401 (audience/binding) from 403
- example config: caller_auth block, and flex_auth_url corrected — it pointed at
flex-auth.flex-auth.svc, a Service that does not exist
- WARDEN-WP-0031, PolicyGatedSigning caller-identity section and flip sequence
Default stays mode: none, so behaviour is unchanged until an operator opts in.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Five rules that governed this repo lived in wiki prose, a workplan, and a
comment at the top of catalog.yaml. All were followed; none was addressable.
A reader outside ops-warden could not cite one, could not tell whether it was
current, and — the point of this change — could not tell whether it was ours
to change or someone else's that we merely obey.
ADR-0001 The routing catalog is a pointer layer, never a second copy
ADR-0002 ops-warden is a transparent conduit, never a secret broker
ADR-0003 Cover gaps, but never silently own them
ADR-0004 High-risk lanes refuse raw value streaming to agent sessions
ADR-0005 Implement one lane narrowly, route everything else
Each carries owner: ops-warden, which is the load-bearing field. It says we
follow the rule AND we are responsible for changing it — by superseding ADR,
never an in-place edit. The failure this prevents runs both ways: a rule we own
mistaken for inherited canon never gets fixed, because we wait for an owner who
does not exist; inherited canon mistaken for ours gets quietly bent, and the
drift is invisible until it breaks a repo that trusted the canonical version.
Rules we follow but do not own — NetKingdom canon, the IAM profile, the
credential-management standard, the-custodian's ADR-001 workplan convention —
are cited, never copied into docs/adr/. Copying them would recreate exactly the
second-source-of-truth failure ADR-0001 exists to prevent. architecture.md also
now flags the three-digit/four-digit ADR-001 vs ADR-0001 collision, which is
itself an ours-versus-inherited confusion waiting to happen.
Publication verified rather than assumed: all five render through policy-nexus
tools/render.py, and owner reaches the reader in three places — the page eyebrow
(render.py:346), the index Owner column (build_site.py:123,137), and the
publication manifest. build_site.py:179 makes title/status/owner required, so
ownership cannot be dropped on the way out. policy-nexus publishes and never
writes back; docs/adr/ stays the source of truth.
Documentation adapted: SCOPE.md gains a Governing rules section and an orientation
entry; .claude/rules/architecture.md replaced its stub with the ADR index, the
owned-versus-inherited rule, and ADR-over-wiki precedence; finding-routing.md's
ADR-gap section closed; catalog.yaml's no-double-source header now cites ADR-0001
rather than the originating workplan.
uv run pytest -q → 338 passed, 4 deselected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every execution position is now explicit. Catalog entries carry
delegation.mode (permanent / native / interim) with intended owner and
blocker. warden route gaps lists the interim set. Promotion requires
the ownership question. Doctrine lives in AccessRouting.md; the
register was published to the named owner repos.
Founder directive: ops-warden works with, never replaces or duplicates,
secrets-engine / tenant-engine / user-engine. Covering an unfilled gap is
acceptable only as a tracked interim with a named intended owner.
- INTENT §9 "Cover gaps, but never silently own them"; success criterion 7;
tenant-engine and user-engine added to the literacy table; non-goal on
permanently owning another component's lane
- WP-0030 (proposed): delegation: metadata, backfill, warden route gaps,
promotion gate, publish the register to owner repos
- history/2026-08-11-delegation-surface-assessment.md: 2 of 24 lanes carry
exec_owner; 11 proxies record no intended owner
- SCOPE refreshed to 2026-08-11 (was 6 workplans behind); completeness C5 -> C4
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add unified metadata-only audit.jsonl with secret-material guard, instrument
sign/access/worker paths, and expose warden activity CLI. Surface broker hint
when VAULT_TOKEN is unset, refresh INTENT/SCOPE docs, and add production
integration checklists plus catalog lane promotion playbook.
Persist the 2026-07-01 assessment, register the alignment workplan with
tasks for INTENT refresh, production integration coordination, broker UX,
and catalog promotion. Promote WP-0022 to ready and update SCOPE links.
T4 (review→send loop): conservative tick persists structured drafts to
state_dir/worker-drafts.json; `warden worker drafts` lists them, `warden worker approve
<id> [--body …]` sends the reviewed draft as the reply + marks read + drops it. Escalated
plans persist no draft. Live-verified end-to-end.
T3 (visibility): `warden worker status` (pending drafts, triage count, last digest, timer
state); best-effort notify-send nudge in the tick when drafts are pending.
T5: wiki/playbooks/scheduled-worker.md (enable/disable, the approve loop, failure modes,
conservative-only posture) + SCOPE note.
WARDEN-WP-0021 finished: the conservative worker now runs on a systemd --user timer
(enabled, every 15 min), triages new inbox messages into drafts you approve with one
command, degrades gracefully, and stops with one command. 249 tests, lint clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
secrets-engine (SECRETS-WP-0003) shipped a native secret-exec front door
(`secrets-engine route/exec`, decision e6381a56) and asked ops-warden to route to it.
Bernd's call: route-primary, proxy-fallback — surface the secrets-engine exec as the
primary path for owned lanes, keep `warden access --exec` as a transparent fallback.
T1 — RouteEntry gains exec_owner/exec_command/pointer_command (+ has_native_exec),
screened for secret material like the other handoff fields. whynot-design-npm-publish
points its native exec at secrets-engine. `warden access` renders Primary (secrets-engine
exec) + Fallback (warden proxy); route/access JSON gain the fields and a native-exec-aware
next_action. Tests added; 217 pass, lint clean.
T2 — credential-routing.md adds secrets-engine as the secret-exec owner (route primary,
proxy fallback); SCOPE adds secrets-engine to Related Repos and records the npm lane as
production-exercised (@whynot/design@0.4.0); playbook leads with secrets-engine exec and
fixes the fallback one-liner (--field NPM_AUTH_TOKEN, --no-policy) per whynot-design.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
WP-0014 made ops-warden the operator access front door (warden access --fetch/--exec
proxies an exec_capable secret as the caller), but every discovery surface still told
the pre-WP-0014 "SSH certs only, pointer not key" story — so agents like whynot-design
never found the proxy and concluded they had to message ops-warden for a token value.
Messaging/discoverability only; the conduit security model is unchanged (no custody,
no broker).
T1 — CLI: `warden route` table warden column is now three-valued (issue/assist/route);
route + access JSON gain warden_role + exec_capable and a proxy-aware next_action;
`warden access` closing line leads with "ops-warden can fetch this for you as the
caller" for exec_capable lanes (route-only lanes keep "owner vends").
T2 — .claude/rules/credential-routing.md reframed (lead + routing table role column);
SCOPE one-liner + a second capability block for the access front door.
T3 — registered the State Hub capability "Operator access front door (caller-identity
fetch proxy)" (the hub had no ops-warden security capability at all); messaged
whynot-design the corrected `warden access "npm auth token" --fetch/--exec` path.
210 tests pass, lint clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Update SCOPE.md "Where we are" / INTENT gap / maturity vector / Current State to
reflect the ops-bridge cert_command pilot (WP-0016) shipped to pilot-ready and all
ops-warden workplans finished. Remaining distance is external (flex-auth prod flip,
ops-bridge live cutover, owner-driven WP-0015 canon landing).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Close ops-warden's side of the last Partial INTENT criterion (ops-bridge integrates
via a stable cert_command). The migration playbook and contract already existed; what
was missing was an automated readiness gate before touching tunnel config.
T1 — scripts/check_tunnel_cert_readiness.py: read-only preflight that asserts the
cert_command path is ready without signing — config/backend, actor inventory + TTL
within type max, pubkey exists/parses/not-private, principals present, and optional
host-principal deployment (mirrors check_principals_drift). Exit 0/1/2.
T2 — opt-in --sign-smoke: runs the cert_command against the local backend and validates
identity/principals/TTL of the emitted cert; refuses a vault backend. Window measured
from the cert's own valid_from->valid_before so it's timezone-robust (fixes a CEST
off-by-2h artifact). integration-marked test + a vault-refusal unit test.
T3 — playbook now leads with Step 0 readiness gate; ops-bridge handoff message sent.
T4 — SCOPE INTENT row: Partial -> Pilot-ready; known-gaps + SSH-lane list updated.
9 unit + 1 integration test, 209 default passing, lint clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Finish the Workload Security Posture workplan (all five tasks done).
T3 — scripts/check_secret_posture_conformance.py: read-only checker that asserts
env-posture conformance (backend/unseal/real_values per tier) and evaluates the
secret-flow lattice via posture.can_deliver. Metadata-only manifest, no secret
values, exit 0/1/2. examples/posture-conformance.example.yaml as the reference.
T4 — src/warden/doubles.py: generalizes "fake bao" into materialize_doubles() —
hermetic, synthetic-only (synthetic- prefix) stand-ins for bao/key-cape honoring
each argv/stdout/exit contract, for fully offline dev/test access flows. Documented
as the sanctioned dev backend in WorkloadSecurityPosture.md R1.
T5 — INTENT/SCOPE/wiki aligned; canon landing in net-kingdom/info-tech-canon left
owner-driven (tracked via coordination messages).
16 new tests, 200 passing, ruff clean. Archived WP-0012/0014/0015 to
workplans/archived/ with 260627- prefix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- wiki/OperatorAccessAssist.md: warden access contract, conduit-vs-broker
boundary, the three guardrails + catalog secret guard, lane semantics.
- AccessRouting.md: issue/route/assist roles; reconciled the anti-pattern
table so the transparent conduit no longer contradicts it.
- credential-routing.md rule: added warden access + "standing broker
forbidden, transparent --fetch sanctioned" anti-pattern.
- INTENT.md: pointer→assist charter extension. SCOPE.md: implemented
list + Getting Oriented + maturity A4→A5 (Availability).
- history decision record for the proxy-mode choice and guardrails.
WP-0014 finished (T1–T5). 172 passed, lint clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Promote Inter-Hub bootstrap lane to active catalog with worker checklist,
attended/unattended branches, and flex-auth/OpenBao pointers. Mark WP-0012
T2/T3 done; ops-bridge tunnel playbook shipped in prior WP-0013 commit.
Add a read-only `warden route` command group (list/show/find) that reads
registry/routing/catalog.yaml and tells a worker which subsystem owns a need
and which wiki/canon doc to follow. ops-warden still executes exactly one lane
(SSH); routed entries return a pointer and never call any subsystem.
- src/warden/routing/: models.py + catalog.py loader; enforces the
no-double-source rule (non-SSH entries with steps/cert_command fail validation),
dup-id and schema checks.
- route list (active-only unless --all, --tag), route show (SSH appends steps +
cert pattern; routed ends with "next action on <owner> — see <wiki_ref>"),
route find (keyword ranking, --json).
- tests/test_routing.py: load/validation, find ranking, CLI JSON shapes, plus a
drift guard (every wiki_ref anchor resolves; every entry has a reviewed date).
- Docs: wiki/AccessRouting.md CLI section, README quick reference, SCOPE A3 -> A4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implements WARDEN-WP-0010 (charter + pointer catalog). ops-warden issues
short-lived SSH certificates and routes every other credential need to the
subsystem that owns it — no desk metaphor, one execution lane.
- wiki/AccessRouting.md: role/boundary, issue-vs-route matrix, anti-patterns
- registry/routing/catalog.yaml: machine-readable pointer layer (6 active + 1
draft). No-double-source rule enforced structurally — authored steps/cert_command
only on the warden_executes:true SSH entry; every wiki_ref anchor resolves
- wiki/CredentialRouting.md: catalog-keyed index + no-duplicate-interfaces note
- INTENT/SCOPE/AGENTS/repo-boundary/capability: aligned to the new framing;
SCOPE notes A3 -> A4 lands with WP-0011 warden route CLI
- WP-0011/0012 + WP-0010: state_hub id writeback; WP-0010 marked done
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SCOPE.md now documents where we are (R3 production sign), INTENT criteria
status, maturity vector, and workplan landscape. Add reassessment history;
point INTENT evolution notes at latest assessment.
Mark WP-0008 finished and move to archived/. Spin flex-auth production gate
to WARDEN-WP-0009. Update SCOPE and reassessment history for R3 reliability.
- Post-WP-0007 reassessment and SCOPE/README updates
- AGENTS.md + workplan-convention task status canon migration
- examples/warden.production.example.yaml for production OpenBao
- Archive WP-0004 through WP-0007 to workplans/archived/260617-*
- WP-0008 T1/T3/T4 done; T2/T5 wait on operator/flex-auth
Add ops-warden INTENT as operational access steward for NetKingdom
security (route credential lanes, align docs, issue SSH certs only).
Refresh SCOPE for stewardship scope, persist INTENT↔SCOPE gap assessment,
and open WARDEN-WP-0006 for routing runbooks and platform alignment.
Document OpenBao as the platform production secrets service while keeping
the vault-compatible warden.yaml config shape. Update OpsWardenConfig,
SCOPE, and CertCommandInterface cross-references.
Update SCOPE and README to reflect the shipped warden CLI, fill agent
rules for stack/architecture/boundary, archive finished workplans
0001–0003, and register WP-0004 in State Hub.