201 lines
6.8 KiB
Python
201 lines
6.8 KiB
Python
"""SCM checkout ownership and private-baseline corruption probes."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
|
|
ROOT = Path(__file__).parents[2]
|
|
sys.path[:0] = [
|
|
str(ROOT / "services/hermes/scripts"),
|
|
str(ROOT / "services/hermes/scm-common/scripts"),
|
|
]
|
|
|
|
import execution_pool_protocol as protocol # noqa: E402
|
|
import execution_pool_scm as scm # noqa: E402
|
|
from testing.tests.test_hermes_execution_pool_mediator import ( # noqa: E402
|
|
KEY,
|
|
assignment,
|
|
init_checkout,
|
|
)
|
|
|
|
|
|
def test_checkout_and_submit_reject_unmanaged_or_corrupt_private_state(
|
|
tmp_path, monkeypatch
|
|
):
|
|
monkeypatch.setattr(scm, "WORKSPACE_ROOT", tmp_path / "workspace")
|
|
monkeypatch.setattr(scm, "SCM_ROOT", tmp_path / "state")
|
|
monkeypatch.setattr(scm, "ORDINAL", 0)
|
|
destination = scm.workspace_path(assignment())
|
|
destination.mkdir(parents=True)
|
|
(destination / "owner-file").write_text("preserve")
|
|
boundary = scm.Boundary(KEY)
|
|
with pytest.raises(protocol.ProtocolError, match="non-empty"):
|
|
boundary.checkout(assignment())
|
|
|
|
(destination / "owner-file").unlink()
|
|
|
|
def clone_with_empty_failure(*arguments, **_kwargs):
|
|
if arguments[0] == "clone" and arguments[4] == "wt/t_deadbeef":
|
|
destination.mkdir(parents=True, exist_ok=True)
|
|
raise RuntimeError("missing")
|
|
if arguments[0] == "clone":
|
|
(destination / ".git").mkdir(parents=True)
|
|
return ""
|
|
|
|
monkeypatch.setattr(scm, "_run", clone_with_empty_failure)
|
|
monkeypatch.setattr(scm, "_workspace_identity", lambda *_a: "a" * 40)
|
|
assert boundary.checkout(assignment())["baseline_sha"] == "a" * 40
|
|
|
|
protocol.atomic_json(scm._state_path(assignment()), {"baseline_sha": "bad"})
|
|
with pytest.raises(protocol.ProtocolError, match="baseline"):
|
|
boundary.submit(assignment(), {})
|
|
|
|
|
|
def test_scm_identity_is_data_only_and_supports_packed_refs(tmp_path):
|
|
checkout = tmp_path / "checkout"
|
|
subprocess.run(["git", "init", "-q", str(checkout)], check=True)
|
|
subprocess.run(
|
|
[
|
|
"git", "-C", str(checkout), "remote", "add", "origin",
|
|
"https://scm.bstein.dev/titan/atlas-iac.git",
|
|
],
|
|
check=True,
|
|
)
|
|
subprocess.run(
|
|
[
|
|
"git", "-C", str(checkout), "remote", "add", "hermes-broker",
|
|
scm._broker_repo("atlas-iac"),
|
|
],
|
|
check=True,
|
|
)
|
|
subprocess.run(
|
|
[
|
|
"git", "-C", str(checkout), "checkout", "-qb",
|
|
"feature/hermes-safe-pool",
|
|
],
|
|
check=True,
|
|
)
|
|
subprocess.run(
|
|
["git", "-C", str(checkout), "config", "user.email", "a@b.c"],
|
|
check=True,
|
|
)
|
|
subprocess.run(
|
|
["git", "-C", str(checkout), "config", "user.name", "Test"],
|
|
check=True,
|
|
)
|
|
(checkout / "tracked").write_text("safe\n")
|
|
subprocess.run(["git", "-C", str(checkout), "add", "tracked"], check=True)
|
|
subprocess.run(
|
|
["git", "-C", str(checkout), "commit", "-qm", "initial"], check=True
|
|
)
|
|
expected = subprocess.check_output(
|
|
["git", "-C", str(checkout), "rev-parse", "HEAD"], text=True
|
|
).strip()
|
|
subprocess.run(
|
|
["git", "-C", str(checkout), "pack-refs", "--all"], check=True
|
|
)
|
|
assert scm._workspace_identity(
|
|
checkout,
|
|
"atlas-iac",
|
|
"feature/hermes-safe-pool",
|
|
) == expected
|
|
(checkout / ".git/refs/heads/feature").mkdir(parents=True)
|
|
(checkout / ".git/refs/heads/feature/hermes-safe-pool").symlink_to(
|
|
"/etc/passwd"
|
|
)
|
|
with pytest.raises(protocol.ProtocolError, match="symlink"):
|
|
scm._workspace_identity(
|
|
checkout,
|
|
"titan-iac",
|
|
"feature/hermes-safe-pool",
|
|
)
|
|
|
|
|
|
def test_scm_paths_and_identity_reject_symlink_and_git_tampering(
|
|
tmp_path, monkeypatch
|
|
):
|
|
workspace = tmp_path / "workspace"
|
|
workspace.mkdir()
|
|
workspace_link = tmp_path / "workspace-link"
|
|
workspace_link.symlink_to(workspace, target_is_directory=True)
|
|
monkeypatch.setattr(scm, "WORKSPACE_ROOT", workspace_link)
|
|
with pytest.raises(protocol.ProtocolError, match="root"):
|
|
scm.workspace_path(assignment())
|
|
|
|
monkeypatch.setattr(scm, "WORKSPACE_ROOT", workspace)
|
|
(workspace / "runs").mkdir()
|
|
(workspace / "runs/metis").symlink_to(tmp_path, target_is_directory=True)
|
|
with pytest.raises(protocol.ProtocolError, match="parent"):
|
|
scm.workspace_path(assignment())
|
|
|
|
state = tmp_path / "state"
|
|
state.mkdir()
|
|
monkeypatch.setattr(scm, "SCM_ROOT", state)
|
|
expected_state = state / "metis-t_deadbeef-42.json"
|
|
expected_state.symlink_to("/etc/passwd")
|
|
with pytest.raises(protocol.ProtocolError, match="state"):
|
|
scm._state_path(assignment())
|
|
|
|
checkout = tmp_path / "checkout"
|
|
checkout.mkdir()
|
|
with pytest.raises(protocol.ProtocolError, match="metadata"):
|
|
scm._workspace_identity(checkout, "metis", "wt/t_deadbeef")
|
|
init_checkout(checkout)
|
|
subprocess.run(
|
|
[
|
|
"git", "-C", str(checkout), "remote", "set-url", "origin",
|
|
"https://evil.example/repo.git",
|
|
],
|
|
check=True,
|
|
)
|
|
with pytest.raises(protocol.ProtocolError, match="origin"):
|
|
scm._workspace_identity(checkout, "metis", "wt/t_deadbeef")
|
|
subprocess.run(
|
|
[
|
|
"git", "-C", str(checkout), "remote", "set-url", "origin",
|
|
"https://scm.bstein.dev/titan/metis.git",
|
|
],
|
|
check=True,
|
|
)
|
|
subprocess.run(
|
|
[
|
|
"git", "-C", str(checkout), "remote", "set-url", "hermes-broker",
|
|
"http://hermes-scm-broker.hermes-scm.svc.cluster.local:9081/"
|
|
"git/atlas/soteria.git",
|
|
],
|
|
check=True,
|
|
)
|
|
with pytest.raises(protocol.ProtocolError, match="broker remote"):
|
|
scm._workspace_identity(checkout, "metis", "wt/t_deadbeef")
|
|
subprocess.run(
|
|
[
|
|
"git", "-C", str(checkout), "remote", "set-url", "hermes-broker",
|
|
"http://hermes-scm-broker.hermes-scm.svc.cluster.local:9081/"
|
|
"git/atlas/metis.git",
|
|
],
|
|
check=True,
|
|
)
|
|
with pytest.raises(protocol.ProtocolError, match="branch"):
|
|
scm._workspace_identity(checkout, "metis", "review/other")
|
|
monkeypatch.setattr(
|
|
scm,
|
|
"_run",
|
|
lambda *arguments, **_kwargs: {
|
|
"remote": (
|
|
"http://hermes-scm-broker.hermes-scm.svc.cluster.local:9081/"
|
|
"git/atlas/metis.git"
|
|
if arguments[-1] == "hermes-broker"
|
|
else "https://scm.bstein.dev/titan/metis.git"
|
|
),
|
|
"symbolic-ref": "wt/t_deadbeef",
|
|
"rev-parse": "invalid",
|
|
}[arguments[0]],
|
|
)
|
|
with pytest.raises(protocol.ProtocolError, match="HEAD"):
|
|
scm._workspace_identity(checkout, "metis", "wt/t_deadbeef")
|