from pathlib import Path ROOT = Path(__file__).resolve().parents[1] def test_deploy_uses_uploaded_tar_and_versioned_container(): script = (ROOT / "scripts" / "deploy-routeros.sh").read_text() assert 'CONTAINER_NAME="suricata_${VERSION}"' in script assert 'ROOT_DIR="/containers/${CONTAINER_NAME}/root"' in script assert 'IMAGE_TAR_ROS="${1:-}"' in script assert '/container/add name="${CONTAINER_NAME}" file="${IMAGE_TAR_ROS}"' in script assert 'build-routeros.sh' not in script assert 'ROUTER_ARCH' not in script assert '/container/get' not in script def test_upload_helper_only_accepts_ready_tar(): script = (ROOT / "scripts" / "upload-routeros-image.sh").read_text() assert 'IMAGE_PATH="${1:-}"' in script assert 'build-routeros.sh' not in script assert 'ROUTER_ARCH' not in script assert '/container/add' not in script assert '/import' not in script def test_upgrade_helper_reuses_existing_routeros_setup_only(): script = (ROOT / "scripts" / "upgrade-routeros-container.sh").read_text() assert 'CONTAINER_NAME="suricata_${VERSION}"' in script assert 'ROOT_DIR="/containers/${CONTAINER_NAME}/root"' in script assert '/container/add name="${CONTAINER_NAME}" file="${IMAGE_TAR_ROS}"' in script assert 'interface="${CONTAINER_VETH}"' in script assert 'mountlists="${CONTAINER_MOUNTLIST}"' in script assert 'envlist="${CONTAINER_ENVLIST}"' in script assert '/container/get' not in script assert '/interface/bridge/add' not in script assert '/interface/veth/add' not in script assert '/ip/address/add' not in script assert '/ip/firewall/nat/add' not in script assert '/tool/sniffer/set' not in script assert '/container/envs/add' not in script assert '/container/mounts/add list="${CONTAINER_MOUNTLIST}" src="${ROUTER_DISK}/containers/suricata-data" dst=/data' in script def test_routeros_deploy_uses_one_persistent_data_mount(): script = (ROOT / "scripts" / "deploy-routeros.sh").read_text() assert '/container/mounts/add list=IDS_MOUNTS src="${DATA_DIR}" dst=/data' in script assert 'suricata-logs' not in script assert 'suricata-rules' not in script def test_compose_uses_one_named_volume(): compose = (ROOT / "docker-compose.yml").read_text() assert compose.count(':/data') == 1 assert 'routeros-suricata-data' in compose assert 'routeros-suricata-logs' not in compose assert 'routeros-suricata-rules' not in compose def test_routeros_deploy_forwards_ndr_and_persistence_controls(): script = (ROOT / "scripts" / "deploy-routeros.sh").read_text() for key in ( "REDIS_MAXMEMORY_MB", "REDIS_SNAPSHOT_SECONDS", "REDIS_AOF", "TRAFFIC_ARCHIVE_INTERVAL_SECONDS", "TRAFFIC_ARCHIVE_LAG_SECONDS", "TRAFFIC_ARCHIVE_BATCH_SIZE", "NDR_ENABLED", "NDR_CORRELATION_WINDOW_SECONDS", "BEHAVIOR_MIN_OBSERVATIONS", "NDR_AUTO_BLOCK", "NDR_AUTO_BLOCK_RISK", "ROUTEROS_INVENTORY_INTERVAL_SECONDS", "NOTIFY_WEBHOOK_URL", "NOTIFY_MIN_RISK", "NOTIFY_TIMEOUT_SECONDS", "METRICS_ALLOWED_IPS", "METRICS_BASIC_AUTH_USERNAME", "METRICS_BASIC_AUTH_PASSWORD", ): assert f"key={key}" in script def test_routeros_deploy_uses_hybrid_tzsp_capture_without_site_bridge_assumption(): script = (ROOT / "scripts" / "deploy-routeros.sh").read_text() env_example = (ROOT / "deploy-routeros.env.example").read_text() assert 'action=sniff-tzsp' in script assert 'chain=forward' in script assert 'comment="MikroSuricata TZSP IPv4"' in script assert '/ip/firewall/mangle/remove [find where comment="MikroSuricata TZSP IPv4"]' in script assert 'filter-mac-protocol=${TZSP_L2_MAC_PROTOCOL}' in script assert 'TZSP_L2_FILTER_INTERFACE="${TZSP_L2_INTERFACE:-all}"' in script assert 'filter-interface="${TZSP_L2_FILTER_INTERFACE}"' in script assert 'streaming-server=${CONTAINER_IP_ONLY}:${TZSP_PORT}' in script assert 'streaming-port=${TZSP_PORT}' in script # compatibility fallback only assert 'VLAN_ID' not in env_example assert 'TZSP_L2_INTERFACE=' in env_example assert 'TZSP_L2_MAC_PROTOCOL=!ip' in env_example assert 'bridge-trunk' not in script def test_hybrid_capture_migration_helper_supports_dry_run_and_same_owned_rule(): script = (ROOT / "scripts" / "configure-routeros-tzsp-hybrid.sh").read_text() assert 'DRY_RUN' in script assert 'action=sniff-tzsp' in script assert 'comment="MikroSuricata TZSP IPv4"' in script assert 'filter-mac-protocol=${TZSP_L2_MAC_PROTOCOL}' in script assert 'TZSP_L2_FILTER_INTERFACE="${TZSP_L2_INTERFACE:-all}"' in script assert 'streaming-server=${CONTAINER_IP_ONLY}:${TZSP_PORT}' in script def test_routeros_manual_capture_template_is_hybrid_and_not_vlan_specific(): hybrid = ROOT / "routeros" / "02-tzsp-hybrid.rsc" assert hybrid.exists() assert not (ROOT / "routeros" / "02-sniffer-vlan100.rsc").exists() text = hybrid.read_text() assert 'action=sniff-tzsp' in text assert 'filter-mac-protocol=$l2MacProtocol' in text assert ':local l2Interface "all"' in text assert 'filter-vlan=100' not in text