atlas-iac/testing/tests/test_release_soteria_publication_retry.py

261 lines
11 KiB
Python

"""Fail-closed coverage for the one-time Soteria publication release."""
from __future__ import annotations
import json
import hashlib
import sqlite3
import sys
from contextlib import contextmanager, nullcontext
from pathlib import Path
from types import SimpleNamespace
import pytest
from testing.tests.test_hermes_cli_support import _load
ROOT = Path(__file__).parents[2]
sys.path.insert(0, str(ROOT / "services/hermes/scm-common/scripts"))
release = _load("release_soteria_publication_retry")
def _receipt() -> dict:
return {
"source": {
"board": release.BOARD,
"task_id": release.CHILD,
"root_task_id": release.ROOT,
"run_id": release.SOURCE_RUN,
"worker_ordinal": release.ORDINAL,
},
"head": release.PRESERVED_HEAD,
"result_digest": release.RECEIPT_DIGEST,
"title": "Replace cache literals safely.",
"body": "Preserved validation evidence.",
}
def _pool(tmp_path: Path, *, active: bool = False, digest: str | None = None, run_id: str = release.FAILED_RUN) -> tuple[Path, str]:
"""Create only the terminal pool columns consumed by the release guard."""
database = tmp_path / "pool.db"
connection = sqlite3.connect(database)
connection.execute(
"CREATE TABLE assignments(board,task_id,run_id,payload_json,result_json,result_digest,state,worker_ordinal,attempt)"
)
resume = {"source": {"run_id": release.SOURCE_RUN, "worker_ordinal": 0}, "head": release.PRESERVED_HEAD}
result = {
"structured": {"status": "blocked"}, "returncode": 1,
"capacity_failure": False, "scm_submission": None,
}
encoded = json.dumps(result, separators=(",", ":"))
actual_digest = hashlib.sha256(encoded.encode()).hexdigest()
connection.execute(
"INSERT INTO assignments VALUES(?,?,?,?,?,?,?,?,?)",
(release.BOARD, release.CHILD, run_id, json.dumps({"scm_resume": resume}), encoded,
digest or actual_digest, "finalized", 0, 1),
)
if active:
connection.execute(
"INSERT INTO assignments VALUES(?,?,?,?,?,?,?,?,?)",
(release.BOARD, release.CHILD, "11", "{}", "{}", "", "assigned", 0, 1),
)
connection.commit()
connection.close()
return database, actual_digest
def _native(monkeypatch, *, event=None, latest=None, status="blocked", block_kind="capability"):
"""Install the actual scalar contract expected from the native adapter."""
event = event or (release.FAILED_EVENT_ID, int(release.FAILED_RUN), "blocked")
latest = latest or (int(release.FAILED_RUN), "blocked", "blocked")
state = SimpleNamespace(
task=SimpleNamespace(status=status, current_run_id=None, block_kind=block_kind),
event=event, latest=latest,
)
class Connection:
def execute(self, statement, _args):
row = state.event if "task_events" in statement else state.latest
return SimpleNamespace(fetchone=lambda: row)
def close(self):
return None
native = SimpleNamespace(
scoped_current_board=lambda _board: nullcontext(), connect=lambda **_kwargs: Connection(),
get_task=lambda _connection, _task_id: state.task,
parent_ids=lambda _connection, _task_id: [release.ROOT],
)
monkeypatch.setitem(sys.modules, "hermes_cli", SimpleNamespace(kanban_db=native))
monkeypatch.setitem(sys.modules, "hermes_cli.kanban_db", native)
return state
def _receipt_state(monkeypatch, receipt: dict, *, issued: str = release.FAILED_RUN):
"""Supply the exact sidecar rows without accepting arbitrary metadata."""
retry = (release.SOURCE_RUN, 0, issued, "", 1, release.RETRY_AFTER, "9")
provenance = (release.SOURCE_RAW_SHA, "normalized-title-from-sealed-receipt-sha256:" + "a" * 64)
class Connection:
def execute(self, statement, _args):
row = retry if "publication_retries" in statement else provenance
return SimpleNamespace(fetchone=lambda: row)
monkeypatch.setattr(release.supervisor_state, "publication_retry", lambda *_args: receipt)
monkeypatch.setattr(release.supervisor_state, "_connect", lambda _board: nullcontext(Connection()))
def _remote(monkeypatch, *, head: str = release.REMOTE_HEAD):
"""Return a scalar broker PR response without contacting a live broker."""
value = {"state": "open", "merged": False, "head": {"ref": release.BRANCH, "sha": head}, "base": {"ref": "main"}}
monkeypatch.setattr(release.scm_broker_client, "read", lambda _path: json.dumps(value).encode())
def test_exact_historical_fixture_passes_all_release_guards(tmp_path, monkeypatch):
"""The copied run-10/native/receipt fixture admits only its reviewed form."""
pool, digest = _pool(tmp_path)
monkeypatch.setattr(release, "FAILED_RESULT_SHA", digest)
_native(monkeypatch)
_receipt_state(monkeypatch, _receipt())
_remote(monkeypatch)
release._pool_guard(pool, release.FAILED_RUN)
release._native_guard(release.FAILED_RUN, release.FAILED_EVENT_ID, "blocked", "blocked")
release._receipt_guard(release.FAILED_RUN)
release._remote_guard()
@pytest.mark.parametrize("change", ["later_event", "changed_receipt", "changed_head", "terminal_digest", "active"])
def test_conflicting_evidence_fails_closed_without_a_release(tmp_path, monkeypatch, change):
"""A later action or altered evidence cannot pass the operator preconditions."""
receipt = _receipt()
pool, digest = _pool(tmp_path, active=change == "active", digest="f" * 64 if change == "terminal_digest" else None)
monkeypatch.setattr(release, "FAILED_RESULT_SHA", digest if change != "terminal_digest" else "e" * 64)
state = _native(monkeypatch, event=(210, None, "blocked") if change == "later_event" else None)
if change == "changed_receipt":
receipt["result_digest"] = "e" * 64
_receipt_state(monkeypatch, receipt)
_remote(monkeypatch, head="d" * 40 if change == "changed_head" else release.REMOTE_HEAD)
with pytest.raises(ValueError):
if change in {"terminal_digest", "active"}:
release._pool_guard(pool, release.FAILED_RUN)
elif change == "later_event":
assert state.event[0] == 210
release._native_guard(release.FAILED_RUN, release.FAILED_EVENT_ID, "blocked", "blocked")
elif change == "changed_receipt":
release._receipt_guard(release.FAILED_RUN)
else:
release._remote_guard()
def test_exact_cas_release_is_repeatable_and_preserves_budget_and_provenance(tmp_path, monkeypatch):
"""A crash before native unblock can retry the CAS without spending another budget."""
state_db = tmp_path / "state.db"
connection = sqlite3.connect(state_db)
connection.executescript(
"CREATE TABLE publication_retries(board,child_task_id,source_run_id,source_ordinal,issued_run_id,"
"resolved_run_id,reissue_count,retry_after,last_reissued_run_id);"
"CREATE TABLE publication_retry_provenance(board,child_task_id,raw_result_sha256,reconstruction);"
)
connection.execute(
"INSERT INTO publication_retries VALUES(?,?,?,?,?,?,?,?,?)",
(release.BOARD, release.CHILD, release.SOURCE_RUN, 0, release.FAILED_RUN, "", 1, release.RETRY_AFTER, "9"),
)
connection.execute(
"INSERT INTO publication_retry_provenance VALUES(?,?,?,?)",
(release.BOARD, release.CHILD, release.SOURCE_RAW_SHA, "normalized-title-from-sealed-receipt-sha256:" + "a" * 64),
)
connection.commit()
connection.close()
@contextmanager
def connect(_board):
connection = sqlite3.connect(state_db)
try:
yield connection
connection.commit()
finally:
connection.close()
for name in ("_pool_guard", "_native_guard", "_receipt_guard", "_remote_guard"):
monkeypatch.setattr(release, name, lambda *_args: None)
monkeypatch.setattr(release.supervisor_state, "_connect", connect)
assert release.release(tmp_path / "unused.db") is True
assert release.release(tmp_path / "unused.db") is False
connection = sqlite3.connect(state_db)
retry = connection.execute("SELECT issued_run_id,reissue_count,retry_after,last_reissued_run_id FROM publication_retries").fetchone()
provenance = connection.execute("SELECT raw_result_sha256,reconstruction FROM publication_retry_provenance").fetchone()
connection.close()
assert retry == ("", 1, release.RETRY_AFTER, "9")
assert provenance[0] == release.SOURCE_RAW_SHA
def test_published_confirmation_requires_run11_triage_and_exact_pr_prose(tmp_path, monkeypatch):
"""The post-push recovery accepts only the unchanged run-11 confirmation."""
pool, digest = _pool(tmp_path, run_id=release.CONFIRM_RUN)
monkeypatch.setattr(release, "FAILED_RESULT_SHA", digest)
_native(
monkeypatch,
event=(release.CONFIRM_EVENT_ID, int(release.CONFIRM_RUN), "block_loop_detected"),
latest=(int(release.CONFIRM_RUN), "blocked", "blocked"),
status="triage",
)
receipt = _receipt()
_receipt_state(monkeypatch, receipt, issued=release.CONFIRM_RUN)
pull = {
"state": "open", "merged": False,
"head": {"ref": release.BRANCH, "sha": release.PRESERVED_HEAD},
"base": {"ref": "main"},
"title": release._draft_title(receipt["title"]), "body": receipt["body"],
}
monkeypatch.setattr(release.scm_broker_client, "read", lambda _path: json.dumps(pull).encode())
release._pool_guard(pool, release.CONFIRM_RUN)
release._native_guard(release.CONFIRM_RUN, release.CONFIRM_EVENT_ID, "triage", "block_loop_detected")
release._published_remote_guard(release._receipt_guard(release.CONFIRM_RUN))
pull["body"] = "changed"
with pytest.raises(ValueError, match="published pull"):
release._published_remote_guard(receipt)
def test_published_confirmation_cas_is_repeatable_without_spending_budget(tmp_path, monkeypatch):
"""A crash before native triage specification leaves one harmless rerun path."""
state_db = tmp_path / "state.db"
connection = sqlite3.connect(state_db)
connection.execute(
"CREATE TABLE publication_retries(board,child_task_id,source_run_id,source_ordinal,issued_run_id,"
"resolved_run_id,reissue_count,retry_after,last_reissued_run_id)"
)
connection.execute(
"INSERT INTO publication_retries VALUES(?,?,?,?,?,?,?,?,?)",
(release.BOARD, release.CHILD, release.SOURCE_RUN, 0, release.CONFIRM_RUN, "", 1, release.RETRY_AFTER, "9"),
)
connection.commit()
connection.close()
@contextmanager
def connect(_board):
connection = sqlite3.connect(state_db)
try:
yield connection
connection.commit()
finally:
connection.close()
monkeypatch.setattr(release, "_pool_guard", lambda *_args: None)
monkeypatch.setattr(release, "_native_guard", lambda *_args: None)
monkeypatch.setattr(release, "_receipt_guard", lambda *_args: {})
monkeypatch.setattr(release, "_published_remote_guard", lambda *_args: None)
monkeypatch.setattr(release.supervisor_state, "_connect", connect)
assert release.confirm_published_release(tmp_path / "unused.db") is True
assert release.confirm_published_release(tmp_path / "unused.db") is False
connection = sqlite3.connect(state_db)
row = connection.execute("SELECT issued_run_id,reissue_count,retry_after,last_reissued_run_id FROM publication_retries").fetchone()
connection.close()
assert row == ("", 1, release.RETRY_AFTER, "9")