mirror of
https://github.com/usestrix/strix.git
synced 2026-10-15 04:18:10 +00:00
Merge e68e768424 into 87f2d783d6
This commit is contained in:
commit
d2b32ca338
2 changed files with 60 additions and 21 deletions
|
|
@ -138,10 +138,13 @@ def write_run_record(run_dir: Path, run_record: dict[str, Any]) -> None:
|
|||
|
||||
def write_executive_report(run_dir: Path, final_scan_result: str) -> None:
|
||||
path = run_dir / "penetration_test_report.md"
|
||||
with path.open("w", encoding="utf-8") as f:
|
||||
f.write("# Security Penetration Test Report\n\n")
|
||||
f.write(f"**Generated:** {datetime.now(UTC).strftime('%Y-%m-%d %H:%M:%S UTC')}\n\n")
|
||||
f.write(f"{final_scan_result}\n")
|
||||
generated_at = datetime.now(UTC).strftime("%Y-%m-%d %H:%M:%S UTC")
|
||||
report_text = (
|
||||
"# Security Penetration Test Report\n\n"
|
||||
f"**Generated:** {generated_at}\n\n"
|
||||
f"{final_scan_result}\n"
|
||||
)
|
||||
atomic_write_text(path, report_text)
|
||||
logger.info("Saved final penetration test report to: %s", path)
|
||||
|
||||
|
||||
|
|
@ -206,18 +209,23 @@ def atomic_write_text(path: Path, payload: str) -> None:
|
|||
into ``\\r\\r\\n`` on Windows.
|
||||
"""
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode="w",
|
||||
encoding="utf-8",
|
||||
newline="",
|
||||
dir=str(path.parent),
|
||||
prefix=f".{path.name}.",
|
||||
suffix=".tmp",
|
||||
delete=False,
|
||||
) as tmp:
|
||||
tmp.write(payload)
|
||||
tmp_path = Path(tmp.name)
|
||||
tmp_path.replace(path)
|
||||
tmp_path: Path | None = None
|
||||
try:
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode="w",
|
||||
encoding="utf-8",
|
||||
newline="",
|
||||
dir=str(path.parent),
|
||||
prefix=f".{path.name}.",
|
||||
suffix=".tmp",
|
||||
delete=False,
|
||||
) as tmp:
|
||||
tmp_path = Path(tmp.name)
|
||||
tmp.write(payload)
|
||||
tmp_path.replace(path)
|
||||
finally:
|
||||
if tmp_path is not None:
|
||||
tmp_path.unlink(missing_ok=True)
|
||||
|
||||
|
||||
def render_vulnerability_md(report: dict[str, Any]) -> str: # noqa: PLR0912, PLR0915
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ from __future__ import annotations
|
|||
|
||||
import csv
|
||||
import json
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
|
|
@ -18,10 +19,6 @@ from strix.report.writer import (
|
|||
)
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _sample_report(**overrides: Any) -> dict[str, Any]:
|
||||
base: dict[str, Any] = {
|
||||
"id": "vuln-0001",
|
||||
|
|
@ -240,6 +237,40 @@ def test_write_executive_report_writes_markdown(tmp_path: Path) -> None:
|
|||
assert "Scan complete. No critical issues." in content
|
||||
|
||||
|
||||
def test_write_executive_report_delegates_to_atomic_write(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
calls: list[tuple[Path, str]] = []
|
||||
|
||||
def fake_atomic(path: Path, payload: str) -> None:
|
||||
calls.append((path, payload))
|
||||
|
||||
monkeypatch.setattr("strix.report.writer.atomic_write_text", fake_atomic)
|
||||
write_executive_report(tmp_path, "Executive test summary.")
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0][0] == tmp_path / "penetration_test_report.md"
|
||||
assert "Executive test summary." in calls[0][1]
|
||||
|
||||
|
||||
def test_atomic_write_text_cleans_up_temp_file_on_replace_failure(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
target = tmp_path / "report.md"
|
||||
|
||||
def fail_replace(_self: Path, _other: Path) -> Path:
|
||||
raise OSError("Simulated disk replace error")
|
||||
|
||||
monkeypatch.setattr(Path, "replace", fail_replace)
|
||||
|
||||
with pytest.raises(OSError, match="Simulated disk replace error"):
|
||||
atomic_write_text(target, "content")
|
||||
|
||||
# Assert no leaked .tmp files exist in directory
|
||||
assert list(tmp_path.glob(".*.tmp")) == []
|
||||
|
||||
|
||||
|
||||
def test_render_vulnerability_md_surfaces_calibration_metadata() -> None:
|
||||
"""Confidence, the case against the finding, and retest status are part of
|
||||
the deliverable — storing them without rendering hides the reasoning."""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue