Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 21 additions & 14 deletions hermes_cli/kanban_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,26 +242,32 @@
# back to zero mutation. The worker toolset can NEVER stamp the kernel identity;
# only this host-level finalizer code does.

# Pinned source-byte sha256 of the frozen aion-governance modules. These are
# verified BEFORE compile/exec; a module merely self-declaring the expected
# contract constant is insufficient — both the bytes and the contract hash are
# independently verified.
# Immutable authority for this module set: aion-governance PR #917, independently
# approved at the exact head below and merged as the exact commit below. The
# source-byte hashes are verified BEFORE compile/exec; a module merely
# self-declaring the expected contract constant is insufficient — both the bytes
# and the contract hash are independently verified.
AION_GOVERNANCE_AUTHORITY_PR = 917
AION_GOVERNANCE_AUTHORITY_HEAD = "44d4c221468d4035e078a6bfbcd4e8a25de4850a"
AION_GOVERNANCE_AUTHORITY_COMMIT = "15e6c82f4020c53cdba511c1e7ca31bab1bfe6bb"
AION_GOVERNANCE_KERNEL_SHA256 = (
"402d7882786093a96826601bfa443fa24efa681b18d94f7d3e8ed1d0cc4d32dc"
)
AION_GOVERNANCE_TYPED_ADAPTERS_SHA256 = (
"fc36d5b6d9b0edf1148ab99e2288f02b960abb3a9ebfd6ea2ef0d4b7b494b092"
)
AION_GOVERNANCE_RECEIPT_BINDER_SHA256 = (
"8099344b8d4b4096ca74e2dda885fcc070bc76108305b802c699cd94b8d4a937"
"5c8e6b517a390fd2d826d464036fc4e4da3f8ed4a9d1d0313f809bac3b1682be"
)

# Default candidate source directory for the pinned aion-governance modules
# (override with AION_GOVERNANCE_SOURCE_DIR). Any directory is safe because the
# loader single-reads and sha-verifies each module before compile/exec.
# Deterministic frozen-install contract for the pinned modules. Never implicitly
# select the mutable /root/aion-governance checkout: operators may install the
# exact PR #917 merge bytes at this content-addressed path, or explicitly point
# AION_GOVERNANCE_SOURCE_DIR at another byte source. In either case the approved
# per-module hashes above — not the directory or working-tree state — are the
# semantic authority.
AION_GOVERNANCE_DEFAULT_SOURCE_DIRS = (
"/root/aion-governance",
"/usr/local/lib/aion-governance",
f"/usr/local/lib/aion-governance/{AION_GOVERNANCE_AUTHORITY_COMMIT}",
)


Expand Down Expand Up @@ -5803,10 +5809,11 @@ def _aion_factory_finalizer_enabled() -> bool:
def _aion_governance_source_dir() -> Optional[Path]:
"""Resolve the pinned aion-governance source directory.

``AION_GOVERNANCE_SOURCE_DIR`` (absolute path) wins; otherwise the first
configured default directory that contains the kernel module. The loader
single-reads and sha-verifies each module before compile/exec, so even a
mutable checkout is safe (drift => hash mismatch => fail closed).
An explicit ``AION_GOVERNANCE_SOURCE_DIR`` wins; otherwise resolve only the
content-addressed frozen-install path for the approved PR #917 merge. The
mutable checkout is deliberately not an implicit candidate. The loader then
single-reads and sha-verifies every module before compile/exec, so any source
drift still fails closed.
"""
raw = os.environ.get("AION_GOVERNANCE_SOURCE_DIR")
if raw:
Expand Down
124 changes: 113 additions & 11 deletions tests/hermes_cli/test_kanban_factory_finalizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@
from hermes_cli import kanban_db as kb


_PR917_AUTHORITY_COMMIT = "15e6c82f4020c53cdba511c1e7ca31bab1bfe6bb"
_PR917_MODULES = {
"scripts/aion_monarch_outcome_proof_gate.py": (
"402d7882786093a96826601bfa443fa24efa681b18d94f7d3e8ed1d0cc4d32dc"
),
"scripts/aion_monarch_typed_adapters.py": (
"fc36d5b6d9b0edf1148ab99e2288f02b960abb3a9ebfd6ea2ef0d4b7b494b092"
),
"scripts/aion_monarch_receipt_binder.py": (
"5c8e6b517a390fd2d826d464036fc4e4da3f8ed4a9d1d0313f809bac3b1682be"
),
}


# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------
Expand All @@ -63,8 +77,32 @@ def kanban_home(tmp_path, monkeypatch):
yield home


def _aion_gov_source_dir() -> Path | None:
"""Resolve the aion-governance source dir the finalizer will pin-load."""
def _materialize_pr917_git_object(tmp_path: Path) -> Path | None:
"""Materialize PR #917's immutable merge object without reading its worktree."""
repo = Path(os.environ.get("HOME", "")) / "aion-governance"
if not repo.is_dir():
return None
dest = tmp_path / _PR917_AUTHORITY_COMMIT
for rel_path, expected_sha in _PR917_MODULES.items():
proc = subprocess.run(
["git", "-C", str(repo), "show", f"{_PR917_AUTHORITY_COMMIT}:{rel_path}"],
capture_output=True,
timeout=30,
)
if proc.returncode != 0 or hashlib.sha256(proc.stdout).hexdigest() != expected_sha:
return None
target = dest / rel_path
target.parent.mkdir(parents=True, exist_ok=True)
target.write_bytes(proc.stdout)
return dest


