mirror of
https://github.com/usestrix/strix.git
synced 2026-08-16 17:27:26 +02:00
Promote the coverage ledger from runtime state to a deliverable: coverage.json beside vulnerabilities.json, a Coverage section rendered into the report from the ledger rather than transcribed by an agent, and SARIF pass / notApplicable / open results so a consumer can tell 'tested and clean' from 'never tested'. Ground it in what the runtime observed rather than only what agents claimed: a risk class an agent carried a skill for and never accounted for is published as a gap (and surfaced back to the root agent from finish_scan while it can still act), and a run cut short is stamped incomplete on both the artifact and the SARIF invocation. Also: make the ledger's duplicate check and insertion one critical section and persist under the lock; key a checkout and the URL it was cloned from onto one threat-model identity; render the calibration metadata (counterevidence, confidence, severity change conditions, fix verification) that was being stored and then dropped.
66 lines
1.7 KiB
Python
66 lines
1.7 KiB
Python
"""finish_scan confronts the root agent with the coverage the runtime can see."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
import pytest
|
|
|
|
from strix.tools.coverage.tools import _record_impl, hydrate_coverage_from_disk
|
|
from strix.tools.finish.tool import _coverage_summary
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
from pathlib import Path
|
|
|
|
|
|
_GRAPH = {
|
|
"statuses": {"agent-1": "completed"},
|
|
"names": {"agent-1": "injection-tester"},
|
|
"metadata": {"agent-1": {"skills": ["sql_injection", "xss"]}},
|
|
}
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _empty_ledger(tmp_path: Path) -> None:
|
|
hydrate_coverage_from_disk(tmp_path)
|
|
|
|
|
|
def _record(risk_area: str) -> None:
|
|
_record_impl(
|
|
surface="POST /api/orders/{id}",
|
|
risk_area=risk_area,
|
|
outcome="no_issue_found",
|
|
evidence="Parameters fuzzed; no anomalies.",
|
|
agent_id="agent-1",
|
|
agent_name="injection-tester",
|
|
)
|
|
|
|
|
|
def test_unrecorded_risk_class_is_reported_back_to_the_root_agent() -> None:
|
|
_record("SQL injection")
|
|
|
|
summary = _coverage_summary(_GRAPH)
|
|
|
|
assert summary["coverage_recorded"] == 1
|
|
assert len(summary["coverage_gaps"]) == 1
|
|
assert "xss" in summary["coverage_gaps"][0]
|
|
assert "unexamined" in summary["coverage_gap_warning"]
|
|
|
|
|
|
def test_fully_accounted_coverage_raises_no_gap_warning() -> None:
|
|
_record("SQL injection")
|
|
_record("cross-site scripting")
|
|
|
|
summary = _coverage_summary(_GRAPH)
|
|
|
|
assert "coverage_gaps" not in summary
|
|
assert "coverage_gap_warning" not in summary
|
|
|
|
|
|
def test_an_empty_ledger_still_warns_first() -> None:
|
|
summary = _coverage_summary(_GRAPH)
|
|
|
|
assert summary["coverage_recorded"] == 0
|
|
assert "No coverage was recorded" in summary["coverage_warning"]
|