Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions testing/backend/unit/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,128 @@ def test_cli_help_menu():
main()
assert exc_info.value.code == 0
mock_print_help.assert_called_once()


def test_cli_no_args_calls_print_help():
"""With no arguments, main() calls print_help and returns (no SystemExit)."""
with patch("argparse.ArgumentParser.print_help") as mock_print_help, \
patch("sys.argv", ["secuscan"]):
main() # should not raise, just calls print_help
mock_print_help.assert_called_once()


@pytest.mark.anyio
async def test_run_scan_target_dot_defaults_to_secret_scanner():
"""When target is '.', run_scan defaults to secret_scanner plugin."""
mock_plugin = MagicMock()
mock_plugin.name = "Secret Scanner"

mock_pm = MagicMock()
mock_pm.get_plugin.return_value = mock_plugin
mock_pm.plugins = {"secret_scanner": mock_plugin}

mock_executor = MagicMock()
mock_executor.create_task = AsyncMock(return_value="task-dot-1")
mock_executor.execute_task = AsyncMock()

mock_queue = AsyncMock()
mock_queue.get.side_effect = [{"type": "status", "data": "completed"}]
mock_executor.subscribe.return_value = mock_queue

mock_db = AsyncMock()
mock_db.fetchone.return_value = {
"id": "task-dot-1",
"plugin_id": "secret_scanner",
"tool_name": "secret_scanner",
"target": ".",
"status": "completed",
"created_at": "2026-01-01",
"preset": None,
"inputs_json": "{}",
"command_used": "",
"structured_json": "{}",
}

with patch("backend.secuscan.cli.init_db", new_callable=AsyncMock), \
patch("backend.secuscan.cli.init_cache", new_callable=AsyncMock), \
patch("backend.secuscan.cli.init_plugins", new_callable=AsyncMock), \
patch("backend.secuscan.cli.get_plugin_manager", return_value=mock_pm), \
patch("backend.secuscan.cli.executor", mock_executor), \
patch("backend.secuscan.cli.get_db", return_value=mock_db):

result = await run_scan(".", "nmap", "console")
assert result == 0
mock_executor.create_task.assert_called_once()


@pytest.mark.anyio
async def test_run_scan_task_not_found_returns_1():
"""When the task record is missing from DB after execution, run_scan returns 1."""
mock_plugin = MagicMock()
mock_plugin.name = "Nmap"

mock_pm = MagicMock()
mock_pm.get_plugin.return_value = mock_plugin

mock_executor = MagicMock()
mock_executor.create_task = AsyncMock(return_value="task-missing-1")
mock_executor.execute_task = AsyncMock()

mock_queue = AsyncMock()
mock_queue.get.side_effect = [{"type": "status", "data": "completed"}]
mock_executor.subscribe.return_value = mock_queue

mock_db = AsyncMock()
mock_db.fetchone.return_value = None # task record gone

with patch("backend.secuscan.cli.init_db", new_callable=AsyncMock), \
patch("backend.secuscan.cli.init_cache", new_callable=AsyncMock), \
patch("backend.secuscan.cli.init_plugins", new_callable=AsyncMock), \
patch("backend.secuscan.cli.get_plugin_manager", return_value=mock_pm), \
patch("backend.secuscan.cli.executor", mock_executor), \
patch("backend.secuscan.cli.get_db", return_value=mock_db):

result = await run_scan("127.0.0.1", "nmap", "console")
assert result == 1


@pytest.mark.anyio
async def test_run_scan_failed_task_returns_1():
"""When task status is 'failed', run_scan returns 1 without printing a report."""
mock_plugin = MagicMock()
mock_plugin.name = "Nmap"

mock_pm = MagicMock()
mock_pm.get_plugin.return_value = mock_plugin

mock_executor = MagicMock()
mock_executor.create_task = AsyncMock(return_value="task-failed-1")
mock_executor.execute_task = AsyncMock()

mock_queue = AsyncMock()
mock_queue.get.side_effect = [{"type": "status", "data": "failed"}]
mock_executor.subscribe.return_value = mock_queue

mock_db = AsyncMock()
mock_db.fetchone.return_value = {
"id": "task-failed-1",
"plugin_id": "nmap",
"tool_name": "nmap",
"target": "127.0.0.1",
"status": "failed",
"created_at": "2026-01-01",
"preset": None,
"inputs_json": "{}",
"command_used": "",
"structured_json": None,
}

with patch("backend.secuscan.cli.init_db", new_callable=AsyncMock), \
patch("backend.secuscan.cli.init_cache", new_callable=AsyncMock), \
patch("backend.secuscan.cli.init_plugins", new_callable=AsyncMock), \
patch("backend.secuscan.cli.get_plugin_manager", return_value=mock_pm), \
patch("backend.secuscan.cli.executor", mock_executor), \
patch("backend.secuscan.cli.get_db", return_value=mock_db):

result = await run_scan("127.0.0.1", "nmap", "console")
assert result == 1
Loading