Simplify scan results with readable summary and matched-event CSV

This commit is contained in:
StasonJatham committed 2026-10-05 06:54:18 +02:00
1 parent 711c42b270
commit 8c3a90225f
8 files changed
+235 -46

No files matched your search

+4 -2
View File
@@ -89,7 +89,9 @@ class CliTests(unittest.TestCase):
self.assertEqual(len(destinations), 2)
self.assertEqual((logs / "sample.log").read_text(), original)
for destination in destinations:
config = json.loads((destination / "configuration.json").read_text())
config = json.loads((destination / "details/configuration.json").read_text())
self.assertTrue((destination / "SUMMARY.txt").is_file())
self.assertTrue((destination / "FINDINGS.csv").is_file())
self.assertIsNone(config["year"])
self.assertEqual(config["timezones"], {})
@@ -105,7 +107,7 @@ class CliTests(unittest.TestCase):
self.assertEqual(
main(["scan", "--input", f"ADC={logs}", "--output", str(root / "out")]), 0
)
config = json.loads((root / "out/configuration.json").read_text())
config = json.loads((root / "out/details/configuration.json").read_text())
self.assertEqual(config["appliances"], ["ADC"])
+49
View File
@@ -0,0 +1,49 @@
import csv
import json
import tempfile
import unittest
from pathlib import Path
from netscaler_triage.presentation import present_results
class PresentationTests(unittest.TestCase):
def test_matches_are_separate_from_context_and_evidence_is_preserved(self) -> None:
with tempfile.TemporaryDirectory() as temporary:
output = Path(temporary)
events = [
{"id": 1, "rules": [], "categories": ["update"]},
{"id": 2, "rules": [], "analysis_errors": ["timeout"]},
{
"id": 3,
"rules": ["probe"],
"source": "=unsafe",
"rule_details": [{"description": "A command probe, not execution."}],
"indicator_matches": [{"status": "authorized_test"}],
},
]
original = "".join(json.dumps(event) + "\n" for event in events)
(output / "findings.jsonl").write_text(original)
(output / "summary.json").write_text('{"status":"partial"}')
(output / "IOCS.csv").write_text("type,value\n")
(output / "inputs").mkdir()
present_results(output, {"status": "partial", "counts": {"records": 3}})
with (output / "FINDINGS.csv").open() as handle:
rows = list(csv.DictReader(handle))
self.assertEqual(len(rows), 1)
self.assertEqual(rows[0]["event_id"], "3")
self.assertEqual(rows[0]["source"], "'=unsafe")
self.assertEqual(rows[0]["indicator_status"], "authorized_test")
self.assertEqual((output / "details/findings.jsonl").read_text(), original)
self.assertIn("Processing status: partial", (output / "SUMMARY.txt").read_text())
self.assertEqual(
{path.name for path in output.iterdir()},
{"SUMMARY.txt", "FINDINGS.csv", "IOCS.csv", "details", "inputs"},
)
def test_no_matches_is_not_a_clean_verdict(self) -> None:
with tempfile.TemporaryDirectory() as temporary:
output = Path(temporary)
(output / "findings.jsonl").write_text("")
present_results(output, {"status": "complete"})
self.assertIn("No matches does not prove", (output / "SUMMARY.txt").read_text())
+1 -1
View File
@@ -66,7 +66,7 @@ class SigmaIntegrationTests(unittest.TestCase):
]
)
self.assertEqual(code, 0)
rows = findings(output)
rows = findings(output / "details")
matches = [row for row in rows if row.get("rules")]
self.assertEqual(len(matches), 1)
self.assertEqual(matches[0]["line"], 1)