feat: adopt security zones and explicit workload refs
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0291a-1e87-7151-9934-fcbfe3f65eb1
This commit is contained in:
tegwick 2026-08-22 15:36:37 +02:00
parent 12c637cbf2
commit 7ce58ae638
52 changed files with 1547 additions and 658 deletions

View file

@ -84,13 +84,13 @@ def test_default_vault_token_env(tmp_path):
assert cfg.vault.token_env == "VAULT_TOKEN"
def test_policy_defaults_disabled(tmp_path):
def test_policy_defaults_to_unknown_zone_profile(tmp_path):
cfg_path = tmp_path / "warden.yaml"
write_yaml(cfg_path, {"backend": "local", "ca_key": str(tmp_path / "ca")})
cfg = load_config(cfg_path)
assert cfg.policy.enabled is False
assert cfg.policy.flex_auth_url == "http://127.0.0.1:8080"
assert cfg.policy.fail_closed is True
assert cfg.policy.flex_auth_url is None
assert cfg.policy.failure_modes["unknown"] == "fail_open"
assert cfg.policy.failure_modes["z3-critical"] == "fail_closed"
def test_policy_block_parsed(tmp_path):
@ -99,18 +99,30 @@ def test_policy_block_parsed(tmp_path):
"backend": "local",
"ca_key": str(tmp_path / "ca"),
"policy": {
"enabled": True,
"flex_auth_url": "http://flex-auth:8080",
"fail_closed": False,
"zone_registry_path": str(tmp_path / "zones.json"),
"failure_modes": {"z2-protected": "fail_closed"},
"tenant": "tenant:coulomb",
"subject_env": "MY_SUBJECT",
"system": "warden-test",
},
})
cfg = load_config(cfg_path)
assert cfg.policy.enabled is True
assert cfg.policy.flex_auth_url == "http://flex-auth:8080"
assert cfg.policy.fail_closed is False
assert cfg.policy.zone_registry_path == tmp_path / "zones.json"
assert cfg.policy.failure_modes["z2-protected"] == "fail_closed"
assert cfg.policy.tenant == "tenant:coulomb"
assert cfg.policy.subject_env == "MY_SUBJECT"
assert cfg.policy.system == "warden-test"
@pytest.mark.parametrize("retired", ["enabled", "fail_closed"])
def test_retired_global_policy_switches_are_rejected(tmp_path, retired):
cfg_path = tmp_path / "warden.yaml"
write_yaml(cfg_path, {
"backend": "local",
"ca_key": str(tmp_path / "ca"),
"policy": {retired: True},
})
with pytest.raises(ConfigError, match=f"policy.{retired}"):
load_config(cfg_path)

View file

@ -1,14 +1,11 @@
"""Tests for warden desk (WARDEN-WP-0029 T03)."""
from __future__ import annotations
import json
import threading
import urllib.error
import urllib.parse
import urllib.request
from http.server import ThreadingHTTPServer
from pathlib import Path
import pytest
from typer.testing import CliRunner

View file

@ -31,4 +31,53 @@ def test_build_registry_from_inventory_seed(tmp_path):
)
assert bridge["attributes"]["actor_type"] == "agt"
assert bridge["attributes"]["max_ttl_hours"] == 24
assert "agt-task-bridge" in bridge["attributes"]["allowed_principals"]
assert "agt-task-bridge" in bridge["attributes"]["allowed_principals"]
assert "trust_zone" not in bridge
assert bridge["attributes"]["security_zone"] == "unknown"
assert bridge["attributes"]["security_zone_admission"] == "unknown"
assert bridge["attributes"]["workload_id"] == "ops-bridge-tunnel"
human = next(
r
for r in registry["resource_manifests"][0]["resources"]
if r["id"] == "ssh-cert:actor/adm-example"
)
assert human["attributes"]["security_zone_admission"] == "not-applicable"
def test_compiler_joins_explicit_workload_reference_to_resolved_zone(tmp_path):
zones = tmp_path / "zones.json"
zones.write_text(json.dumps({
"records": [{
"workload_id": "ops-bridge-tunnel",
"declared_zone": "z2-continuity",
"admission": "satisfied",
"admission_reason": "admission_floor_met",
"effective_zone": "z2-continuity",
"membership_revision": "sha256:zone-revision",
}]
}))
out = tmp_path / "registry.json"
subprocess.run(
[
sys.executable,
str(SCRIPT),
str(INVENTORY),
"--zone-resolutions",
str(zones),
"-o",
str(out),
],
check=True,
cwd=ROOT,
)
registry = json.loads(out.read_text())
bridge = next(
r
for r in registry["resource_manifests"][0]["resources"]
if r["id"] == "ssh-cert:actor/agt-state-hub-bridge"
)
attrs = bridge["attributes"]
assert attrs["security_zone"] == "z2-continuity"
assert attrs["security_zone_admission"] == "satisfied"
assert attrs["security_zone_revision"] == "sha256:zone-revision"

