ops-warden/pep-stance.yaml
tegwick baf53602ca Revert the npm field, re-measure coverage, and hold the layer divergence
Five inbox items worked, none of which changed a credential value or moved a
secret.

whynot-design-npm-publish: field reverted npm_token -> NPM_AUTH_TOKEN and the
path confirmed, on railiance-platform's attended, read-only, no-value field
enumeration (their docs/evidence/2026-09-10-npm-lane-field-resolution.json).
Exactly one field is present at the governed path. The 2026-09-09 change was
adopted from a coordination message and would have failed at the WP-0037-T03
rotation. The ungoverned second location is recorded as an explicit non-lane,
not deleted and not tidied away.

pep-stance coverage: published figures were stale by eight lanes (unknown
18->20, not_applicable 12->15) while resolved stayed at 3 — the denominator
moved, the classification did not. Caught by the test that asserts the published
block equals what report_coverage.py measures. tests/test_workload_join.py held
the same stale counts; both now measure the same populations.

rapp-qonto-keycape-client: blocker character updated — authority exists and is
unexercised by owner decision ("not yet", offer open), which is not the same as
no authority existing. Reopen triggers are events, never elapsed time.

flex-auth -> access-engine rename (WARDEN-IN-0003): access-engine added to the
policy-check lane's keywords so routing resolves under both names from today.
owner_repo deliberately not flipped — policy.py sends it as resource.system on
every /v1/check, and FLEX-DEC-2026-013 keeps runtime names as flex-auth.

layer declaration: INTENT.md says Staff, layer.yaml says staff, section 11 does
not say which governs. Neither changed; gate-house holds the ruling. Position in
docs/layer-declaration-precedence.md, wait in WARDEN-WP-0034-T06, and a comment
in layer.yaml telling the next session not to "fix" it — the divergence is the
evidence the ruling is made against.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 63291@bnt-lap001
Assistant-Session: 8bd77868-ca68-4f49-bb1e-d539ecc0d703
2026-09-21 02:16:33 +02:00

152 lines
7.3 KiB
YAML

# ops-warden — PEP unreachable-engine stance map
#
# Framework: net-kingdom/canon/standards/security-layer-model_v0.7.md §6.4, §9.3, §9.7
# 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
# v0.7 is the accepted standard and the one in force. v0.8 is `proposed`: its
# assent round closed 2026-09-09 (GH-DEC-2026-011) with nine corrections applied,
# but the version is not yet accepted, so this declaration stays pinned to what
# binds. The one cell v0.8 would change is marked inline below rather than
# silently pre-adopted.
standard_version: "0.7"
standard_version_reviewed: "0.8" # reviewed and assented; see history/2026-09-09-layer-model-v08-review.md
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
# DECLARED GAP under security-layer-model v0.8 §6.4 obligation 3 (GH-DEC-2026-011,
# net-kingdom@64394e9): unknown is not a zone and MUST resolve to fail_closed.
# ops-warden ASSENTED to that rule — we went looking for the §5.1 read-only
# diagnostic its reversal clause predicts and do not have one, because this map
# governs `warden sign`, a credential-issuing side effect.
#
# The cell has not been flipped, and the reason is measured rather than argued:
# 0 of 3 signing targets resolve to a zone, so converting today would fail closed
# on essentially every certificate whenever the engine is unreachable — including
# the certificate an operator needs to reach the host and repair it. That is
# ADR-0006's rejected configuration reached from another direction.
#
# We asked for a coverage-gated transitional fail_open and were DECLINED: a
# sanctioned transitional fail_open is indistinguishable at runtime from the
# stance the rule forbids. Our second preference was adopted instead — §13.1 now
# carries a Coverage column, and this repo's figures are its first entries.
#
# So this is tracked non-conformance with a route, not an exemption.
# Route: WARDEN-WP-0040. Register row: §13.1, marked.
unknown: fail_open # non-conformant at v0.8; see above
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.
# Classification coverage, published beside the stance because v0.8 §6.4
# obligation 3 now requires it and because ops-warden asked for the column.
# Coverage is DISCLOSURE, never a transitional licence: it does not soften this
# map's stance, does not gate it, and never makes the marked cell conformant.
# Self-measured; regenerate with `python scripts/report_coverage.py`.
# 2026-09-21 re-measure: routing lanes grew from 30 to 38 catalogued entries
# since 2026-09-09, so unknown rose 18 -> 20 and not-applicable 12 -> 15 while
# RESOLVED STAYED AT 3. Classification did not regress; the denominator moved.
# Signing targets are unchanged. Reported to gate-house per §13.1 — a figure in
# a register that cannot detect its own staleness is only as good as the last
# re-measure, and this one was stale by eight lanes before the test caught it.
classification_coverage:
measured: "2026-09-21"
attribution: self-measured
signing_targets:
resolved: 0
unknown: 3
not_applicable: 1
routing_lanes:
resolved: 3
unknown: 20
not_applicable: 15
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
# §9.7.2 — the certificate-verification PEP has no active revocation channel.
# A previously allowed certificate remains usable until its enforced TTL expires,
# so the visibility deadline is exactly the maximum issued lifetime per actor type.
revocation_visibility:
boundary: "SSH certificate verification at the target host"
mechanism: ttl_expiry
revocation_channel: none
deadline_hours:
adm: 48
agt: 24
atm: 8
note: >-
No CRL or KRL distribution exists. Host-side authorization belongs to
railiance-infra; shortening or actively recalling this window is a joint
design question, not an implied capability of ops-warden.
# §9.6 — signing evidence is attributive, not load-bearing. Measurement as of
# 2026-09-04 found three signature records across 79 calendar days, concentrated
# on only two active days (1 event on 2026-06-17; 2 within 40 minutes on
# 2026-08-22). That bursty operator-driven sample cannot support a useful rate
# threshold, so cadence is explicitly deferred instead of fabricated.
emission_cadence:
classification: attributive
status: deferred
measured_as_of: "2026-09-04"
observed_window:
first: "2026-06-17T23:18:33Z"
last: "2026-09-04T21:21:30Z"
signature_records: 3
active_signature_days: 2
daily_counts:
"2026-06-17": 1
"2026-08-22": 2
reason: "operator-driven issuance is too sparse and bursty for a meaningful rate threshold"