feat: prepare pinned Custodian worker bundle and required input admission

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a15374-f59f-7a31-86d2-d23b5d2ed181
This commit is contained in:
tegwick 2026-10-19 15:09:27 +02:00
parent 0319fe8be8
commit fed119a17c
18 changed files with 1058 additions and 2 deletions

View file

@ -0,0 +1,31 @@
import importlib.util
import shutil
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
spec = importlib.util.spec_from_file_location("bundle_verifier", ROOT / "scripts/verify_custodian_bundle.py")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
def test_reviewed_bundle_bytes():
result = module.verify(ROOT / "k8s/custodian-release/commands", "60d893af1bf77f457504b64ff1c9ffb5c6ae6579")
assert result["verified_files"] == 4
def test_tampered_installed_file_refused(tmp_path):
shutil.copytree(ROOT / "k8s/custodian-release/commands", tmp_path / "bundle")
(tmp_path / "bundle/scripts/security_flow_daily.py").write_text("changed")
with pytest.raises(ValueError, match="hash mismatch"):
module.verify(tmp_path / "bundle")
def test_installed_symlink_refused(tmp_path):
shutil.copytree(ROOT / "k8s/custodian-release/commands", tmp_path / "bundle")
path = tmp_path / "bundle/scripts/security_flow_daily.py"
path.unlink()
path.symlink_to(ROOT / "k8s/custodian-release/commands/scripts/security_flow_daily.py")
with pytest.raises(ValueError, match="regular installed"):
module.verify(tmp_path / "bundle")

View file

@ -0,0 +1,93 @@
import hashlib
import json
from datetime import UTC, datetime
import pytest
from activity_core.custodian_inputs import admit
@pytest.fixture
def evidence(tmp_path):
fleet = tmp_path / "fleet"
file = fleet / "example/workplans/task.md"
file.parent.mkdir(parents=True)
file.write_text("task")
manifest = {"schema": "repo-manager.fleet-input.v1", "freshness_verified": False,
"repositories": [{"slug": "example", "commit": "a" * 40, "files": [
{"path": "workplans/task.md", "bytes": 4, "sha256": hashlib.sha256(b"task").hexdigest()}]}]}
raw = json.dumps(manifest).encode()
(fleet / "manifest.json").write_bytes(raw)
(fleet / "COMPLETE").write_text(hashlib.sha256(raw).hexdigest())
policy = tmp_path / "policy.json"
policy.write_text(json.dumps({"schema": "activity-core.custodian-input-policy.v1", "repositories": ["example"],
"max_observation_age_seconds": 7200, "max_future_skew_seconds": 300,
"max_snapshot_bytes": 1024, "expected_hub_instance": "railiance01"}))
receipts = tmp_path / "receipts.json"
receipt = {"schema": "repo-manager.freshness-receipt.v1", "repo_slug": "example", "forge_commit": "a" * 40,
"outcome": "noop", "reason": "forge_head_matches_last_success", "finished_at": "2026-10-19T10:00:00Z",
"hub": {"verified_primary": True, "instance_role": "primary", "instance_label": "railiance01"}}
prior = {**receipt, "outcome": "applied", "reason": None,
"finished_at": "2026-10-01T00:00:00Z",
**{key: "a" * 40 for key in ("expected_commit", "derived_commit", "projected_commit")}}
receipts.write_text(json.dumps([receipt, prior]))
return fleet, policy, receipts
def check(evidence):
return admit(*evidence, ["example"], now=datetime(2026, 10, 19, 11, tzinfo=UTC))
def test_accepts_independent_recent_receipt(evidence):
assert len(check(evidence)) == 64
@pytest.mark.parametrize("case", ["missing", "stale", "future", "wrong_commit", "wrong_hub", "failed"])
def test_rejects_invalid_freshness(evidence, case):
path = evidence[2]
rows = json.loads(path.read_text())
if case == "missing":
rows = []
elif case == "stale":
rows[0]["finished_at"] = "2026-10-18T10:00:00Z"
elif case == "future":
rows[0]["finished_at"] = "2026-10-20T10:00:00Z"
elif case == "wrong_commit":
rows[0]["forge_commit"] = "b" * 40
elif case == "wrong_hub":
rows[0]["hub"]["instance_label"] = "workstation"
else:
rows[0]["outcome"] = "failed"
path.write_text(json.dumps(rows))
with pytest.raises(ValueError, match="fresh Forge receipt"):
check(evidence)
@pytest.mark.parametrize("case", ["tamper", "extra", "marker", "extra_repo"])
def test_rejects_changed_snapshot(evidence, case):
fleet = evidence[0]
if case == "tamper":
(fleet / "example/workplans/task.md").write_text("changed")
elif case == "extra":
(fleet / "example/workplans/extra.md").write_text("extra")
elif case == "extra_repo":
(fleet / "outside").mkdir()
else:
(fleet / "COMPLETE").write_text("incorrect")
with pytest.raises(ValueError):
check(evidence)
def test_native_noop_uses_protected_issuer_contract(evidence):
path = evidence[2]
path.write_text(json.dumps(json.loads(path.read_text())[:1]))
assert len(check(evidence)) == 64
def test_fifo_refused_without_open(evidence):
import os
path = evidence[2]
path.unlink()
os.mkfifo(path)
with pytest.raises(ValueError, match="unsafe"):
check(evidence)

