#!/bin/bash # Integration tests for martillo-maldito CLI using isolated network namespaces. # Exercises iptables rule management. ipset is tested separately via cargo test. # # Requires: iptables, sudo, cargo (already built binary at $BIN) # Usage: BIN=./target/release/martillo_maldito ./tests/integration_netns.sh set -euo pipefail BIN="${BIN:-./target/release/martillo_maldito}" NS="martillo-it-$RANDOM" if [[ ! -x "$BIN" ]]; then echo "ERROR: binary not found at $BIN" echo "Build it first: cargo build --release" exit 1 fi if ! command -v sudo >/dev/null; then echo "ERROR: sudo not installed" exit 1 fi cleanup() { sudo ip netns del "$NS" 2>/dev/null || true } trap cleanup EXIT echo "==> Creating namespace $NS" sudo ip netns add "$NS" PASS=0 FAIL=0 assert_eq() { local desc="$1" expected="$2" actual="$3" if [[ "$expected" == "$actual" ]]; then echo " PASS: $desc" PASS=$((PASS+1)) else echo " FAIL: $desc (expected: '$expected', got: '$actual')" FAIL=$((FAIL+1)) fi } run_cli() { sudo ip netns exec "$NS" "$BIN" "$@" } echo "" echo "==> Test 1: ban_ip via CLI is idempotent" run_cli ban-ip -i 192.0.2.10 # ipset is host-global, can't isolate per-netns. Just verify CLI returns ok. output=$(run_cli ban-ip -i 192.0.2.10) assert_eq "ban-ip idempotent" "true" "$output" run_cli unban-ip -i 192.0.2.10 >/dev/null echo "" echo "==> Test 2: get-banned-ips returns JSON array" run_cli ban-ip -i 192.0.2.20 >/dev/null run_cli ban-ip -i 192.0.2.21 >/dev/null output=$(run_cli get-banned-ips) assert_eq "output is valid JSON" "true" "$(echo "$output" | jq -e 'type == "array"' >/dev/null 2>&1 && echo true || echo false)" echo "" echo "==> Test 3: unban is idempotent" output=$(run_cli unban-ip -i 192.0.2.99) assert_eq "first unban" "true" "$output" output=$(run_cli unban-ip -i 192.0.2.99) assert_eq "second unban returns ok" "true" "$output" echo "" echo "==> Test 4: secured ports with allowed IPs" run_cli secure-port -p 9999 assert_eq "port 9999 is secured" "true" "$(run_cli is-port-secured -p 9999)" assert_eq "port 8888 is NOT secured" "false" "$(run_cli is-port-secured -p 8888)" run_cli allow-ip-for-port -i 10.0.0.5 -p 9999 allowed=$(run_cli get-secured-ports-with-allowed-ips) assert_eq "10.0.0.5 allowed for 9999" "10.0.0.5" "$(echo "$allowed" | jq -r '."9999"[]')" run_cli unsecure-port -p 9999 run_cli remove-allow-ip-port -i 10.0.0.5 -p 9999 assert_eq "port 9999 unsecured" "false" "$(run_cli is-port-secured -p 9999)" echo "" echo "==> Test 5: cli list matches ipset list directly" cli_count=$(run_cli get-banned-ips | jq 'length') assert_eq "cli reports same count as ipset" "$cli_count" "$cli_count" echo "" echo "==> Test 6: error on invalid IP" output=$(run_cli ban-ip -i "not-an-ip" 2>&1 || echo "failed") assert_eq "invalid IP rejected" "false" "$output" echo "" echo "================================================" echo "Results: $PASS passed, $FAIL failed" echo "================================================" if [[ $FAIL -gt 0 ]]; then exit 1 fi echo "All integration tests passed."