"""Executable contracts for the credential-isolated Hermes SCM broker.""" from __future__ import annotations import importlib.util import io import json import sys from email.message import Message from pathlib import Path import pytest import yaml ROOT = Path(__file__).parents[2] SCRIPTS = ROOT / "services/hermes/scm-common/scripts" sys.path.insert(0, str(SCRIPTS)) def _load(name: str): path = SCRIPTS / f"{name}.py" spec = importlib.util.spec_from_file_location(f"test_{name}", path) assert spec and spec.loader module = importlib.util.module_from_spec(spec) sys.modules[spec.name] = module spec.loader.exec_module(module) return module def _load_path(name: str, path: Path): spec = importlib.util.spec_from_file_location(name, path) assert spec and spec.loader module = importlib.util.module_from_spec(spec) sys.modules[spec.name] = module spec.loader.exec_module(module) return module class Response: def __init__(self, body: bytes, *, status: int = 200, content_type: str): self.body = body self.stream = io.BytesIO(body) self.status = status self.headers = Message() self.headers["Content-Type"] = content_type def __enter__(self): return self def __exit__(self, *_args): return False def read(self, limit=-1): return self.stream.read(limit) def _receive_command(old: bytes, new: bytes, ref: bytes) -> bytes: command = old + b" " + new + b" " + ref + b"\x00report-status\n" return f"{len(command) + 4:04x}".encode() + command + b"0000PACK" @pytest.mark.parametrize( "target", [ "/api/v1/repos/atlas/cassandra/pulls/1/merge", "/api/v1/repos/atlas/cassandra/pulls/1/reviews", "/api/v1/admin/users", "/git/evil/cassandra.git/info/refs?service=git-upload-pack", "/git/atlas/cassandra.git/hooks", "/git/atlas/cassandra.git/git-receive-pack?force=true", "/git/atlas/cassandra.git/info/refs?service=git-upload-pack\nignored", "/git/atlas/cassandra.git/info/refs?service=git-upload-pack\tignored", "/git/atlas/cassandra.git/info/refs?service=git-upload-pack#fragment", ], ) def test_broker_rejects_privileged_or_non_atlas_routes(target: str): broker = _load("scm_broker") with pytest.raises(broker.PolicyError): broker._git_target(target) def test_broker_metadata_boundary_reuses_explicit_read_allowlist(): api = _load("gitea_api") assert ( api.authorize_request("GET", "/api/v1/repos/atlas/cassandra/pulls/1", None) == "pull" ) for path in ( "/api/v1/repos/atlas/cassandra/pulls/1/merge", "/api/v1/repos/atlas/cassandra/pulls/1/reviews", "/api/v1/repos/atlas/cassandra/hooks", "/api/v1/admin/users", ): with pytest.raises(api.PolicyError): api.authorize_request("GET", path, None) def test_receive_pack_allows_only_new_namespaced_feature_branch(): broker = _load("scm_broker") zero = b"0" * 40 commit = b"1" * 40 broker._validate_receive_pack( _receive_command(zero, commit, b"refs/heads/hermes/focused-fix"), "runtime-sentinel", ) for old, new, ref in ( (commit, b"2" * 40, b"refs/heads/hermes/focused-fix"), (commit, zero, b"refs/heads/hermes/focused-fix"), (zero, commit, b"refs/heads/main"), (zero, commit, b"refs/heads/master"), (zero, commit, b"refs/tags/release"), ): with pytest.raises(broker.PolicyError): broker._validate_receive_pack( _receive_command(old, new, ref), "runtime-sentinel" ) def test_git_proxy_uses_fixed_origin_and_never_reflects_credential(): broker = _load("scm_broker") seen = [] def opener(request, timeout): seen.append((request, timeout)) return Response( b"git-result", content_type="application/x-git-upload-pack-result", ) result = broker._upstream_git_request( "/atlas/cassandra.git/git-upload-pack", method="POST", body=b"request", content_type="application/x-git-upload-pack-request", expected_type="application/x-git-upload-pack-result", token="runtime-sentinel", opener=opener, ) assert result == b"git-result" request = seen[0][0] assert request.full_url == ( "https://scm.bstein.dev/atlas/cassandra.git/git-upload-pack" ) assert b"runtime-sentinel" not in request.data assert "runtime-sentinel" not in request.full_url with pytest.raises(broker.PolicyError, match="credential material"): broker._upstream_git_request( "/atlas/cassandra.git/git-upload-pack", method="POST", body=b"request", content_type="application/x-git-upload-pack-request", expected_type="application/x-git-upload-pack-result", token="runtime-sentinel", opener=lambda *_a, **_k: Response( b"runtime-sentinel", content_type="application/x-git-upload-pack-result", ), ) encoded = broker._credential_forms("runtime-sentinel")[1] with pytest.raises(broker.PolicyError, match="credential material"): broker._upstream_git_request( "/atlas/cassandra.git/git-upload-pack", method="POST", body=b"request", content_type="application/x-git-upload-pack-request", expected_type="application/x-git-upload-pack-result", token="runtime-sentinel", opener=lambda *_a, **_k: Response( b"Authorization: Basic " + encoded, content_type="application/x-git-upload-pack-result", ), ) @pytest.mark.parametrize("status", [201, 202, 204, 206, 301, 302, 307, 308]) def test_git_proxy_requires_exact_http_200(status: int): broker = _load("scm_broker") with pytest.raises(broker.PolicyError, match="unexpected HTTP status"): broker._upstream_git_request( "/atlas/cassandra.git/git-upload-pack", method="POST", body=b"request", content_type="application/x-git-upload-pack-request", expected_type="application/x-git-upload-pack-result", token="runtime-sentinel", opener=lambda *_a, **_k: Response( b"result", status=status, content_type="application/x-git-upload-pack-result", ), ) def test_agent_broker_client_sends_no_credential_or_authorization_header(): client = _load("scm_broker_client") seen = [] def opener(request, timeout): seen.append((request, timeout)) return Response(b"{}", content_type="application/json") assert client.read( "/api/v1/repos/atlas/cassandra", opener=opener ) == b"{}" request = seen[0][0] assert request.full_url == client.BROKER_ORIGIN + "/v1/metadata" assert request.get_header("Authorization") is None assert json.loads(request.data) == { "path": "/api/v1/repos/atlas/cassandra" } @pytest.mark.parametrize("raw", ["", "01", "9" * 4000, "134217729", "12"]) def test_broker_content_length_is_canonical_and_bounded(raw: str): broker = _load("scm_broker") headers = Message() headers["Content-Length"] = raw with pytest.raises(broker.PolicyError, match="request length"): broker._content_length(headers, broker.MAX_GIT_REQUEST) def test_large_git_exchange_rolls_to_disk_and_scans_chunk_boundaries(): broker = _load("scm_broker") token = "runtime-sentinel" safe = b"x" * (broker.SPOOL_MEMORY_LIMIT + 1) inbound_timeouts = [] spool, length = broker._spool_bounded( io.BytesIO(safe), broker.MAX_GIT_REQUEST, len(safe), token=token, context="Git request", deadline=broker.time.monotonic() + 30, set_timeout=inbound_timeouts.append, ) try: assert length == len(safe) assert spool._rolled is True assert spool.read(4) == b"xxxx" assert inbound_timeouts assert all(0 < value <= 30 for value in inbound_timeouts) finally: spool.close() crossing = b"x" * (broker.STREAM_CHUNK - 5) + token.encode() + b"tail" with pytest.raises(broker.PolicyError, match="credential material"): broker._spool_bounded( io.BytesIO(crossing), broker.MAX_GIT_REQUEST, len(crossing), token=token, context="Git request", deadline=broker.time.monotonic() + 30, ) def test_large_upstream_response_is_streamed_through_bounded_spool(): broker = _load("scm_broker") body = b"z" * (broker.SPOOL_MEMORY_LIMIT + 1) seen = [] def opener(request, **_kwargs): seen.append(request) assert request.get_header("Content-length") == "7" assert request.data.read() == b"request" return Response(body, content_type="application/x-git-upload-pack-result") streamed = broker._upstream_git_request( "/atlas/cassandra.git/git-upload-pack", method="POST", body=io.BytesIO(b"request"), body_length=7, content_type="application/x-git-upload-pack-request", expected_type="application/x-git-upload-pack-result", token="runtime-sentinel", stream_result=True, opener=opener, ) spool, length = streamed try: assert length == len(body) assert spool._rolled is True assert spool.read(3) == b"zzz" assert len(seen) == 1 finally: spool.close() def test_body_deadline_fails_closed_before_reading(): broker = _load("scm_broker") with pytest.raises(broker.PolicyError, match="deadline"): broker._spool_bounded( io.BytesIO(b"body"), broker.MAX_GIT_REQUEST, 4, token="runtime-sentinel", context="Git request", deadline=broker.time.monotonic() - 1, ) def test_upstream_stream_applies_absolute_socket_deadline(): broker = _load("scm_broker") class DeadlineSocket: def __init__(self): self.values = [] def settimeout(self, value): self.values.append(value) response = Response(b"safe", content_type="application/x-git-upload-pack-result") sock = DeadlineSocket() response.fp = type("FP", (), {"raw": type("Raw", (), {"_sock": sock})()})() spool, length = broker._spool_response(response, broker.MAX_GIT_RESPONSE, "sentinel") try: assert length == 4 assert sock.values assert all(0 < value <= broker.INBOUND_BODY_TIMEOUT for value in sock.values) finally: spool.close() def test_broker_rejects_work_when_concurrency_slots_are_exhausted(): broker = _load("scm_broker") class FakeSocket: def __init__(self): self.value = b"" def sendall(self, value): self.value += value def shutdown(self, _how): return None def close(self): return None server = broker.BoundedThreadingHTTPServer(("127.0.0.1", 0), broker.BrokerHandler) try: assert server._slots.acquire(blocking=False) assert server._slots.acquire(blocking=False) request = FakeSocket() server.process_request(request, ("127.0.0.1", 1)) assert b"503 Service Unavailable" in request.value finally: server._slots.release() server._slots.release() server.server_close() def test_broker_bounds_header_count_size_and_duplicate_lengths(): broker = _load("scm_broker") def validate(headers): handler = object.__new__(broker.BrokerHandler) handler.headers = headers handler._validate_headers() too_many = Message() for index in range(broker.MAX_HEADERS + 1): too_many[f"X-Test-{index}"] = "safe" with pytest.raises(broker.PolicyError, match="too many headers"): validate(too_many) too_large = Message() too_large["X-Test"] = "x" * broker.MAX_HEADER_BYTES with pytest.raises(broker.PolicyError, match="safe limit"): validate(too_large) duplicate = Message() duplicate["Content-Length"] = "1" duplicate["Content-Length"] = "1" with pytest.raises(broker.PolicyError, match="duplicate Content-Length"): validate(duplicate) def _can_i(role: dict, api_group: str, resource: str, verb: str) -> bool: return any( (api_group in rule["apiGroups"] or "*" in rule["apiGroups"]) and (resource in rule["resources"] or "*" in rule["resources"]) and (verb in rule["verbs"] or "*" in rule["verbs"]) for rule in role["rules"] ) def test_agent_rbac_preserves_read_diagnostics_without_administrator_authority(): documents = list( yaml.safe_load_all( (ROOT / "services/hermes-observer-rbac/rbac.yaml").read_text( encoding="utf-8" ) ) ) cluster_role, namespaced_role, binding = documents assert binding["roleRef"]["name"] == "hermes-agent-cluster-observer-v2" assert _can_i(cluster_role, "", "nodes", "get") assert _can_i(namespaced_role, "", "pods", "get") assert _can_i(namespaced_role, "", "pods/log", "get") assert _can_i( namespaced_role, "kustomize.toolkit.fluxcd.io", "kustomizations", "list", ) denied = ( ("", "secrets", "get"), ("", "serviceaccounts/token", "create"), ("", "pods", "create"), ("", "pods/exec", "create"), ("", "pods/attach", "create"), ("", "pods/portforward", "create"), ("rbac.authorization.k8s.io", "clusterrolebindings", "create"), ("authorization.k8s.io", "selfsubjectaccessreviews", "create"), ("apps", "deployments", "patch"), ) assert all( not _can_i(role, *request) for request in denied for role in (cluster_role, namespaced_role) ) bindings = yaml.safe_load( (ROOT / "services/hermes-observer-rbac/rolebindings.yaml").read_text( encoding="utf-8" ) )["items"] namespaces = {item["metadata"]["namespace"] for item in bindings} assert "hermes-scm" not in namespaces assert {"cassandra", "flux-system", "hermes", "kube-system"} <= namespaces assert all(item["roleRef"]["name"].endswith("namespaced-observer-v2") for item in bindings) def test_flux_boundary_keeps_broker_secret_and_network_separate_from_agent(): agent = yaml.safe_load( (ROOT / "services/hermes/agent-deployment.yaml").read_text(encoding="utf-8") ) annotations = agent["spec"]["template"]["metadata"]["annotations"] assert not any("gitea" in key.lower() for key in annotations) assert "GIT_ASKPASS" not in json.dumps(agent) broker = yaml.safe_load( (ROOT / "services/hermes-scm-broker/deployment.yaml").read_text( encoding="utf-8" ) ) assert broker["metadata"]["namespace"] == "hermes-scm" assert broker["spec"]["template"]["spec"]["serviceAccountName"] == ( "hermes-scm-broker" ) assert "gitea-token" in json.dumps(broker) container = broker["spec"]["template"]["spec"]["containers"][0] assert container["resources"]["limits"]["memory"] == "768Mi" assert container["livenessProbe"]["failureThreshold"] == 10 tmp = next( item for item in broker["spec"]["template"]["spec"]["volumes"] if item["name"] == "tmp" ) assert tmp["emptyDir"]["sizeLimit"] == "1Gi" policy = yaml.safe_load( (ROOT / "services/hermes-scm-broker/networkpolicy.yaml").read_text( encoding="utf-8" ) ) ingress = policy["spec"]["ingress"] assert ingress[0]["from"][0]["namespaceSelector"]["matchLabels"] == { "kubernetes.io/metadata.name": "hermes" } assert ingress[0]["from"][0]["podSelector"]["matchLabels"] == { "app": "hermes-agent" } vault = ( ROOT / "services/vault/scripts/vault_k8s_auth_configure.sh" ).read_text(encoding="utf-8") assert 'write_policy_and_role "hermes-scm-broker" "hermes-scm"' in vault assert '"hermes/developer-gitea" ""' in vault agent_start = vault.index('write_policy_and_role "hermes-agent"') agent_end = vault.index("write_policy_and_role", agent_start + 1) assert "developer-gitea" not in vault[agent_start:agent_end] def test_flux_bootstrap_has_no_agent_namespace_dependency_cycle(): hermes_resources = yaml.safe_load( (ROOT / "services/hermes/kustomization.yaml").read_text(encoding="utf-8") )["resources"] assert "namespace.yaml" in hermes_resources assert "scm-common" in hermes_resources applications = ( ROOT / "clusters/atlas/flux-system/applications/kustomization.yaml" ).read_text(encoding="utf-8") assert "hermes-scm-agent-code" not in applications broker_code = yaml.safe_load( ( ROOT / "clusters/atlas/flux-system/applications/hermes-scm-broker-code/kustomization.yaml" ).read_text(encoding="utf-8") ) assert broker_code["spec"]["path"] == "./services/hermes/scm-common" assert broker_code["spec"]["targetNamespace"] == "hermes-scm" assert broker_code["spec"]["dependsOn"] == [{"name": "hermes-scm-namespace"}] def test_gitea_bootstrap_enforces_human_review_without_overwriting_drift(): script = ( ROOT / "services/gitea/scripts/gitea_atlas_identity_ensure.sh" ).read_text(encoding="utf-8") assert 'required_approvals\\\":1' in script assert 'enable_push_whitelist\\\":true' in script assert 'push_whitelist_usernames\\\":[\\\"${protected_reviewer}\\\"]' in script assert 'enable_merge_whitelist\\\":true' in script assert 'merge_whitelist_usernames\\\":[\\\"${protected_reviewer}\\\"]' in script assert "protection differs from the human-review policy" in script assert "api_request PATCH" not in script job = yaml.safe_load( (ROOT / "services/gitea/atlas-identity-bootstrap-job.yaml").read_text() ) init = job["spec"]["template"]["spec"]["initContainers"][0] assert init["image"] == ( "python@sha256:6d43704baacd1bfbe7c295d7f13079d5d8104ed33568873133f8fc69980419df" ) assert init["securityContext"]["runAsNonRoot"] is True assert init["securityContext"]["capabilities"]["drop"] == ["ALL"] assert "/opt/python/bin/python3" in script def _protection(rule_name: str, priority: int, helper, **overrides): value = {"rule_name": rule_name, "priority": priority, **helper._required("bstein")} value.update(overrides) return value def test_branch_protection_uses_first_effective_glob_by_priority(): helper = _load_path( "branch_protection_test", ROOT / "services/gitea/scripts/gitea_branch_protection_check.py", ) earlier_drift = _protection("m*", 1, helper, required_approvals=0) later_exact = _protection("main", 2, helper) with pytest.raises(helper.PolicyError, match="effective main protection differs"): helper.evaluate(json.dumps([later_exact, earlier_drift]).encode(), "main", "bstein") earlier_drift["required_approvals"] = 1 assert ( helper.evaluate(json.dumps([later_exact, earlier_drift]).encode(), "main", "bstein") == "PRESENT" ) brace_drift = _protection("m{ain,aster}", 1, helper, required_approvals=0) with pytest.raises(helper.PolicyError, match="effective master protection differs"): helper.evaluate(json.dumps([brace_drift]).encode(), "master", "bstein") @pytest.mark.parametrize( "rules", [ [{"rule_name": "main", "priority": 1}, {"rule_name": "m*", "priority": 1}], [{"rule_name": "[main", "priority": 1}], [{"rule_name": "main", "priority": 0}], [{"rule_name": "main"}], ], ) def test_branch_protection_rejects_ambiguous_rules_before_creation(rules): helper = _load_path( "branch_protection_adversarial_test", ROOT / "services/gitea/scripts/gitea_branch_protection_check.py", ) with pytest.raises(helper.PolicyError): helper.evaluate(json.dumps(rules).encode(), "main", "bstein") def test_branch_protection_reports_absent_only_when_no_rule_matches(): helper = _load_path( "branch_protection_absent_test", ROOT / "services/gitea/scripts/gitea_branch_protection_check.py", ) rules = [_protection("release/*", 1, helper)] assert helper.evaluate(json.dumps(rules).encode(), "master", "bstein") == "ABSENT"