View file

@ -7,7 +7,7 @@ import json
from typer.testing import CliRunner
from warden.cli import app
from warden.memory import activate, enabled, record_command_episode, status, store_path
from warden.memory import activate, record_command_episode, status, store_path
from warden.worker import RuleBrain, _plan_with_memory, build_plans
runner = CliRunner()
@ -140,4 +140,4 @@ def test_route_find_implicitly_activates_memory_without_explicit_command(tmp_pat
activation = ensure_memory_context(need="ssh tunnel", implicit=True)
assert activation is not None
assert activation.get("implicit") is True
assert status()["episode_count"] >= 1
assert status()["episode_count"] >= 1

View file

@ -27,6 +27,17 @@ def _spec(pubkey_path: Path) -> CertSpec:
)
def _zone_registry(tmp_path: Path, zone: str) -> Path:
path = tmp_path / "registry.json"
path.write_text(
'{"resource_manifests":[{"resources":[{"id":'
'"ssh-cert:actor/agt-state-hub-bridge","attributes":{'
f'"security_zone":"{zone}","security_zone_admission":"satisfied"'
'}}]}]}'
)
return path
def test_pubkey_fingerprint(tmp_path):
pubkey = tmp_path / "key.pub"
pubkey.write_text("ssh-ed25519 AAAA test\n")
@ -35,26 +46,32 @@ def test_pubkey_fingerprint(tmp_path):
assert len(fp) == 7 + 64
def test_disabled_returns_none(tmp_path):
def test_unconfigured_evaluator_uses_unknown_fail_open_profile(tmp_path):
pubkey = tmp_path / "key.pub"
pubkey.write_text("ssh-ed25519 AAAA\n")
cfg = PolicyConfig(enabled=False)
assert check_sign_policy(cfg, _spec(pubkey)) is None
cfg = PolicyConfig()
spec = _spec(pubkey)
assert check_sign_policy(cfg, spec) is None
assert spec.policy_zone == "unknown"
assert spec.policy_failure_mode == "fail_open"
assert spec.policy_outcome == "fail_open"
def test_allow_returns_decision_id(tmp_path):
pubkey = tmp_path / "key.pub"
pubkey.write_text("ssh-ed25519 AAAA\n")
cfg = PolicyConfig(enabled=True, flex_auth_url="http://flex-auth.test")
cfg = PolicyConfig(flex_auth_url="http://flex-auth.test")
mock_response = MagicMock()
mock_response.json.return_value = {"effect": "allow", "id": "dec-123"}
mock_response.raise_for_status = MagicMock()
spec = _spec(pubkey)
with patch("warden.policy.httpx.post", return_value=mock_response) as post:
result = check_sign_policy(cfg, _spec(pubkey))
result = check_sign_policy(cfg, spec)
assert result == "dec-123"
assert spec.policy_outcome == "allow"
post.assert_called_once()
call_kwargs = post.call_args
assert call_kwargs[0][0] == "http://flex-auth.test/v1/check"
@ -67,7 +84,7 @@ def test_allow_returns_decision_id(tmp_path):
def test_deny_raises_ca_error(tmp_path):
pubkey = tmp_path / "key.pub"
pubkey.write_text("ssh-ed25519 AAAA\n")
cfg = PolicyConfig(enabled=True)
cfg = PolicyConfig(flex_auth_url="http://flex-auth.test")
mock_response = MagicMock()
mock_response.json.return_value = {
@ -84,7 +101,10 @@ def test_deny_raises_ca_error(tmp_path):
def test_unreachable_fail_closed_raises(tmp_path):
pubkey = tmp_path / "key.pub"
pubkey.write_text("ssh-ed25519 AAAA\n")
cfg = PolicyConfig(enabled=True, fail_closed=True)
cfg = PolicyConfig(
flex_auth_url="http://flex-auth.test",
zone_registry_path=_zone_registry(tmp_path, "z3-critical"),
)
with patch(
"warden.policy.httpx.post",
@ -97,7 +117,7 @@ def test_unreachable_fail_closed_raises(tmp_path):
def test_unreachable_fail_open_returns_none(tmp_path):
pubkey = tmp_path / "key.pub"
pubkey.write_text("ssh-ed25519 AAAA\n")
cfg = PolicyConfig(enabled=True, fail_closed=False)
cfg = PolicyConfig(flex_auth_url="http://flex-auth.test")
with patch(
"warden.policy.httpx.post",
@ -109,7 +129,10 @@ def test_unreachable_fail_open_returns_none(tmp_path):
def test_http_error_fail_closed_raises(tmp_path):
pubkey = tmp_path / "key.pub"
pubkey.write_text("ssh-ed25519 AAAA\n")
cfg = PolicyConfig(enabled=True, fail_closed=True)
cfg = PolicyConfig(
flex_auth_url="http://flex-auth.test",
zone_registry_path=_zone_registry(tmp_path, "z3-critical"),
)
mock_response = MagicMock()
mock_response.status_code = 403
@ -123,7 +146,7 @@ def test_http_error_fail_closed_raises(tmp_path):
def test_missing_pubkey_raises(tmp_path):
cfg = PolicyConfig(enabled=True)
cfg = PolicyConfig(flex_auth_url="http://flex-auth.test")
spec = _spec(tmp_path / "missing.pub")
with pytest.raises(CAError, match="Public key not found"):
check_sign_policy(cfg, spec)
@ -132,7 +155,10 @@ def test_missing_pubkey_raises(tmp_path):
def test_subject_from_env(tmp_path, monkeypatch):
pubkey = tmp_path / "key.pub"
pubkey.write_text("ssh-ed25519 AAAA\n")
cfg = PolicyConfig(enabled=True, subject_env="WARDEN_POLICY_SUBJECT")
cfg = PolicyConfig(
flex_auth_url="http://flex-auth.test",
subject_env="WARDEN_POLICY_SUBJECT",
)
monkeypatch.setenv("WARDEN_POLICY_SUBJECT", "iam:bernd")
mock_response = MagicMock()
@ -212,7 +238,7 @@ def test_sign_policy_sends_authorization_header(tmp_path, monkeypatch):
pubkey.write_text("ssh-ed25519 AAAA test\n")
cfg = PolicyConfig(
enabled=True,
flex_auth_url="http://flex-auth.test",
caller_auth=CallerAuthConfig(mode="file", token_path=token_file),
)
spec = CertSpec(
@ -250,8 +276,8 @@ def test_sign_policy_fail_closed_when_caller_token_unavailable(tmp_path):
pubkey = tmp_path / "id.pub"
pubkey.write_text("ssh-ed25519 AAAA test\n")
cfg = PolicyConfig(
enabled=True,
fail_closed=True,
flex_auth_url="http://flex-auth.test",
zone_registry_path=_zone_registry(tmp_path, "z3-critical"),
caller_auth=CallerAuthConfig(mode="file", token_path=tmp_path / "absent"),
)
spec = CertSpec(
@ -263,3 +289,21 @@ def test_sign_policy_fail_closed_when_caller_token_unavailable(tmp_path):
)
with pytest.raises(CAError, match="caller identity unavailable"):
policy_mod.check_sign_policy(cfg, spec)
def test_advisory_decision_is_recorded_and_does_not_block(tmp_path):
pubkey = tmp_path / "id.pub"
pubkey.write_text("ssh-ed25519 AAAA test\n")
cfg = PolicyConfig(flex_auth_url="http://flex-auth.test")
response = MagicMock()
response.json.return_value = {
"effect": "audit_only",
"reason": "advisory_would_deny_disallowed_principal",
"id": "decision:advisory",
}
response.raise_for_status = MagicMock()
spec = _spec(pubkey)
with patch("warden.policy.httpx.post", return_value=response):
assert check_sign_policy(cfg, spec) == "decision:advisory"
assert spec.policy_zone == "unknown"
assert spec.policy_outcome == "audit_only"

View file

@ -193,7 +193,6 @@ def _warden_yaml(tmp_path: Path) -> Path:
(tmp_path / "ca").write_text("")
cfg.write_text(
f"backend: local\nca_key: {tmp_path/'ca'}\nstate_dir: {tmp_path/'state'}\n"
"policy:\n enabled: false\n"
)
return cfg
@ -203,10 +202,11 @@ def _proxy_env(monkeypatch, tmp_path):
monkeypatch.setenv("WARDEN_CONFIG", str(_warden_yaml(tmp_path)))
def test_cli_proxy_refuses_without_policy_ack(monkeypatch, tmp_path):
def test_cli_proxy_unknown_zone_fail_open_reaches_transport_guard(monkeypatch, tmp_path):
_proxy_env(monkeypatch, tmp_path)
monkeypatch.setenv("VAULT_TOKEN", "caller")
# subprocess must never run if the gate blocks first.
# The unknown-zone profile proceeds when no evaluator is configured, then
# the independent safe-transport boundary still refuses captured stdout.
monkeypatch.setattr(
"warden.proxy.subprocess.run",
lambda *a, **k: (_ for _ in ()).throw(AssertionError("fetch ran despite gate")),
@ -216,8 +216,8 @@ def test_cli_proxy_refuses_without_policy_ack(monkeypatch, tmp_path):
["access", "npm", "--domain", "coulomb_social", "--field", "NPM_AUTH_TOKEN",
"--path", "platform/x/y/z", "--fetch"],
)
assert r.exit_code == 4
assert "not enforced" in r.stdout or "not enforced" in str(r.output)
assert r.exit_code == 6
assert "unknown-zone fail_open" in r.output
def test_cli_proxy_requires_caller_auth(monkeypatch, tmp_path):
@ -228,11 +228,27 @@ def test_cli_proxy_requires_caller_auth(monkeypatch, tmp_path):
r = runner.invoke(
app,
["access", "npm", "--domain", "coulomb_social", "--field", "NPM_AUTH_TOKEN",
"--path", "platform/x/y/z", "--fetch", "--no-policy"],
"--path", "platform/x/y/z", "--fetch"],
)
assert r.exit_code == 3
def test_cli_proxy_rejects_retired_no_policy_bypass(monkeypatch, tmp_path):
_proxy_env(monkeypatch, tmp_path)
monkeypatch.setenv("VAULT_TOKEN", "caller")
monkeypatch.setattr(
"warden.proxy.subprocess.run",
lambda *a, **k: (_ for _ in ()).throw(AssertionError("fetch ran despite retired flag")),
)
r = runner.invoke(
app,
["access", "npm", "--domain", "coulomb_social", "--field", "NPM_AUTH_TOKEN",
"--path", "platform/x/y/z", "--fetch", "--no-policy"],
)
assert r.exit_code == 2
assert "--no-policy is retired" in r.output
# --- T4: login lane --------------------------------------------------------
def test_cli_login_lane_runs_without_token_or_policy_ack(monkeypatch, tmp_path):
@ -281,6 +297,7 @@ def test_invalid_lane_rejected(tmp_path):
id="x", title="t", need_keywords=["k"], owner_repo="o", subsystem="s",
warden_executes=False, wiki_ref="w", canon_ref="c", reviewed="2026-06-27",
status="active", lane="bogus",
workload_ref={"applicability": "not-applicable", "reason": "fixture"},
)
p = tmp_path / "c.yaml"
p.write_text(yaml.dump({"version": 1, "entries": [entry]}))
@ -361,7 +378,7 @@ def test_access_fetch_to_nonterminal_stdout_is_refused(tmp_path, monkeypatch):
lambda *a, **k: (_ for _ in ()).throw(AssertionError("fetch ran despite stdout guard")),
)
# CliRunner captures stdout (not a tty), so the guard trips without --unsafe-stdout.
r = runner.invoke(app, ["access", "whynot-design-npm-publish", "--fetch", "--no-policy"])
r = runner.invoke(app, ["access", "whynot-design-npm-publish", "--fetch"])
assert r.exit_code == 6
assert "sanctioned transport" in r.output.lower() or "refusing" in r.output.lower()
@ -378,7 +395,7 @@ def test_access_fingerprint_masks_and_bypasses_stdout_guard(monkeypatch, tmp_pat
monkeypatch.setattr("warden.proxy.subprocess.run", lambda *a, **k: _Fake())
r = runner.invoke(
app,
["access", "whynot-design-npm-publish", "--fingerprint", "--no-policy"],
["access", "whynot-design-npm-publish", "--fingerprint"],
)
assert r.exit_code == 0
assert "top-secret-token-value" not in r.output # value never shown
@ -395,7 +412,7 @@ def test_access_agent_high_risk_raw_stream_refused(tmp_path, monkeypatch):
app,
[
"access", "railiance-backup-offsite-lane",
"--fetch", "--no-policy", "--unsafe-stdout",
"--fetch", "--unsafe-stdout",
],
)
assert r.exit_code == 7, r.output
@ -415,7 +432,7 @@ def test_access_agent_high_risk_fingerprint_allowed(tmp_path, monkeypatch):
monkeypatch.setattr("warden.proxy.subprocess.run", lambda *a, **k: _Fake())
r = runner.invoke(
app,
["access", "railiance-backup-offsite-lane", "--fingerprint", "--no-policy"],
["access", "railiance-backup-offsite-lane", "--fingerprint"],
)
assert r.exit_code == 0, r.output
assert "should-not-appear" not in r.output

View file

@ -4,6 +4,7 @@ No test here requires a live subsystem — routing is a read-only pointer layer.
"""
import json
import re
from datetime import date
from pathlib import Path
import pytest
@ -11,10 +12,9 @@ import yaml
from typer.testing import CliRunner
from warden.cli import app
from datetime import date
from warden.routing import CatalogError, load_catalog
from warden.routing.catalog import days_since_review, find_catalog_path, is_review_stale
from warden.scorecard import check_catalog_rotation_coverage
runner = CliRunner()
@ -40,6 +40,10 @@ SSH_ENTRY = {
"canon_ref": "net-kingdom/docs/x.md",
"reviewed": "2026-06-18",
"status": "active",
"workload_ref": {
"applicability": "not-applicable",
"reason": "generic certificate action",
},
"cert_command": "warden sign <actor> --pubkey <path>",
"steps": ["confirm inventory", "sign"],
}
@ -55,6 +59,10 @@ ROUTED_ENTRY = {
"canon_ref": "net-kingdom/docs/x.md",
"reviewed": "2026-06-18",
"status": "active",
"workload_ref": {
"applicability": "not-applicable",
"reason": "generic credential pattern",
},
}
@ -76,6 +84,45 @@ def test_real_catalog_has_one_executed_lane():
assert [e.id for e in executed] == ["ssh-cert-host-access"]
def test_every_catalog_lane_declares_workload_applicability():
catalog = load_catalog(_repo_catalog())
assert all(entry.workload_ref is not None for entry in catalog.entries)
assert {entry.workload_ref.resolution for entry in catalog.entries} == {
"resolved", "unknown", "not-applicable"
}
def test_managed_and_operational_workload_references_parse():
catalog = load_catalog(_repo_catalog())
managed = catalog.get("issue-core-ingestion-api-key").workload_ref
assert managed.resolution == "resolved"
assert (managed.rapp_id, managed.name, managed.deployable) == (
"rapp-issue-core", "issue-core", "issue-core"
)
operational = catalog.get("ops-warden-warden-sign-token").workload_ref
assert operational.resolution == "resolved"
assert operational.rapp_id is None
assert operational.name == "ops-warden"
assert operational.declaration_ref == "tenancy.yaml"
def test_workload_reference_rejects_ambiguous_absence(tmp_path):
bad = dict(ROUTED_ENTRY)
bad.pop("workload_ref")
with pytest.raises(CatalogError, match="workload_ref"):
load_catalog(_write_catalog(tmp_path, [bad]))
def test_workload_reference_rejects_malformed_managed_target(tmp_path):
bad = dict(ROUTED_ENTRY)
bad["workload_ref"] = {
"applicability": "applicable",
"rapp_id": "rapp-issue-core",
}
with pytest.raises(CatalogError, match="requires name"):
load_catalog(_write_catalog(tmp_path, [bad]))
def test_ops_warden_warden_sign_lane_has_native_exec():
"""RAILIANCE-WP-0005 T08 — broker lane routes to railiance-platform credential exec."""
catalog = load_catalog(_repo_catalog())
@ -454,9 +501,6 @@ def test_every_entry_has_reviewed_date():
# Rotation / re-establishment guidance registry (WARDEN-WP-0026 T06)
# ---------------------------------------------------------------------------
from warden.scorecard import check_catalog_rotation_coverage
def test_every_active_vending_lane_has_rotation_guidance():
"""Coverage gate: an active lane that vends a secret must say how to renew it."""
catalog = load_catalog(_repo_catalog())
@ -774,6 +818,32 @@ def test_unrecognised_grade_is_treated_as_high():
assert entry.is_graded is False
def test_ungraded_risk_uses_maturity_derived_zone_default():
entry = _bare_entry()
assert entry.risk_for_zone(
effective_zone="z0-experimental",
admission="satisfied",
synthetic_only=True,
) == "standard"
assert entry.risk_for_zone(
effective_zone="z0-experimental",
admission="unknown",
synthetic_only=True,
) == "high"
assert entry.risk_for_zone(
effective_zone="z3-critical",
admission="satisfied",
) == "critical"
assert entry.risk_for_zone(effective_zone="unknown") == "high"
def test_explicit_risk_grade_always_wins_over_zone_default():
entry = _bare_entry(risk="standard")
assert entry.risk_for_zone(
effective_zone="z3-critical", admission="satisfied"
) == "standard"
def test_low_risk_vocabulary_is_explicit():
for grade in ("standard", "low", "accepted"):
entry = _bare_entry(risk=grade)
@ -870,6 +940,11 @@ def test_cli_route_gaps_fail_on_stale_exits_3(repo_catalog_env):
assert result.exit_code == 3
rows = json.loads(result.stdout)
assert any(r["stale"] for r in rows)
# A lane can be stale on age or on never having been verified; both must be
# expressible, or asked-and-waiting silently passes the gate.
assert any(r["stale"] and r["days_since_review"] == 0 for r in rows)
# A freshly reviewed lane can still be stale because it was never verified;
# asked-and-waiting must not silently pass the gate as the calendar moves.
assert any(
r["stale"]
and r["days_since_review"] <= 1
and r["verified"] == "asked-and-waiting"
for r in rows
)

View file

@ -1,10 +1,6 @@
"""Tests for EXPOSED taint convention (WARDEN-WP-0026 T05)."""
from __future__ import annotations
import json
from pathlib import Path
import pytest
from typer.testing import CliRunner
from warden.cli import app

View file

@ -0,0 +1,52 @@
"""Explicit lane-to-workload join tests (WARDEN-WP-0032 / RMGR-WP-0010-T06)."""
from pathlib import Path
import yaml
from scripts.report_workload_join import build
ROOT = Path(__file__).resolve().parents[1]
def test_repo_catalog_uses_only_explicit_workload_references():
report = build(ROOT / "registry/routing/catalog.yaml", Path.home())
assert report["ok"] is True
assert len(report["resolved"]) == 3
assert len(report["unknown"]) == 17
assert len(report["not_applicable"]) == 7
assert {row["lane"] for row in report["resolved"]} == {
"ops-warden-warden-sign-token",
"issue-core-ingestion-api-key",
"rapp-qonto-keycape-client",
}
def test_invalid_exact_deployable_resolves_unknown(tmp_path):
rapp = tmp_path / "rapp-x" / "declarations"
rapp.mkdir(parents=True)
(rapp / "rapp.yaml").write_text(yaml.safe_dump({
"rapp_id": "rapp-x",
"workload_identity": {"name": "x"},
"composition": {"member_repos": [{"deployables": ["api"]}]},
}))
catalog_dir = tmp_path / "ops-warden" / "registry" / "routing"
catalog_dir.mkdir(parents=True)
catalog = catalog_dir / "catalog.yaml"
catalog.write_text(yaml.safe_dump({"entries": [{
"id": "x",
"workload_ref": {
"applicability": "applicable",
"rapp_id": "rapp-x",
"name": "x",
"deployable": "missing",
},
}]}))
posture = catalog_dir.parent / "policy"
posture.mkdir()
(posture / "security-posture.yaml").write_text("dataclass_floor: {}\n")
report = build(catalog, tmp_path)
assert not report["resolved"]
assert report["unknown"][0]["lane"] == "x"
assert "deployable" in report["unknown"][0]["reason"]