View file

@ -1,4 +1,6 @@
import json
import hashlib
from datetime import datetime, timezone
from pathlib import Path
from unittest.mock import patch
@ -21,6 +23,26 @@ def runtime(tmp_path, monkeypatch):
monkeypatch.setenv("ACTIVITY_CORE_CUSTODIAN_HUB", "http://127.0.0.1:8000")
monkeypatch.setenv("ACTIVITY_CORE_CUSTODIAN_REPOS", "the-custodian")
(fleet / "the-custodian/workplans").mkdir(parents=True)
(fleet / "the-custodian/workplans/task.md").write_text("task")
manifest = {"schema": "repo-manager.fleet-input.v1", "repositories": [{
"slug": "the-custodian", "commit": "a" * 40, "files": [{"path": "workplans/task.md",
"bytes": 4, "sha256": hashlib.sha256(b"task").hexdigest()}]}]}
raw = json.dumps(manifest).encode()
(fleet / "manifest.json").write_bytes(raw)
(fleet / "COMPLETE").write_text(hashlib.sha256(raw).hexdigest())
policy = state / "policy.json"
policy.write_text(json.dumps({"schema": "activity-core.custodian-input-policy.v1",
"repositories": ["the-custodian"], "max_observation_age_seconds": 7200,
"max_future_skew_seconds": 300, "max_snapshot_bytes": 1024,
"expected_hub_instance": "railiance01"}))
receipts = state / "receipts.json"
receipts.write_text(json.dumps([{"schema": "repo-manager.freshness-receipt.v1",
"repo_slug": "the-custodian", "outcome": "applied",
"finished_at": datetime.now(timezone.utc).isoformat(),
"hub": {"verified_primary": True, "instance_role": "primary", "instance_label": "railiance01"},
**{key: "a" * 40 for key in ("forge_commit", "expected_commit", "derived_commit", "projected_commit")}}]))
monkeypatch.setenv("ACTIVITY_CORE_CUSTODIAN_INPUT_POLICY", str(policy))
monkeypatch.setenv("ACTIVITY_CORE_CUSTODIAN_FRESHNESS_RECEIPTS", str(receipts))
for name in ("security_flow_daily.py", "weekly_allocation_report.py"):
(root / "scripts" / name).write_text("# owner fixture\n")
return root, fleet, state
@ -168,3 +190,23 @@ def test_subprocess_timeout_kills_group():
with pytest.raises(RuntimeError, match='timed out'):
runner._execute(['fixed-owner-command'], Path('/tmp'), 1)
kill.assert_called_once_with(12345, runner.signal.SIGKILL)
def test_configured_freshness_admission_refuses_before_subprocess(runtime, monkeypatch):
root, fleet, state = runtime
policy = state / "policy.json"
receipts = state / "receipts.json"
policy.write_text("{}")
receipts.write_text("[]")
monkeypatch.setenv("ACTIVITY_CORE_CUSTODIAN_INPUT_POLICY", str(policy))
monkeypatch.setenv("ACTIVITY_CORE_CUSTODIAN_FRESHNESS_RECEIPTS", str(receipts))
with patch.object(runner, "_execute") as execute, pytest.raises(ValueError):
runner.run_custodian_operation("custodian_security_flow", {"apply": True})
execute.assert_not_called()
def test_missing_policy_refuses_before_subprocess(runtime, monkeypatch):
monkeypatch.delenv("ACTIVITY_CORE_CUSTODIAN_INPUT_POLICY")
with patch.object(runner, "_execute") as execute, pytest.raises(ValueError):
runner.run_custodian_operation("custodian_security_flow", {"apply": True})
execute.assert_not_called()