Files
vacuum-wall/tests/test_firewall.py
T
mteehan 65741644a3 Fix dashboard template bugs, acme date parsing, wireguard sudoers match, and stale docs
- dashboard.html: Fix zones, leases, wg_status, cert key names, add services var
- server.py: Pass services to dashboard template via _get_service_status()
- lib/acme.py: Fix dead third date format (%Y%m%d%H%M%z) using astimezone(UTC)
- lib/wireguard.py: Add -- separator to cp command to match sudoers rule
- lib/nginx.py: Replace shallow dict.copy() with {**...} for DEFAULT_SSL
- AGENTS.md: Update test count 149 -> 154
- docs/api.md: Rename cert field expiry -> expires_at
2026-05-08 19:11:54 +00:00

162 lines
5.2 KiB
Python

from datetime import datetime
from unittest.mock import patch
from lib import firewall
class TestParseForwardPorts:
def test_single_entry(self):
result = firewall._parse_forward_ports("port=443/proto=tcp")
assert len(result) == 1
assert result[0]["port"] == 443
assert result[0]["proto"] == "tcp"
def test_multiple_entries(self):
result = firewall._parse_forward_ports(
"port=443/proto=tcp port=80/proto=tcp/toaddr=10.0.0.1/toport=8080"
)
assert len(result) == 2
assert result[0]["port"] == 443
assert result[1]["port"] == 80
assert result[1]["toaddr"] == "10.0.0.1"
assert result[1]["toport"] == 8080
def test_empty_string(self):
assert firewall._parse_forward_ports("") == []
class TestGetActiveZones:
@patch("lib.firewall._run")
def test_parses_active_zones(self, mock_run):
mock_run.return_value = "public\n eth0\ninternal\n eth1\n eth2"
result = firewall.get_active_zones()
assert result == {
"public": ["eth0"],
"internal": ["eth1", "eth2"],
}
@patch("lib.firewall._run")
def test_empty_output(self, mock_run):
mock_run.return_value = ""
result = firewall.get_active_zones()
assert result == {}
@patch("lib.firewall._run")
def test_zone_with_no_interfaces(self, mock_run):
mock_run.return_value = "dmz"
result = firewall.get_active_zones()
assert result == {"dmz": []}
class TestGetZoneInfo:
@patch("lib.firewall._run")
def test_parses_zone_info(self, mock_run):
mock_run.return_value = (
"target: default\n"
"interfaces: eth0\n"
"sources: \n"
"services: ssh dhcp\n"
"ports: 8080/tcp\n"
"protocols: \n"
"forward-ports: \n"
"masquerade: yes\n"
"ics: no\n"
"rich-rules: \n"
"icmp-blocks: \n"
"module: \n"
)
result = firewall.get_zone_info("public")
assert result["name"] == "public"
assert result["services"] == ["ssh", "dhcp"]
assert result["ports"] == ["8080/tcp"]
assert result["masquerade"] is True
assert result["interfaces"] == ["eth0"]
assert result["sources"] == []
assert result["rich-rules"] == []
class TestGetInterfaces:
@patch("lib.firewall._run")
def test_parses_interfaces(self, mock_run):
mock_run.return_value = (
"1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536\n"
"2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500\n"
"3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500\n"
)
result = firewall.get_interfaces()
assert result == ["lo", "eth0", "eth1"]
class TestGetRichRules:
@patch("lib.firewall._run")
def test_single_rule(self, mock_run):
mock_run.return_value = (
'rule family="ipv4" port protocol="tcp" port="443" accept;'
)
result = firewall.get_rich_rules("public")
assert len(result) == 1
@patch("lib.firewall._run")
def test_empty_rules(self, mock_run):
mock_run.return_value = ""
result = firewall.get_rich_rules("public")
assert result == []
@patch("lib.firewall._run")
def test_multiline_rule(self, mock_run):
mock_run.return_value = (
'rule family="ipv4"\n source address="10.0.0.0/24"\n reject;'
)
result = firewall.get_rich_rules("public")
assert len(result) == 1
assert "10.0.0.0/24" in result[0]
class TestNowIso:
def test_returns_iso_string(self):
result = firewall._now_iso()
datetime.fromisoformat(result)
assert "+" in result
class TestAddForwardPort:
@patch("lib.firewall._run")
def test_forward_port_basic(self, mock_run):
mock_run.return_value = ""
firewall.add_forward_port("public", 443, "tcp", toaddr="10.0.0.5", toport=8080)
calls = [c[0][0] for c in mock_run.call_args_list]
assert any("--add-forward-port=" in str(c) for c in calls)
@patch("lib.firewall._run")
def test_forward_port_port_only(self, mock_run):
mock_run.return_value = ""
firewall.add_forward_port("public", 80, "tcp", toport=8080)
class TestGetState:
@patch("lib.firewall.get_available_zones")
@patch("lib.firewall.get_zone_info")
@patch("lib.firewall.get_active_zones")
@patch("lib.firewall.get_interfaces")
@patch("lib.firewall.get_services")
@patch("lib.firewall.get_rich_rules")
def test_returns_full_state(
self,
mock_rich,
mock_services,
mock_ifaces,
mock_active,
mock_zone_info,
mock_available,
):
mock_available.return_value = ["public", "internal"]
mock_active.return_value = {"public": ["eth0"]}
mock_ifaces.return_value = ["eth0", "eth1"]
mock_services.return_value = ["ssh", "http"]
mock_zone_info.return_value = {"name": "public", "services": []}
mock_rich.return_value = []
result = firewall.get_state()
assert "zones" in result
assert "active_zones" in result
assert "timestamp" in result