All checks were successful
ci / validate (push) Successful in 2m51s
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0726e-5232-73f2-aaca-2c05ceb62efb
172 lines
7 KiB
Python
172 lines
7 KiB
Python
import importlib.util
|
|
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
from glas_harness.contract import ExecutionSummary, OperationalReadiness, ToolCall
|
|
from glas_harness.profiles import OperationallyBlockedProfileError, ProfileCatalog
|
|
from glas_harness.reins.rein_aharness import ReinAharness
|
|
|
|
|
|
spec = importlib.util.spec_from_file_location(
|
|
"local_profile_proof", Path(__file__).parents[1] / "scripts/prove-local-profile.py"
|
|
)
|
|
proof = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(proof)
|
|
|
|
|
|
def test_blocked_profile_refuses_before_fixture_or_manager_creation():
|
|
with patch.object(proof.tempfile, "TemporaryDirectory") as temporary, \
|
|
patch.object(proof, "SandboxManager") as manager:
|
|
with pytest.raises(OperationallyBlockedProfileError):
|
|
proof.prove("harness.agent-dev-local@1.0.0", ProfileCatalog())
|
|
temporary.assert_not_called()
|
|
manager.assert_not_called()
|
|
|
|
|
|
def test_unpinned_profile_is_never_a_proof_candidate():
|
|
with pytest.raises(ValueError, match="version-pinned"):
|
|
proof.select_candidate("harness.agent-dev-local", ProfileCatalog())
|
|
|
|
|
|
@pytest.mark.parametrize("changes", [
|
|
{"credential_route_refs": []},
|
|
{"timeout_seconds": 901},
|
|
{"timeout_seconds": None},
|
|
{"budget_tokens": 60001},
|
|
{"budget_tokens": None},
|
|
])
|
|
def test_candidate_requires_credentials_and_explicit_proof_bounds(changes):
|
|
catalog = ProfileCatalog()
|
|
profile, _ = catalog.resolve("harness.agent-dev-local@1.0.0")
|
|
updates = {
|
|
"operational_readiness": OperationalReadiness(status="unverified"),
|
|
"credential_route_refs": ["test-claude-route"],
|
|
"limits": profile.limits.model_copy(update={
|
|
key: value for key, value in changes.items() if key != "credential_route_refs"
|
|
}),
|
|
}
|
|
if "credential_route_refs" in changes:
|
|
updates["credential_route_refs"] = changes["credential_route_refs"]
|
|
catalog.profiles()[(profile.id, profile.version)] = profile.model_copy(update=updates)
|
|
with pytest.raises(ValueError):
|
|
proof.select_candidate(str(profile.ref), catalog)
|
|
|
|
|
|
def test_observer_delegates_actual_dispatch_and_cleanup():
|
|
delegate = MagicMock(spec=ReinAharness)
|
|
observer = proof.ObservedRein(delegate, Path("/absent-source"))
|
|
session = {"transport": MagicMock(), "task_file": "/workspace/.git/task.json"}
|
|
call = ToolCall(name="run_task")
|
|
assert observer.dispatch_tool(session, call) is delegate.dispatch_tool.return_value
|
|
delegate.dispatch_tool.assert_called_once_with(session, call)
|
|
session["transport"].run.return_value.returncode = 0
|
|
observer.cleanup_session(session)
|
|
delegate.cleanup_session.assert_called_once_with(session)
|
|
session["transport"].run.assert_called_once_with(
|
|
["test", "!", "-e", session["task_file"]], timeout=15
|
|
)
|
|
assert observer.task_removed
|
|
|
|
|
|
@pytest.mark.parametrize("report", [
|
|
{"head": "abc", "checks": {}},
|
|
{"head": "wrong", "checks": {key: True for key in proof.CHECKS}},
|
|
{"head": "abc", "checks": {key: "true" for key in proof.CHECKS}},
|
|
])
|
|
def test_observer_rejects_incomplete_mismatched_or_untyped_inspection(report):
|
|
delegate = MagicMock(spec=ReinAharness)
|
|
delegate.end_session.return_value = ExecutionSummary(
|
|
committed=True, outcome="succeeded", commit_sha="abc"
|
|
)
|
|
observer = proof.ObservedRein(delegate, Path("/absent-source"))
|
|
observer.request_id = "proof-request"
|
|
transport = MagicMock()
|
|
transport.run.return_value = subprocess.CompletedProcess([], 0, json.dumps(report), "")
|
|
with pytest.raises(RuntimeError, match="acceptance failed"):
|
|
observer.end_session({"transport": transport, "head_before": "before",
|
|
"task_file": "/workspace/.git/task.json"})
|
|
|
|
|
|
@pytest.fixture
|
|
def repository(tmp_path):
|
|
repo = tmp_path / "sandbox"
|
|
repo.mkdir()
|
|
proof.git(repo, "init", "-q")
|
|
proof.git(repo, "config", "user.name", "Glas Proof Tests")
|
|
proof.git(repo, "config", "user.email", "proof@example.invalid")
|
|
(repo / "sentinel").write_text("unchanged\n")
|
|
proof.git(repo, "add", "sentinel")
|
|
proof.git(repo, "commit", "-qm", "baseline")
|
|
baseline = proof.git(repo, "rev-parse", "HEAD").decode().strip()
|
|
task = repo / ".git/task.json"
|
|
task.write_text("{}")
|
|
task.chmod(0o600)
|
|
(repo / "PROOF.md").write_text("Glas local profile proof.\n")
|
|
proof.git(repo, "add", "PROOF.md")
|
|
proof.git(repo, "commit", "-qm", "proof")
|
|
return repo, baseline, task
|
|
|
|
|
|
def inspect(repository, source):
|
|
repo, baseline, task = repository
|
|
result = subprocess.run(
|
|
["/usr/bin/python3", "-c", proof.INSPECTOR, baseline, str(source), str(task), "req"],
|
|
cwd=repo, capture_output=True, text=True, timeout=15,
|
|
env={"PATH": "/usr/bin:/bin", "HOME": str(repo),
|
|
"SANDBOXER_ACTOR": "agt", "SANDBOXER_PROJECT": "glas-local-proof",
|
|
"SANDBOXER_RUN_ID": "req"},
|
|
)
|
|
assert result.returncode == 0, result.stderr
|
|
return json.loads(result.stdout)
|
|
|
|
|
|
def test_artifact_inspector_validates_content_and_parent_commit(repository, tmp_path):
|
|
report = inspect(repository, tmp_path / "absent-source")
|
|
assert set(report["checks"]) == proof.CHECKS
|
|
assert all(report["checks"].values())
|
|
|
|
|
|
@pytest.mark.parametrize("fault,failed_check", [
|
|
("extra_commit", "one_commit"),
|
|
("wrong_content", "committed_content"),
|
|
("extra_path", "only_expected_path"),
|
|
("untracked", "clean_worktree"),
|
|
("ignored", "clean_worktree"),
|
|
("source_visible", "source_absent"),
|
|
("task_mode", "task_private"),
|
|
])
|
|
def test_artifact_inspector_rejects_false_positive_commits(repository, tmp_path,
|
|
fault, failed_check):
|
|
repo, _, task = repository
|
|
source = tmp_path / "absent-source"
|
|
if fault == "extra_commit":
|
|
proof.git(repo, "commit", "--allow-empty", "-qm", "extra")
|
|
elif fault == "wrong_content":
|
|
(repo / "PROOF.md").write_text("wrong\n")
|
|
proof.git(repo, "commit", "-qam", "wrong", "--amend")
|
|
elif fault == "extra_path":
|
|
(repo / "extra").write_text("unwanted\n")
|
|
proof.git(repo, "add", "extra")
|
|
proof.git(repo, "commit", "-qm", "extra path", "--amend")
|
|
elif fault in {"untracked", "ignored"}:
|
|
(repo / "private-cache").write_text("must not survive\n")
|
|
if fault == "ignored":
|
|
(repo / ".git/info/exclude").write_text("private-cache\n")
|
|
elif fault == "source_visible":
|
|
source.mkdir()
|
|
elif fault == "task_mode":
|
|
task.chmod(0o644)
|
|
report = inspect(repository, source)
|
|
assert report["checks"][failed_check] is False
|
|
|
|
|
|
def test_cli_never_prints_raw_provider_errors(capsys):
|
|
with patch.object(proof, "prove", side_effect=RuntimeError("secret-provider-response")):
|
|
assert proof.main(["--harness-profile", "harness.agent-dev-local@1.0.0"]) == 1
|
|
output = capsys.readouterr().out
|
|
assert "secret-provider-response" not in output
|
|
assert json.loads(output)["error_type"] == "RuntimeError"
|