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
This commit is contained in:
2026-05-08 19:11:54 +00:00
parent e2f56b8cc8
commit 65741644a3
26 changed files with 384 additions and 200 deletions
+15 -3
View File
@@ -50,7 +50,9 @@ class TestFirewallListZones:
class TestFirewallZoneDetails:
@patch("webui.api.firewall.get_zone_info")
def test_success(self, mock_info, client):
@patch("webui.api.firewall.get_available_zones")
def test_success(self, mock_available, mock_info, client):
mock_available.return_value = ["public", "internal"]
mock_info.return_value = {"name": "public", "services": ["ssh"]}
resp = client.get("/api/firewall/zones/public")
assert resp.status_code == 200
@@ -208,11 +210,21 @@ class TestDhcpStaticLease:
assert resp.status_code == 400
@patch("webui.api.dhcp.remove_static_lease")
def test_remove(self, mock_remove, client):
@patch("webui.api.dhcp.get_config")
def test_remove(self, mock_get, mock_remove, client):
mock_get.return_value = {
"dhcp": {"static_leases": [{"mac": "AA:BB:CC", "ip": "10.0.0.5"}]}
}
mock_remove.return_value = None
resp = client.delete("/api/dhcp/static-lease?mac=AA:BB:CC")
assert resp.status_code == 200
@patch("webui.api.dhcp.get_config")
def test_remove_not_found(self, mock_get, client):
mock_get.return_value = {"dhcp": {"static_leases": []}}
resp = client.delete("/api/dhcp/static-lease?mac=AA:BB:CC")
assert resp.status_code == 404
def test_remove_missing_mac(self, client):
resp = client.delete("/api/dhcp/static-lease")
assert resp.status_code == 400
@@ -340,7 +352,7 @@ class TestWireguardInitialize:
resp = client.post("/api/wireguard/initialize")
data = resp.get_json()
assert data["ok"] is True
assert "private_key" not in data["data"]["interface"]
assert data["data"] is None
class TestWireguardGenerateClient: