ops-warden/tests/test_case_attended_boundary.py
tegwick ae7bc73b4f
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
fix(case): preserve attended authority at dispatch and validate session lanes
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a1468b-63fa-7710-85dc-8f2e16b3ebfa
2026-10-17 20:31:16 +02:00

113 lines
4.7 KiB
Python

"""Synthetic attended admission/dispatch regressions; no owner/native actions."""
from dataclasses import replace
import pytest
from tests.test_case_admission_modes import admit, mode_step
from tests.test_case_run import fixture_catalog, lane_entry, make_rig
from warden.case_receipt_state import Outcome, Refused
from warden.case_type import check_follow_through
from warden.routing.catalog import CatalogError, _parse_entry, load_catalog
def attended(rig, entries):
return admit(rig, step=mode_step(False, True), entries=entries,
desc=dict(effect="change", revocation_scopes=("parent-session",)))
@pytest.mark.parametrize("operation", ["run", "rollback", "reconcile"])
@pytest.mark.parametrize("marker", ["agent-1", "", None])
def test_identity_change_refuses_before_any_write_or_callback(tmp_path, monkeypatch, operation, marker):
monkeypatch.delenv("WARDEN_AGENT_ID", raising=False)
rig = make_rig(tmp_path)
executor = rig[0]
admitted = attended(rig, [dict(lane_entry(), lane="login")])
executor.evidence_verifier = lambda *_: True
if operation == "rollback":
executor.run(*admitted)
elif operation == "reconcile":
old = executor.adapters[admitted[0].adapter]
def lost(_):
raise RuntimeError("synthetic lost reply")
executor.adapters[old.reference] = replace(old, invoke=lost)
executor.run(*admitted)
calls = []
old = executor.adapters[admitted[0].adapter]
callback = getattr(old, "invoke" if operation == "run" else operation)
def observed(*args):
calls.append(args)
return callback(*args)
executor.adapters[old.reference] = replace(old, **{
"invoke" if operation == "run" else operation: observed,
})
def rows():
return tuple(executor.journal.db.execute(f"SELECT COUNT(*) FROM {table}").fetchone()[0]
for table in ("intents", "receipts"))
before = rows()
if marker is None:
result = getattr(executor, operation)(*admitted)
assert result.last.outcome is {"run": Outcome.SUCCESS,
"rollback": Outcome.ROLLED_BACK,
"reconcile": Outcome.NO_CHANGE}[operation]
assert len(calls) == 1
assert rows() != before
return
monkeypatch.setenv("WARDEN_AGENT_ID", marker)
with pytest.raises(Refused, match="attended step requires a human parent session"):
getattr(executor, operation)(*admitted)
assert rows() == before
assert not calls
def entries_for(case):
change = dict(lane_entry(), lane="attended-change", session_lane="login-lane")
login = dict(lane_entry("login-lane"), lane="login")
if case == "missing":
return [change]
if case == "draft-login":
login["status"] = "draft"
elif case == "unreviewed-login":
login["reviewed"] = ""
elif case == "wrong-kind-login":
login["lane"] = "secret"
elif case == "draft-change":
change["status"] = "draft"
elif case == "unreviewed-change":
change["reviewed"] = ""
elif case == "missing-session-field":
del change["session_lane"]
elif case in ("secret", "ceremony"):
change["lane"] = case
del change["session_lane"]
return [change, login]
@pytest.mark.parametrize("case, code", [
("valid", None), ("missing", "LANE-KIND"), ("draft-login", "LANE-KIND"),
("unreviewed-login", "LANE-KIND"), ("wrong-kind-login", "LANE-KIND"),
("draft-change", "LANE-UNREVIEWED"), ("unreviewed-change", "LANE-UNREVIEWED"),
("secret", "LANE-KIND"), ("ceremony", "LANE-KIND"),
])
def test_attended_change_planner_and_executor_agree(tmp_path, monkeypatch, case, code):
monkeypatch.delenv("WARDEN_AGENT_ID", raising=False)
entries = entries_for(case)
path = tmp_path / "catalog.yaml"
path.write_bytes(fixture_catalog(*entries))
catalog = load_catalog(path)
step = dict(mode_step(False, True)[0], attended_justification="synthetic test",
entry_point="owner/test", auth="synthetic session", value_handling="none")
doc = {"spec": {"follow_through": [step], "rollback": [{"reverses": step["id"]}]}}
report = check_follow_through(doc, catalog)
assert [f.code for f in report.findings] == ([] if code is None else [code])
rig = make_rig(tmp_path)
if code:
with pytest.raises(Refused):
attended(rig, entries)
assert rig[0].journal.db.execute("SELECT COUNT(*) FROM receipts").fetchone()[0] == 0
else:
assert attended(rig, entries)[1].lane == "issuer-lane"
def test_attended_change_missing_session_is_parser_rejection():
with pytest.raises(CatalogError, match="must name session_lane"):
_parse_entry(entries_for("missing-session-field")[0], 0)