Files
NetScaler_forensik/tests/test_cli.py
T

116 lines
5.0 KiB
Python

"""CLI presentation must not corrupt evidence output or generate assessments."""
import contextlib
import io
import json
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch
from rich.console import Console
from netscaler_triage.cli import display_result, main
from netscaler_triage.engine import scan
class CliTests(unittest.TestCase):
def test_help_and_argument_errors(self) -> None:
output = io.StringIO()
with contextlib.redirect_stdout(output), self.assertRaises(SystemExit) as raised:
main(["scan", "--help"])
self.assertEqual(raised.exception.code, 0)
self.assertIn("Log folders or archives", output.getvalue())
self.assertIn("Example:", output.getvalue())
self.assertNotIn("--regex-timeout", output.getvalue())
advanced = io.StringIO()
with contextlib.redirect_stdout(advanced), self.assertRaises(SystemExit):
main(["scan", "--help-all"])
self.assertIn("--regex-timeout", advanced.getvalue())
error = io.StringIO()
with contextlib.redirect_stderr(error), self.assertRaises(SystemExit) as raised:
main(["scan", "--not-a-valid-option"])
self.assertEqual(raised.exception.code, 2)
self.assertIn("Invalid arguments", error.getvalue())
self.assertIn("--help", error.getvalue())
def test_json_and_interactive_output(self) -> None:
result = {"status": "complete", "counts": {"records": 7}}
output = io.StringIO()
with contextlib.redirect_stdout(output):
display_result(result, json_output=True)
self.assertEqual(json.loads(output.getvalue()), result)
self.assertNotIn("\x1b", output.getvalue())
terminal = io.StringIO()
with patch(
"netscaler_triage.cli.Console",
return_value=Console(
file=terminal,
force_terminal=True,
color_system=None,
),
):
display_result(result)
self.assertIn("NetScaler triage results", terminal.getvalue())
def test_missing_file_is_friendly_and_has_no_stdout(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
output, error = io.StringIO(), io.StringIO()
with contextlib.redirect_stdout(output), contextlib.redirect_stderr(error):
code = main(["decode", str(Path(tmp) / "missing.txt")])
self.assertEqual(code, 2)
self.assertEqual(output.getvalue(), "")
self.assertIn("Check that the input file or directory exists", error.getvalue())
def test_scan_does_not_write_an_assessment(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp).resolve()
source = root / "logs"
source.mkdir()
(source / "sample.log").write_text("plain text\n", encoding="utf-8")
scan([("sample", source)], root / "output", [], defaults=False)
self.assertTrue((root / "output/summary.json").is_file())
self.assertFalse((root / "output/BERICHT.txt").exists())
def test_scan_requires_only_a_folder_and_never_overwrites(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp).resolve()
logs = root / "appliance"
logs.mkdir()
original = "ordinary text\n"
(logs / "sample.log").write_text(original, encoding="utf-8")
for _ in range(2):
output, error = io.StringIO(), io.StringIO()
with contextlib.redirect_stdout(output), contextlib.redirect_stderr(error):
self.assertEqual(main(["scan", str(logs)]), 0)
self.assertEqual(json.loads(output.getvalue())["files"], 1)
self.assertIn("Results saved to:", error.getvalue())
destinations = list(root.glob("triage-results-*"))
self.assertEqual(len(destinations), 2)
self.assertEqual((logs / "sample.log").read_text(), original)
for destination in destinations:
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"], {})
def test_named_inputs_remain_supported(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp).resolve()
logs = root / "logs"
logs.mkdir()
with (
contextlib.redirect_stdout(io.StringIO()),
contextlib.redirect_stderr(io.StringIO()),
):
self.assertEqual(
main(["scan", "--input", f"ADC={logs}", "--output", str(root / "out")]), 0
)
config = json.loads((root / "out/details/configuration.json").read_text())
self.assertEqual(config["appliances"], ["ADC"])
if __name__ == "__main__":
unittest.main()