def _aion_gov_source_dir(tmp_path: Path | None = None) -> Path | None:
"""Resolve only a byte-exact PR #917 authority source for integration tests."""
if tmp_path is not None:
immutable = _materialize_pr917_git_object(tmp_path)
if immutable is not None:
return immutable
raw = os.environ.get("AION_GOVERNANCE_SOURCE_DIR")
if raw and Path(raw).is_dir():
return Path(raw)
Expand All @@ -77,18 +115,16 @@ def _aion_gov_source_dir() -> Path | None:


@pytest.fixture
def aion_gov_src(monkeypatch):
"""Point AION_GOVERNANCE_SOURCE_DIR at the aion-governance checkout, or
mark the test as skipped when unavailable."""
src = _aion_gov_source_dir()
def aion_gov_src(monkeypatch, tmp_path):
"""Point the finalizer at immutable PR #917 bytes, or skip if unavailable."""
src = _aion_gov_source_dir(tmp_path)
if src is None:
pytest.skip("AION_GOVERNANCE_SOURCE_DIR not configured")
monkeypatch.setenv("AION_GOVERNANCE_SOURCE_DIR", str(src))
# Assert the pinned source matches the pinned hashes so the finalizer path
# is genuinely testable here (fail loud rather than masking a drift).
kernel = (src / "scripts" / "aion_monarch_outcome_proof_gate.py").read_bytes()
if hashlib.sha256(kernel).hexdigest() != kb.AION_GOVERNANCE_KERNEL_SHA256:
pytest.skip("aion-governance kernel does not match pinned sha256")
for rel_path, expected_sha in _PR917_MODULES.items():
module_bytes = (src / rel_path).read_bytes()
if hashlib.sha256(module_bytes).hexdigest() != expected_sha:
pytest.skip(f"aion-governance module {rel_path} does not match PR #917")
return src


Expand Down Expand Up @@ -173,6 +209,72 @@ def _kernel_receipt_doc(task_id: str, run_id: str) -> dict:
}


# ---------------------------------------------------------------------------
# PR #917 immutable authority and source-drift fence
# ---------------------------------------------------------------------------

def test_pr917_authority_is_exact_and_mutable_checkout_is_not_a_default():
assert kb.AION_GOVERNANCE_AUTHORITY_PR == 917
assert kb.AION_GOVERNANCE_AUTHORITY_HEAD == (
"44d4c221468d4035e078a6bfbcd4e8a25de4850a"
)
assert kb.AION_GOVERNANCE_AUTHORITY_COMMIT == _PR917_AUTHORITY_COMMIT
assert kb.AION_GOVERNANCE_KERNEL_SHA256 == _PR917_MODULES[
"scripts/aion_monarch_outcome_proof_gate.py"
]
assert kb.AION_GOVERNANCE_TYPED_ADAPTERS_SHA256 == _PR917_MODULES[
"scripts/aion_monarch_typed_adapters.py"
]
assert kb.AION_GOVERNANCE_RECEIPT_BINDER_SHA256 == _PR917_MODULES[
"scripts/aion_monarch_receipt_binder.py"
]
assert all(
_PR917_AUTHORITY_COMMIT in source_dir
for source_dir in kb.AION_GOVERNANCE_DEFAULT_SOURCE_DIRS
)
assert "/root/aion-governance" not in kb.AION_GOVERNANCE_DEFAULT_SOURCE_DIRS


def test_pr917_module_drift_fails_closed_with_zero_mutation(
kanban_home, aion_gov_src, tmp_path, monkeypatch,
):
drifted = tmp_path / "drifted-pr917"
for rel_path in _PR917_MODULES:
target = drifted / rel_path
target.parent.mkdir(parents=True, exist_ok=True)
target.write_bytes((aion_gov_src / rel_path).read_bytes())
binder_path = drifted / "scripts" / "aion_monarch_receipt_binder.py"
binder_path.write_bytes(binder_path.read_bytes() + b"\n# injected drift\n")
monkeypatch.setenv("AION_GOVERNANCE_SOURCE_DIR", str(drifted))

with kb.connect() as conn:
task_id = kb.create_task(
conn, title="drift-fenced", factory_build_gate=1, assignee="agent007",
)
run_id = _claim_and_run_id(conn, task_id)
status_before = kb.get_task(conn, task_id).status
events_before = [event.kind for event in kb.list_events(conn, task_id)]

with pytest.raises(
kb.FactoryTerminalReceiptRequiredError,
match="aion_monarch_receipt_binder.py sha256 mismatch",
):
kb.complete_task(conn, task_id, result="must roll back", expected_run_id=run_id)

row = conn.execute(
"SELECT status, factory_terminal_receipt_sha256 FROM tasks WHERE id = ?",
(task_id,),
).fetchone()
assert row is not None
assert row["status"] == status_before == "running"
assert row["factory_terminal_receipt_sha256"] is None
assert kb.list_attachments(conn, task_id) == []
assert [event.kind for event in kb.list_events(conn, task_id)] == events_before
assert conn.execute(
"SELECT COUNT(*) FROM factory_terminal_write_grants"
).fetchone()[0] == 0


# ---------------------------------------------------------------------------
# T1 RED — finalizer disabled -> FAIL_CLOSED zero mutation
# ---------------------------------------------------------------------------
Expand Down
Loading