atlas-iac/testing/tests/test_hermes_execution_pool_assignment.py
Hermes Agent 7a55b259bf hermes: add the fenced three-node distributed execution pool
Three fenced worker Pods claim Hermes Kanban runs through a coordinator that
owns every state transition, with per-ordinal HMAC authority, a mediated
broker-only SCM path, and durable per-ordinal workspaces.

Content is the reviewed head of PR #18 (689bcb6e) with PR 16's and PR 19's
contributions removed: they were merged in only to validate co-existence and are
not prerequisites, so this branch no longer carries them as ancestors. Only PR 14
and PR 15 remain, because the broker boundary and the cli_lane_* decomposition
are load-bearing for two of the fixed P0 boundaries.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 16:31:15 +00:00

209 lines
7.8 KiB
Python

"""SCM assignment tests that keep coordinator credentials out of worktrees."""
from __future__ import annotations
import sys
from pathlib import Path
from http.server import BaseHTTPRequestHandler
from types import SimpleNamespace
import pytest
import yaml
SCRIPTS = Path(__file__).parents[2] / "services/hermes/scripts"
HERMES = SCRIPTS.parent
sys.path[:0] = [str(SCRIPTS), str(HERMES / "scm-common/scripts")]
import execution_pool_coordinator as coordinator # noqa: E402
import execution_pool_project as project # noqa: E402
import execution_pool_protocol as protocol # noqa: E402
import execution_pool_scm as scm # noqa: E402
import execution_pool_worker as worker # noqa: E402
KEY = b"k" * 32
def test_new_task_uses_explicit_reviewed_atlas_default(monkeypatch):
monkeypatch.setattr(
project,
"resolve_project",
lambda board: (
f"https://scm.bstein.dev/atlas/{board}.git", "main", Path("/unused")
),
)
task = SimpleNamespace(id="t_deadbeef", workspace_path="", branch_name="")
assert project.resolve_assignment("titan-iac", task) == (
"https://scm.bstein.dev/atlas/titan-iac.git",
"wt/t_deadbeef",
"main",
)
def test_legacy_local_workspace_remains_owned_by_local_lane(tmp_path):
task = SimpleNamespace(
id="t_deadbeef", workspace_path=str(tmp_path), branch_name="feature/safe"
)
assert project.distributed_workspace_eligible(task) is False
def test_local_git_environment_excludes_credential_boundary_paths():
local = scm._git_environment()
assert "HERMES_SCM_PASSWORD_FILE" not in local
assert "GIT_ASKPASS" not in local
assert "GITEA_TOKEN" not in local
def test_finalized_duplicate_result_is_acknowledged_without_refinalizing(tmp_path):
binding = {
"board": "atlas", "task_id": "t_deadbeef", "run_id": "run-1",
"worker_ordinal": 0, "attempt": 1,
}
store = protocol.PoolStore(tmp_path / "pool.db")
store.add(binding, {"context": "safe"})
ordinal_key = protocol.derive_ordinal_key(KEY, 0)
result = protocol.sign_envelope(ordinal_key, "result", binding, {"structured": {}})
store.accept_result(result)
store.finalize(binding, "finalized")
pool = coordinator.Coordinator(KEY, store)
called = []
pool.finalize = called.append
assert pool.result(result)["payload"]["duplicate"] is True
assert called == []
def test_provider_sessions_are_bound_to_exact_task_run(tmp_path, monkeypatch):
runtime = tmp_path / "runtime"
(runtime / "codex").mkdir(parents=True)
(runtime / "claude").mkdir(parents=True)
monkeypatch.setattr(worker, "ROOT", tmp_path / "worker")
(tmp_path / "worker/provider-state").mkdir(parents=True)
monkeypatch.setattr(worker.cli_lane_runner, "DATA_ROOT", tmp_path / "worker-data")
(tmp_path / "worker-data").mkdir()
monkeypatch.setenv("CODEX_HOME", str(runtime / "codex"))
monkeypatch.setenv("CLAUDE_CONFIG_DIR", str(runtime / "claude"))
assignment = {"board": "atlas", "task_id": "t_deadbeef", "run_id": "run-1"}
worker._bind_provider_sessions(assignment)
for path in (
runtime / "codex/sessions", runtime / "claude/projects",
runtime / "claude/session-env", runtime / "claude/todos",
):
assert path.is_symlink()
assert "atlas/t_deadbeef/run-1" in str(path.resolve())
assert (tmp_path / "worker-data/home").is_symlink()
assert "atlas/t_deadbeef/run-1" in str((tmp_path / "worker-data/home").resolve())
def test_internal_http_server_rejects_work_above_its_bound(monkeypatch):
server = protocol.BoundedHTTPServer(
("127.0.0.1", 0), BaseHTTPRequestHandler, max_workers=1
)
rejected = []
monkeypatch.setattr(server, "shutdown_request", rejected.append)
assert server._slots.acquire(blocking=False)
try:
marker = object()
server.process_request(marker, ("127.0.0.1", 1))
assert rejected == [marker]
finally:
server._slots.release()
server.server_close()
def test_additive_patch_replaces_local_lane_without_touching_base_deployment():
patch = yaml.safe_load((HERMES / "execution-coordinator-patch.yaml").read_text())
containers = patch["spec"]["template"]["spec"]["containers"]
local = next(item for item in containers if item["name"] == "cli-lane-runner")
pool = next(item for item in containers if item["name"] == "execution-pool-coordinator")
environment = {item["name"]: item["value"] for item in local["env"]}
assert environment == {
"HERMES_CLI_LANE_OWNED_WORKSPACES_ONLY": "true",
"HERMES_CLI_LANE_CONCURRENCY": "1",
}
assert pool["resources"]["requests"] == {"cpu": "50m", "memory": "128Mi"}
access = next(item for item in pool["volumeMounts"] if item["name"] == "runtime-access")
assert access["subPath"] == "execution-pool-key" and access["readOnly"] is True
def test_additive_network_policies_expose_only_worker_pool_and_switchyard_ports():
documents = list(yaml.safe_load_all(
(HERMES / "execution-worker-networkpolicy.yaml").read_text()
))
policies = {item["metadata"]["name"]: item for item in documents}
assert set(policies) == {
"hermes-execution-worker-isolation",
"hermes-execution-mediator-isolation",
"hermes-execution-pool-ingress",
"hermes-execution-switchyard-ingress",
*(f"hermes-execution-worker-mediator-{ordinal}" for ordinal in range(3)),
*(f"hermes-execution-mediator-worker-{ordinal}" for ordinal in range(3)),
}
assert policies["hermes-execution-pool-ingress"]["spec"]["ingress"][0]["ports"] == [
{"protocol": "TCP", "port": 9007}
]
pool_source = policies["hermes-execution-pool-ingress"]["spec"]["ingress"]
assert "hermes-execution-mediator" in str(pool_source)
worker_egress = policies["hermes-execution-worker-isolation"]["spec"]["egress"]
assert "hermes-scm-broker" not in str(worker_egress)
assert "hermes-execution-mediator" not in str(worker_egress)
for ordinal in range(3):
worker_policy = policies[f"hermes-execution-worker-mediator-{ordinal}"]
mediator_policy = policies[f"hermes-execution-mediator-worker-{ordinal}"]
assert worker_policy["spec"]["podSelector"]["matchLabels"][
"apps.kubernetes.io/pod-index"
] == str(ordinal)
assert worker_policy["spec"]["egress"][0]["to"][0]["podSelector"][
"matchLabels"
]["pool-ordinal"] == str(ordinal)
assert mediator_policy["spec"]["ingress"][0]["from"][0]["podSelector"][
"matchLabels"
]["apps.kubernetes.io/pod-index"] == str(ordinal)
@pytest.mark.parametrize(
"branch",
[
"../main",
"main",
"feature/../../main",
],
)
def test_assignment_rejects_unreviewed_task_branch(monkeypatch, branch):
monkeypatch.setattr(
project,
"resolve_project",
lambda _board: (
"https://scm.bstein.dev/atlas/titan-iac.git", "main", Path("/unused")
),
)
task = SimpleNamespace(
id="t_deadbeef", workspace_path="", branch_name=branch,
repo_url="https://evil.example/atlas/other.git", base_branch="../main",
)
with pytest.raises(project.ProjectPolicyError):
project.resolve_assignment("titan-iac", task)
def test_registry_authority_ignores_unreviewed_task_repo_metadata(monkeypatch):
monkeypatch.setattr(
project,
"resolve_project",
lambda _board: (
"https://scm.bstein.dev/atlas/metis.git", "main", Path("/unused")
),
)
task = SimpleNamespace(
id="t_deadbeef", branch_name="review/t_deadbeef",
repo_url="https://evil.example/atlas/other.git", base_branch="../main",
)
assert project.resolve_assignment("metis", task)[:2] == (
"https://scm.bstein.dev/atlas/metis.git", "review/t_deadbeef"
)