This commit is contained in:
Rio Griya Putra 2026-10-14 10:49:13 -05:00 • committed by GitHub
commit d2b32ca338
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 60 additions and 21 deletions

View file

@ -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

View file

@ -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."""