114 lines
4.9 KiB
Python
114 lines
4.9 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 / "configuration.json").read_text())
|
|
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/configuration.json").read_text())
|
|
self.assertEqual(config["appliances"], ["ADC"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|