evaluate_names_absent returned PASS when its step exited 0 with no output, so five mandatory checks - the ones asserting that provider API keys, forge credentials, a cluster-admin binding, and shared coordinator state are absent - could report a pass on no evidence and turn a NO_GO into a GO. Both name rules now resolve their step through one guard in _line_step, so zero observations are NOT_RUN. Regressions pin all five real catalog specs plus both reachable silence paths: a POSIX pipeline whose status comes from its last stage, and a drifted kubectl -o jsonpath. The pool claim projection emits one <volume>=<claim> line per template volume so a volume without a PVC still counts as an observation rather than reading as drift. Also closes the review's reachable hardening and evidence defects: - pin Gitea paths to atlas/titan-iac on an exact segment boundary and reject relative segments, including percent-encoded ones - forbid impersonation structurally in every mode and vantage; the inner command of kubectl exec is re-checked rather than exempted, and validate_catalog no longer guards only the operator vantage - drop flux and helm from the binary allowlist; they had no pinned release digest, so no allowlisted binary can now be admitted that the executor would refuse to attest - remove the inert --concurrency and --expect-telegram-sessions flags and the dead concurrency bound; Telegram continuity stays mandatory - read the ephemeral pull index page by page, treat the create response as an authoritative source for the pull number, close every number either source names, and surface residue_ref plus exact manual_cleanup commands when creation is uncertain - keep executable_path and executable_sha256 on unrecorded bulk-evidence steps so withholding bytes never withholds binary attestation - revert the repo-wide hygiene legacy-exception mechanism; the contract change here is purely additive and the four pre-existing over-cap files are left to the canonical contract change in PR #14/#15 - correct the runbook ruff format scope so the documented command passes Split hermes_handoff_arming.py out of hermes_handoff_ephemeral.py to keep both modules under the 500-line cap. All 16 handoff modules hold at least 95% line and branch coverage; the mutation gate is 13/13. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
61 lines
1.7 KiB
Python
61 lines
1.7 KiB
Python
"""Tests for the deterministic Hermes handoff mutation gate."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from testing.quality_handoff_mutation import (
|
|
MUTATIONS,
|
|
Mutation,
|
|
MutationReport,
|
|
main,
|
|
run_gate,
|
|
)
|
|
|
|
|
|
ROOT = Path(__file__).parents[2]
|
|
|
|
|
|
def test_every_security_mutant_is_killed() -> None:
|
|
report = run_gate(ROOT)
|
|
assert report.issues == ()
|
|
assert report.score == 100.0
|
|
assert report.killed == report.total >= 9
|
|
|
|
|
|
def test_invalid_anchor_baseline_syntax_and_survivor_are_reported() -> None:
|
|
path = "hermes_handoff_model.py"
|
|
cases = (
|
|
Mutation("missing", path, "not present", "x", "pass"),
|
|
Mutation(
|
|
"baseline",
|
|
path,
|
|
"SCHEMA_VERSION = 1",
|
|
"SCHEMA_VERSION = 2",
|
|
"raise SystemExit(1)",
|
|
),
|
|
Mutation("syntax", path, "SCHEMA_VERSION = 1", "if", "pass"),
|
|
Mutation("survivor", path, "SCHEMA_VERSION = 1", "SCHEMA_VERSION = 2", "pass"),
|
|
)
|
|
report = run_gate(ROOT, cases)
|
|
assert report.killed == 0
|
|
assert len(report.issues) == 4
|
|
assert report.score == 0.0
|
|
|
|
|
|
def test_main_reports_a_perfect_score(capsys) -> None:
|
|
"""Every mutant must die, and the count must track the declared set."""
|
|
assert main() == 0
|
|
total = len(MUTATIONS)
|
|
assert total >= 13
|
|
assert f"{total}/{total} (100.00%)" in capsys.readouterr().out
|
|
|
|
|
|
def test_main_reports_mutation_issues(monkeypatch, capsys) -> None:
|
|
monkeypatch.setattr(
|
|
"testing.quality_handoff_mutation.run_gate",
|
|
lambda _root: MutationReport(1, 0, ("survivor",)),
|
|
)
|
|
assert main() == 1
|
|
assert "survivor" in capsys.readouterr().out
|