ops-warden/history/2026-08-28-security-layer-model-assent.md
tegwick 70d8b503f0
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assent to the NetKingdom security layer model (WARDEN-IN-0001)
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
2026-08-28 21:47:44 +02:00

8.7 KiB

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