refactor: unify project structure, improve security, and enhance deployment
- Fix WireGuard private key leak in API responses and config updates - Update systemd service to serve from repo root with adjusted sandbox - Add CLI flags, idempotency, and dev mode to install.sh - Extract common utilities to lib/common.py and webui/api/common.py - Migrate frontend to htmx for simpler, more maintainable UI - Update docs to reflect current architecture and deployment model - Vendor htmx dependencies per project requirements
This commit is contained in:
+19
-19
@@ -26,7 +26,7 @@ class TestParseForwardPorts:
|
||||
|
||||
|
||||
class TestGetActiveZones:
|
||||
@patch("lib.firewall._run")
|
||||
@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()
|
||||
@@ -35,13 +35,13 @@ class TestGetActiveZones:
|
||||
"internal": ["eth1", "eth2"],
|
||||
}
|
||||
|
||||
@patch("lib.firewall._run")
|
||||
@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")
|
||||
@patch("lib.firewall.run")
|
||||
def test_zone_with_no_interfaces(self, mock_run):
|
||||
mock_run.return_value = "dmz"
|
||||
result = firewall.get_active_zones()
|
||||
@@ -49,7 +49,7 @@ class TestGetActiveZones:
|
||||
|
||||
|
||||
class TestGetZoneInfo:
|
||||
@patch("lib.firewall._run")
|
||||
@patch("lib.firewall.run")
|
||||
def test_parses_zone_info(self, mock_run):
|
||||
mock_run.return_value = (
|
||||
"target: default\n"
|
||||
@@ -76,7 +76,7 @@ class TestGetZoneInfo:
|
||||
|
||||
|
||||
class TestGetInterfaces:
|
||||
@patch("lib.firewall._run")
|
||||
@patch("lib.firewall.run")
|
||||
def test_parses_interfaces(self, mock_run):
|
||||
mock_run.return_value = (
|
||||
"1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536\n"
|
||||
@@ -88,7 +88,7 @@ class TestGetInterfaces:
|
||||
|
||||
|
||||
class TestGetRichRules:
|
||||
@patch("lib.firewall._run")
|
||||
@patch("lib.firewall.run")
|
||||
def test_single_rule(self, mock_run):
|
||||
mock_run.return_value = (
|
||||
'rule family="ipv4" port protocol="tcp" port="443" accept;'
|
||||
@@ -96,13 +96,13 @@ class TestGetRichRules:
|
||||
result = firewall.get_rich_rules("public")
|
||||
assert len(result) == 1
|
||||
|
||||
@patch("lib.firewall._run")
|
||||
@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")
|
||||
@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;'
|
||||
@@ -120,14 +120,14 @@ class TestNowIso:
|
||||
|
||||
|
||||
class TestAddForwardPort:
|
||||
@patch("lib.firewall._run")
|
||||
@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")
|
||||
@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)
|
||||
@@ -229,7 +229,7 @@ class TestConfigGet:
|
||||
'{"zones": {"public": {"interfaces": ["eth0"], "services": ["http"], "masquerade": true, "target": "DEFAULT"}}}'
|
||||
)
|
||||
with patch.object(firewall, "CONFIG_FILE", cfg_file):
|
||||
result = firewall.config_get()
|
||||
result = firewall.get_config()
|
||||
assert result["zones"]["public"]["interfaces"] == ["eth0"]
|
||||
assert result["zones"]["public"]["services"] == ["http"]
|
||||
|
||||
@@ -241,7 +241,7 @@ class TestConfigSet:
|
||||
patch.object(firewall, "CONFIG_FILE", cfg_file),
|
||||
patch.object(firewall, "CONFIG_DIR", tmp_path),
|
||||
):
|
||||
firewall.config_set({"zones": {"test": {"interfaces": ["eth0"]}}})
|
||||
firewall.save_config({"zones": {"test": {"interfaces": ["eth0"]}}})
|
||||
import json as _json
|
||||
|
||||
content = _json.loads(cfg_file.read_text())
|
||||
@@ -249,7 +249,7 @@ class TestConfigSet:
|
||||
|
||||
|
||||
class TestConfigApply:
|
||||
@patch("lib.firewall.config_get")
|
||||
@patch("lib.firewall.get_config")
|
||||
@patch("lib.firewall.save_backup")
|
||||
@patch("lib.firewall.get_available_zones")
|
||||
@patch("lib.firewall.create_zone")
|
||||
@@ -287,7 +287,7 @@ class TestConfigApply:
|
||||
mock_set_svcs.assert_called_once_with("public", ["http", "https"])
|
||||
mock_set_mq.assert_called_once_with("public", True)
|
||||
|
||||
@patch("lib.firewall.config_get")
|
||||
@patch("lib.firewall.get_config")
|
||||
@patch("lib.firewall.save_backup")
|
||||
@patch("lib.firewall.get_available_zones")
|
||||
@patch("lib.firewall.create_zone")
|
||||
@@ -325,7 +325,7 @@ class TestConfigApply:
|
||||
|
||||
|
||||
class TestConfigPending:
|
||||
@patch("lib.firewall.config_get")
|
||||
@patch("lib.firewall.get_config")
|
||||
@patch("lib.firewall.get_state")
|
||||
def test_detects_interface_drift(self, mock_state, mock_cfg):
|
||||
mock_cfg.return_value = {
|
||||
@@ -350,7 +350,7 @@ class TestConfigPending:
|
||||
assert result["needs_apply"] is True
|
||||
assert any(c["type"] == "interfaces" for c in result["pending"])
|
||||
|
||||
@patch("lib.firewall.config_get")
|
||||
@patch("lib.firewall.get_config")
|
||||
@patch("lib.firewall.get_state")
|
||||
def test_in_sync(self, mock_state, mock_cfg):
|
||||
mock_cfg.return_value = {
|
||||
@@ -374,7 +374,7 @@ class TestConfigPending:
|
||||
result = firewall.config_pending()
|
||||
assert result["needs_apply"] is False
|
||||
|
||||
@patch("lib.firewall.config_get")
|
||||
@patch("lib.firewall.get_config")
|
||||
@patch("lib.firewall.get_state")
|
||||
def test_detects_services_drift(self, mock_state, mock_cfg):
|
||||
mock_cfg.return_value = {
|
||||
@@ -398,7 +398,7 @@ class TestConfigPending:
|
||||
result = firewall.config_pending()
|
||||
assert any(c["type"] == "services" for c in result["pending"])
|
||||
|
||||
@patch("lib.firewall.config_get")
|
||||
@patch("lib.firewall.get_config")
|
||||
@patch("lib.firewall.get_state")
|
||||
def test_detects_unmanaged_zones(self, mock_state, mock_cfg):
|
||||
mock_cfg.return_value = {"zones": {}}
|
||||
@@ -416,7 +416,7 @@ class TestConfigPending:
|
||||
|
||||
|
||||
class TestConfigEmptyZones:
|
||||
@patch("lib.firewall.config_get")
|
||||
@patch("lib.firewall.get_config")
|
||||
@patch("lib.firewall.save_backup")
|
||||
@patch("lib.firewall.get_available_zones")
|
||||
@patch("lib.firewall.create_zone")
|
||||
|
||||
Reference in New Issue
Block a user