atlas-iac/testing/tests/test_hermes_scm_broker_policy.py
2026-08-17 07:58:44 -03:00

322 lines
12 KiB
Python

"""RBAC, Flux, and human-review contracts for the Hermes SCM broker."""
from __future__ import annotations
import json
import pytest
import yaml
from testing.tests.test_hermes_scm_broker_support import ROOT, _load_path
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-bindings/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
observer = yaml.safe_load(
(
ROOT
/ "clusters/atlas/flux-system/applications/hermes-observer-rbac/kustomization.yaml"
).read_text(encoding="utf-8")
)
assert "dependsOn" not in observer["spec"]
observer_objects = [
item
for item in yaml.safe_load_all(
(ROOT / "services/hermes-observer-rbac/rbac.yaml").read_text(
encoding="utf-8"
)
)
if item
]
assert {item["kind"] for item in observer_objects} <= {
"ClusterRole",
"ClusterRoleBinding",
}
hermes_flux = yaml.safe_load(
(
ROOT / "clusters/atlas/flux-system/applications/hermes/kustomization.yaml"
).read_text(encoding="utf-8")
)
assert "hermes-observer-rbac" in {
item["name"] for item in hermes_flux["spec"]["dependsOn"]
}
bindings_flux = yaml.safe_load(
(
ROOT
/ "clusters/atlas/flux-system/applications/hermes-observer-bindings/kustomization.yaml"
).read_text(encoding="utf-8")
)
assert {item["name"] for item in bindings_flux["spec"]["dependsOn"]} == {
"hermes",
"hermes-observer-rbac",
}
assert bindings_flux["metadata"]["name"] not in {
item["name"] for item in hermes_flux["spec"]["dependsOn"]
}
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,
"created_at": "2026-01-01T00:00:00Z",
**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")
upper_glob = _protection("M*", 1, helper, required_approvals=0)
assert (
helper.evaluate(json.dumps([upper_glob, later_exact]).encode(), "main", "bstein")
== "PRESENT"
)
def test_branch_protection_matches_gitea_v1238_tie_order():
helper = _load_path(
"branch_protection_order_test",
ROOT / "services/gitea/scripts/gitea_branch_protection_check.py",
)
older_glob = _protection(
"m*", 1, helper, created_at="2025-01-01T00:00:00Z", required_approvals=0
)
newer_plain = _protection(
"MAIN", 1, helper, created_at="2026-01-01T00:00:00Z"
)
assert (
helper.evaluate(json.dumps([older_glob, newer_plain]).encode(), "main", "bstein")
== "PRESENT"
)
older_glob["created_at"] = "2026-01-02T00:00:00Z"
earlier_glob = _protection(
"m{ain,aster}",
1,
helper,
created_at="2026-01-01T00:00:00Z",
required_approvals=0,
)
with pytest.raises(helper.PolicyError, match="effective main protection differs"):
helper.evaluate(json.dumps([older_glob, earlier_glob]).encode(), "main", "bstein")
@pytest.mark.parametrize(
("rule_name", "branch", "expected"),
[
("release/*", "release/v1.17", True),
("release/**/v1.17", "release/test/1/v1.17", True),
("release/*/v1.17", "release/test/1/v1.17", False),
("*", "release/v1.16", False),
("**", "release/v1.16", True),
("MAIN", "main", True),
("M*", "main", False),
("m{ain,aster}", "master", True),
(r"m\ain", "main", True),
],
)
def test_branch_glob_matches_gitea_v1238_source_corpus(
rule_name: str, branch: str, expected: bool
):
helper = _load_path(
"branch_protection_glob_parity_test",
ROOT / "services/gitea/scripts/gitea_branch_protection_check.py",
)
assert helper._matches(rule_name, branch) is expected
@pytest.mark.parametrize(
"rules",
[
[{"rule_name": "main", "priority": 0, "created_at": "2026-01-01T00:00:00Z"}],
[{"rule_name": "main", "priority": 1, "created_at": "not-a-time"}],
[{"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"