3394c72814
- bigbrother.py: Click CLI with start/stop/status/activate/deactivate/ kill/config/selftest/modules commands plus Rich interactive menu. Module discovery scans modules/stealth/ for BaseModule subclasses. Supports --daemon mode with PID file and --passive-only flag. - tests/conftest.py: Shared fixtures (tmp_dir, mock_config, mock_bus, mock_state, hardware_tier_override, project_root) - tests/test_bus.py: 6 tests for EventBus pub/sub, filtering, wildcards - tests/test_engine.py: 5 tests for Engine lifecycle, deps, tier, phase - tests/test_crypto.py: 5 tests for AES-256-GCM, file encryption, KDF - tests/test_resource.py: 7 tests for hardware detection, memory, disk - tests/test_tool_manager.py: 6 tests for subprocess management - tests/test_stealth_modules.py: 4 parametrized test classes covering all 12 stealth modules (import, inheritance, attributes, instantiation)
114 lines
4.0 KiB
Python
114 lines
4.0 KiB
Python
"""Tests for modules/stealth/ — Stealth module import and structure validation."""
|
|
|
|
import inspect
|
|
import importlib
|
|
import os
|
|
import sys
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
from modules.base import BaseModule
|
|
|
|
|
|
# All stealth modules defined in modules/stealth/__init__.py
|
|
STEALTH_MODULE_NAMES = [
|
|
"MacManager",
|
|
"ProcessDisguise",
|
|
"LogSuppression",
|
|
"EncryptedStorage",
|
|
"TmpfsManager",
|
|
"Watchdog",
|
|
"AntiForensics",
|
|
"TrafficMimicry",
|
|
"JA3Spoofer",
|
|
"IDSTester",
|
|
"LKMRootkit",
|
|
"OverlayfsManager",
|
|
]
|
|
|
|
STEALTH_MODULE_DOTTED = [
|
|
"modules.stealth.mac_manager",
|
|
"modules.stealth.process_disguise",
|
|
"modules.stealth.log_suppression",
|
|
"modules.stealth.encrypted_storage",
|
|
"modules.stealth.tmpfs_manager",
|
|
"modules.stealth.watchdog",
|
|
"modules.stealth.anti_forensics",
|
|
"modules.stealth.traffic_mimicry",
|
|
"modules.stealth.ja3_spoofer",
|
|
"modules.stealth.ids_tester",
|
|
"modules.stealth.lkm_rootkit",
|
|
"modules.stealth.overlayfs_manager",
|
|
]
|
|
|
|
|
|
class TestStealthModulesImportable:
|
|
|
|
@pytest.mark.parametrize("dotted_path", STEALTH_MODULE_DOTTED)
|
|
def test_all_stealth_modules_importable(self, dotted_path):
|
|
"""Each stealth module file can be imported without errors."""
|
|
mod = importlib.import_module(dotted_path)
|
|
assert mod is not None
|
|
|
|
|
|
class TestStealthModulesAreBaseModule:
|
|
|
|
@pytest.mark.parametrize("class_name", STEALTH_MODULE_NAMES)
|
|
def test_stealth_modules_are_base_module(self, class_name):
|
|
"""Each stealth module class is a subclass of BaseModule."""
|
|
import modules.stealth as stealth_pkg
|
|
cls = getattr(stealth_pkg, class_name)
|
|
assert issubclass(cls, BaseModule), f"{class_name} is not a BaseModule subclass"
|
|
|
|
|
|
class TestStealthModuleAttributes:
|
|
|
|
@pytest.mark.parametrize("class_name", STEALTH_MODULE_NAMES)
|
|
def test_stealth_module_attributes(self, class_name):
|
|
"""Each stealth module has required class attributes: name, module_type, priority."""
|
|
import modules.stealth as stealth_pkg
|
|
cls = getattr(stealth_pkg, class_name)
|
|
|
|
assert hasattr(cls, "name"), f"{class_name} missing 'name'"
|
|
assert hasattr(cls, "module_type"), f"{class_name} missing 'module_type'"
|
|
assert hasattr(cls, "priority"), f"{class_name} missing 'priority'"
|
|
assert hasattr(cls, "dependencies"), f"{class_name} missing 'dependencies'"
|
|
assert hasattr(cls, "requires_root"), f"{class_name} missing 'requires_root'"
|
|
|
|
# name should not be 'unnamed' (BaseModule default)
|
|
assert cls.name != "unnamed", f"{class_name} still has default name 'unnamed'"
|
|
|
|
# module_type should be 'stealth'
|
|
assert cls.module_type == "stealth", f"{class_name} module_type is '{cls.module_type}', expected 'stealth'"
|
|
|
|
# priority should be an integer
|
|
assert isinstance(cls.priority, int), f"{class_name} priority is not an int"
|
|
|
|
# dependencies should be a list
|
|
assert isinstance(cls.dependencies, list), f"{class_name} dependencies is not a list"
|
|
|
|
# Check abstract methods are implemented
|
|
for method_name in ("start", "stop", "status", "configure"):
|
|
method = getattr(cls, method_name, None)
|
|
assert method is not None, f"{class_name} missing method '{method_name}'"
|
|
assert callable(method), f"{class_name}.{method_name} is not callable"
|
|
|
|
|
|
class TestStealthModuleInstantiate:
|
|
|
|
@pytest.mark.parametrize("class_name", STEALTH_MODULE_NAMES)
|
|
def test_stealth_module_instantiate(self, class_name, mock_bus, mock_state, mock_config):
|
|
"""Each stealth module can be instantiated with mock bus/state/config."""
|
|
import modules.stealth as stealth_pkg
|
|
cls = getattr(stealth_pkg, class_name)
|
|
|
|
# Instantiate (should not crash)
|
|
instance = cls(bus=mock_bus, state=mock_state, config=mock_config)
|
|
|
|
assert instance is not None
|
|
assert instance.bus is mock_bus
|
|
assert instance.state is mock_state
|
|
assert instance.config is mock_config
|
|
assert instance._running is False
|