Ship WARDEN-WP-0030: delegation register for every catalog lane
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.
This commit is contained in:
parent
8d3706fa06
commit
c93e3c9b43
11 changed files with 619 additions and 29 deletions
|
|
@ -575,3 +575,137 @@ def test_route_show_json_includes_risk():
|
|||
assert payload["high_risk"] is True
|
||||
assert payload["resolvable"] is True
|
||||
assert payload["status"] == "active"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Delegation register (WARDEN-WP-0030)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_every_catalog_entry_declares_delegation():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
missing = [e.id for e in catalog.entries if e.delegation is None]
|
||||
assert missing == [], f"entries missing delegation block: {missing}"
|
||||
|
||||
|
||||
def test_every_proxy_declares_delegation():
|
||||
"""A new exec_capable proxy cannot land without answering the ownership question."""
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
missing = [
|
||||
e.id
|
||||
for e in catalog.entries
|
||||
if e.exec_capable and not e.warden_executes and e.delegation is None
|
||||
]
|
||||
assert missing == [], f"proxy lanes missing delegation: {missing}"
|
||||
|
||||
|
||||
def test_ssh_lane_is_permanent_delegation():
|
||||
e = load_catalog(_repo_catalog()).get("ssh-cert-host-access")
|
||||
assert e.delegation is not None
|
||||
assert e.delegation.mode == "permanent"
|
||||
assert e.delegation.intended_owner is None
|
||||
assert e.is_interim is False
|
||||
|
||||
|
||||
def test_native_exec_lanes_are_native_delegation():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
for eid, owner in (
|
||||
("whynot-design-npm-publish", "secrets-engine"),
|
||||
("ops-warden-warden-sign-token", "railiance-platform"),
|
||||
):
|
||||
e = catalog.get(eid)
|
||||
assert e.delegation is not None
|
||||
assert e.delegation.mode == "native"
|
||||
assert e.delegation.intended_owner == owner
|
||||
|
||||
|
||||
def test_founder_interim_lanes_classified():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
expected = {
|
||||
"rapp-qonto-keycape-client": "key-cape",
|
||||
"binky-company-email-imap": "tenant-engine",
|
||||
"binky-qonto-api": "tenant-engine",
|
||||
"railiance-backup-offsite-lane": "railiance-platform",
|
||||
"agent-harness-forgejo-deploy": "railiance-platform",
|
||||
}
|
||||
for eid, owner in expected.items():
|
||||
e = catalog.get(eid)
|
||||
assert e is not None and e.delegation is not None
|
||||
assert e.delegation.mode == "interim"
|
||||
assert e.delegation.intended_owner == owner
|
||||
assert e.delegation.blocked_on
|
||||
|
||||
|
||||
def test_missing_delegation_is_implicit_interim(tmp_path):
|
||||
catalog = load_catalog(_write_catalog(tmp_path, [dict(ROUTED_ENTRY)]))
|
||||
e = catalog.get("openbao-api-key")
|
||||
d = e.effective_delegation
|
||||
assert e.delegation is None
|
||||
assert d.implicit is True
|
||||
assert d.mode == "interim"
|
||||
assert d.intended_owner is None
|
||||
assert "unclassified" in (d.blocked_on or "")
|
||||
|
||||
|
||||
def test_interim_without_blocked_on_rejected(tmp_path):
|
||||
bad = dict(
|
||||
ROUTED_ENTRY,
|
||||
delegation={
|
||||
"mode": "interim",
|
||||
"intended_owner": "secrets-engine",
|
||||
"reviewed": "2026-08-15",
|
||||
},
|
||||
)
|
||||
with pytest.raises(CatalogError, match="blocked_on"):
|
||||
load_catalog(_write_catalog(tmp_path, [bad]))
|
||||
|
||||
|
||||
def test_non_permanent_without_owner_rejected(tmp_path):
|
||||
bad = dict(
|
||||
ROUTED_ENTRY,
|
||||
delegation={"mode": "native", "reviewed": "2026-08-15"},
|
||||
)
|
||||
with pytest.raises(CatalogError, match="intended_owner"):
|
||||
load_catalog(_write_catalog(tmp_path, [bad]))
|
||||
|
||||
|
||||
def test_invalid_delegation_mode_rejected(tmp_path):
|
||||
bad = dict(
|
||||
ROUTED_ENTRY,
|
||||
delegation={"mode": "maybe", "intended_owner": "x", "reviewed": "2026-08-15"},
|
||||
)
|
||||
with pytest.raises(CatalogError, match="delegation.mode"):
|
||||
load_catalog(_write_catalog(tmp_path, [bad]))
|
||||
|
||||
|
||||
def test_catalog_gaps_lists_only_interim():
|
||||
catalog = load_catalog(_repo_catalog())
|
||||
gap_ids = {e.id for e in catalog.gaps(include_draft=True)}
|
||||
assert "ssh-cert-host-access" not in gap_ids
|
||||
assert "whynot-design-npm-publish" not in gap_ids
|
||||
assert "binky-company-email-imap" in gap_ids
|
||||
assert "openbao-api-key" in gap_ids
|
||||
assert all(catalog.get(i).is_interim for i in gap_ids)
|
||||
|
||||
|
||||
def test_cli_route_gaps_json(repo_catalog_env):
|
||||
result = runner.invoke(app, ["route", "gaps", "--json"])
|
||||
assert result.exit_code == 0
|
||||
data = json.loads(result.stdout)
|
||||
assert data
|
||||
ids = {row["id"] for row in data}
|
||||
assert "binky-company-email-imap" in ids
|
||||
assert "ssh-cert-host-access" not in ids
|
||||
for row in data:
|
||||
assert row["mode"] == "interim"
|
||||
assert "intended_owner" in row
|
||||
assert "blocked_on" in row
|
||||
assert "days_since_review" in row
|
||||
|
||||
|
||||
def test_cli_route_show_includes_delegation(repo_catalog_env):
|
||||
result = runner.invoke(app, ["route", "show", "binky-qonto-api", "--json"])
|
||||
assert result.exit_code == 0
|
||||
data = json.loads(result.stdout)
|
||||
assert data["delegation"]["mode"] == "interim"
|
||||
assert data["delegation"]["intended_owner"] == "tenant-engine"
|
||||
assert data["delegation"]["implicit"] is False
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue