This repository has been archived on 2026-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
orchestrator/agent-team/tests/test_task_model.py

137 lines
3.7 KiB
Python
Raw Normal View History

"""Unit tests for agent_team.task_model (§3.3, §3.3.1)."""
from __future__ import annotations
from agent_team.task_model import (
Phase,
PipelineState,
TaskRecord,
TaskStatus,
new_thread_id,
task_from_dict,
task_from_json,
task_to_dict,
task_to_json,
)
def test_new_thread_id_unique_hex() -> None:
a = new_thread_id()
b = new_thread_id()
assert a != b
assert len(a) == 32
int(a, 16) # must be valid hex
def test_phase_members() -> None:
assert {p.name for p in Phase} == {
"INTAKE",
"CLARIFY",
"PLAN",
"REVIEW",
"BUILD",
"VERIFY",
"CONF_DRAFT",
"CONF_GATE",
"CONF_WRITE",
"PARKED",
"DONE",
}
def test_task_record_defaults() -> None:
rec = TaskRecord(
thread_id="t1",
status=TaskStatus.ACTIVE,
current_phase=Phase.INTAKE,
)
assert rec.qa_history == []
assert rec.plan is None
assert rec.review_verdicts == []
assert rec.candidate_diff is None
assert rec.diff_hash is None
assert rec.ci_results is None
assert rec.transport == ""
def test_to_dict_serializes_enums_to_values() -> None:
rec = TaskRecord(
thread_id="t1",
status=TaskStatus.WAITING_HUMAN,
current_phase=Phase.CLARIFY,
)
data = task_to_dict(rec)
assert data["status"] == "waiting_human"
assert data["current_phase"] == "clarify"
def test_roundtrip_dict() -> None:
rec = TaskRecord(
thread_id="t1",
status=TaskStatus.PARKED,
current_phase=Phase.PLAN,
qa_history=[{"q": "x", "a": "y"}],
plan={"phases": [1, 2]},
review_verdicts=["REQUEST_CHANGES"],
candidate_diff="diff --git a b",
diff_hash="deadbeef",
ci_results={"conclusion": "success"},
run_id="27990718108",
ci_correlation_tag="t1-1a2b3c",
dispatched_at="2026-06-17T00:30:00Z",
fix(agent-team): remediate C1 security-review BLOCK (2 HIGH + MED/LOW) High-recall /sh-security-review fan-out + proof-or-kill verifier found two confirmed HIGH; both now closed (verified empirically against the working tree): - LOGIC-RACE-01 (HIGH, CWE-835): the build-loop budget was structurally dead (verifier read a shared wiring-time VerifierConfig.build_loops, always 0, so the max_build_loops park never fired -> a perpetually-failing task looped BUILD->DISPATCH->VERIFY forever, force-pushing + firing a CI run each round). Threaded build_loops through durable PipelineState/TaskRecord; verifier reads state.get('build_loops',0), writes the incremented count back on each FAIL, and PARKS at max_build_loops. Parks after exactly N failures, never unbounded. - SEC-01 (HIGH, CWE-532) + SEC-02 (MED, CWE-214): p3_rollback.sh echoed the live App JWT to stdout in default dry-run and passed it as a gh argv literal. Added redact_secrets (Bearer/Authorization/ghX_/PEM masking) through run_or_plan; the App uninstall now uses curl -H @<0600 tempfile> (JWT never on argv), shredded after. Empirical: app/incident/all dry-runs leak 0 JWT occurrences. - SEC-03 (MED, CWE-798): assert_no_write_token now applies the PEM regex + the configured App-ID to env/config VALUES (not just files) — an App private key under a benign env name is caught. - SEC-04 (LOW) + P3-IAC-08 (LOW): tightened the box GITHUB_TOKEN fallback / value-scan; staged-only WARN on the live workflow revert. Suite: 1382 passed, ruff clean. Branch only; not merged/deployed. NOTE: re-verifier flagged SEC-01 as open by grepping COMMITTED blobs (the fix was uncommitted working-tree state); independently confirmed closed empirically.
2026-06-23 19:40:59 -04:00
build_loops=2,
transport="slack",
created_at="2026-06-17T00:00:00Z",
updated_at="2026-06-17T01:00:00Z",
)
restored = task_from_dict(task_to_dict(rec))
assert restored == rec
# P3 dispatch->verify plumbing fields survive the dict round-trip.
assert restored.run_id == "27990718108"
assert restored.ci_correlation_tag == "t1-1a2b3c"
assert restored.dispatched_at == "2026-06-17T00:30:00Z"
fix(agent-team): remediate C1 security-review BLOCK (2 HIGH + MED/LOW) High-recall /sh-security-review fan-out + proof-or-kill verifier found two confirmed HIGH; both now closed (verified empirically against the working tree): - LOGIC-RACE-01 (HIGH, CWE-835): the build-loop budget was structurally dead (verifier read a shared wiring-time VerifierConfig.build_loops, always 0, so the max_build_loops park never fired -> a perpetually-failing task looped BUILD->DISPATCH->VERIFY forever, force-pushing + firing a CI run each round). Threaded build_loops through durable PipelineState/TaskRecord; verifier reads state.get('build_loops',0), writes the incremented count back on each FAIL, and PARKS at max_build_loops. Parks after exactly N failures, never unbounded. - SEC-01 (HIGH, CWE-532) + SEC-02 (MED, CWE-214): p3_rollback.sh echoed the live App JWT to stdout in default dry-run and passed it as a gh argv literal. Added redact_secrets (Bearer/Authorization/ghX_/PEM masking) through run_or_plan; the App uninstall now uses curl -H @<0600 tempfile> (JWT never on argv), shredded after. Empirical: app/incident/all dry-runs leak 0 JWT occurrences. - SEC-03 (MED, CWE-798): assert_no_write_token now applies the PEM regex + the configured App-ID to env/config VALUES (not just files) — an App private key under a benign env name is caught. - SEC-04 (LOW) + P3-IAC-08 (LOW): tightened the box GITHUB_TOKEN fallback / value-scan; staged-only WARN on the live workflow revert. Suite: 1382 passed, ruff clean. Branch only; not merged/deployed. NOTE: re-verifier flagged SEC-01 as open by grepping COMMITTED blobs (the fix was uncommitted working-tree state); independently confirmed closed empirically.
2026-06-23 19:40:59 -04:00
# The durable build<->verify loop count round-trips (LOGIC-RACE-01).
assert restored.build_loops == 2
def test_build_loops_defaults_zero_and_roundtrips() -> None:
rec = TaskRecord(
thread_id="t1",
status=TaskStatus.ACTIVE,
current_phase=Phase.BUILD,
)
assert rec.build_loops == 0
# A dict missing build_loops (older record) defaults to 0, not a crash.
legacy = task_to_dict(rec)
del legacy["build_loops"]
assert task_from_dict(legacy).build_loops == 0
def test_roundtrip_json() -> None:
rec = TaskRecord(
thread_id="t2",
status=TaskStatus.DONE,
current_phase=Phase.DONE,
diff_hash="abc",
)
restored = task_from_json(task_to_json(rec))
assert restored == rec
assert restored.status is TaskStatus.DONE
assert restored.current_phase is Phase.DONE
def test_pipeline_state_keys_mirror_task_record() -> None:
# Every PipelineState key should be a TaskRecord field.
state_keys = set(PipelineState.__annotations__)
record_fields = set(TaskRecord.__dataclass_fields__)
assert state_keys == record_fields
def test_pipeline_state_usable_as_dict() -> None:
state: PipelineState = {
"thread_id": "t1",
"status": "active",
"current_phase": "intake",
}
assert state["thread_id"] == "t1"