Simplify scan results with readable summary and matched-event CSV
This commit is contained in:
1 parent
711c42b270
commit
8c3a90225f
8 files changed
+235
-46
No files matched your search
+4
-2
@@ -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"])
|
||||
|
||||
|
||||
|
||||
@@ -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())
|
||||
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user