gate-house ruled the v0.8 assent round (GH-DEC-2026-011, net-kingdom@64394e9): ask 1 declined, ask 2 adopted. Ask 1's refusal is accepted without reservation and the reason is better than the ask -- a sanctioned transitional fail_open is indistinguishable at runtime from the stance the rule forbids, and would make the rule optional at the only moment it costs anything. Ask 2 gave §13.1 a Coverage column with this repo's figures as its first entries. Since we asked for the column, we owe it accuracy: scripts/report_coverage.py measures both populations from the artifacts the runtime uses (reusing the workload-join build rather than re-deriving it), and a test asserts pep-stance.yaml's published block equals what it measures. A hand-counted number in a register that explicitly does not recompute it decays silently, and a stale figure beside a marked cell is worse than the blank the other four rows carry. pep-stance.yaml marks the unknown cell inline as a declared gap -- assent, the measured reason for not flipping, the declined ask, WARDEN-WP-0040 as route -- and a second test keeps it marked while it is fail_open, failing when it is flipped. standard_version stays 0.7 because that is what binds; v0.8 is proposed, so it gains standard_version_reviewed rather than pre-adopting. Separately, gate-house corrected GH-DEC-2026-008: the claim/decision digest comparison it originally required is unimplementable and a fail-closed consumer obeying it would have denied permanently. We had never copied the wording, so nothing to unwind -- but everything they have sent about this lane was living in an inbox thread, a bad home for a correction that only matters when someone finally wires the consume. Now wiki/ApprovalConsumption.md, leading with "nothing is wired", carrying the corrected target and the attribution gap that digest matching does not discharge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013EPuTc18FjU5WFqoSEKH3C Assistant: claude-code Assistant-Model: opus Assistant-Process: 1276224@bnt-lap001 Assistant-Session: 426ec497-e1c4-4dd3-b417-dfce1ca1dbc3
201 lines
8.4 KiB
Python
201 lines
8.4 KiB
Python
"""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"
|
|
assert d["standard_version"] == "0.7"
|
|
# §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"
|
|
|
|
def test_revocation_visibility_deadline_equals_enforced_ttl_policy(self):
|
|
"""§9.7.2: a published replay window must not drift from issuance."""
|
|
from warden.models import ActorType, MAX_TTL_HOURS
|
|
|
|
published = self._stance()["revocation_visibility"]
|
|
expected = {actor.value: MAX_TTL_HOURS[actor] for actor in ActorType}
|
|
assert published["deadline_hours"] == expected
|
|
assert published["mechanism"] == "ttl_expiry"
|
|
assert published["revocation_channel"] == "none"
|
|
|
|
def test_attributive_emission_cadence_deferral_carries_measurement(self):
|
|
cadence = self._stance()["emission_cadence"]
|
|
assert cadence["classification"] == "attributive"
|
|
assert cadence["status"] == "deferred"
|
|
assert cadence["observed_window"]["signature_records"] == 3
|
|
assert cadence["observed_window"]["active_signature_days"] == 2
|
|
assert cadence["reason"]
|
|
|
|
|
|
# --- classification coverage (v0.8 §6.4 obligation 3) -------------------------
|
|
|
|
def test_published_coverage_equals_measured_coverage():
|
|
"""The published figure must equal what the repo actually measures.
|
|
|
|
ops-warden asked gate-house for §13.1's Coverage column and its figures are
|
|
that column's first entries, so their accuracy is ours to hold. The register
|
|
explicitly does not compute anyone's coverage, and a stale number beside a
|
|
marked cell is worse than a blank -- a blank at least reads as "not reported".
|
|
|
|
This is the same property that makes the stance map worth publishing (the map
|
|
equals PolicyConfig.failure_modes by test), applied one level up.
|
|
"""
|
|
import importlib.util
|
|
|
|
repo = Path(__file__).resolve().parents[1]
|
|
spec = importlib.util.spec_from_file_location(
|
|
"report_coverage", repo / "scripts" / "report_coverage.py"
|
|
)
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
|
|
published = yaml.safe_load((repo / "pep-stance.yaml").read_text())[
|
|
"classification_coverage"
|
|
]
|
|
measured = module.measure()
|
|
|
|
for population in ("signing_targets", "routing_lanes"):
|
|
assert published[population] == measured[population], population
|
|
|
|
|
|
def test_the_unknown_cell_is_marked_as_a_declared_gap():
|
|
"""A non-conformant cell must say so where it is declared, not only in a review.
|
|
|
|
§11's marking obligation, which ops-warden argued for in the v0.6 round and
|
|
then acquired a marked cell under. If the cell is ever flipped to fail_closed
|
|
this test fails, which is the correct time to remove the marking.
|
|
"""
|
|
repo = Path(__file__).resolve().parents[1]
|
|
text = (repo / "pep-stance.yaml").read_text()
|
|
stance = yaml.safe_load(text)["stance"]
|
|
|
|
if stance["unknown"] == "fail_open":
|
|
assert "DECLARED GAP" in text
|
|
assert "WARDEN-WP-0040" in text
|
|
else:
|
|
assert stance["unknown"] == "fail_closed"
|