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
+42
View File
@@ -52,6 +52,16 @@ class TestRunAcme:
with pytest.raises(RuntimeError):
acme._run_acme(["--list"])
@patch("lib.acme._find_acme")
@patch("lib.acme.subprocess.run")
def test_no_sudo_prefix(self, mock_run, mock_find):
mock_find.return_value = "/usr/local/bin/acme.sh"
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
acme._run_acme(["--list"])
cmd = mock_run.call_args[0][0]
assert cmd[0] == "/usr/local/bin/acme.sh"
assert "sudo" not in cmd
class TestParseListOutput:
def test_parses_single_entry(self):
@@ -128,3 +138,35 @@ class TestGetCertPaths:
assert paths["key"].endswith("example.com/example.com.key")
assert paths["ca"].endswith("example.com/ca.cer")
assert paths["fullchain"].endswith("example.com/fullchain.cer")
class TestDeployHook:
@patch("lib.acme._run_acme")
def test_deploy_registers_hook(self, mock_run):
acme.deploy("example.com")
args = mock_run.call_args[0][0]
assert "--deploy" in args
assert "-d" in args
assert "example.com" in args
assert "--deploy-hook" in args
assert any("acme-deploy.sh" in arg for arg in args)
class TestHasAutoRenew:
@patch("lib.acme.Path.home")
def test_true_when_conf_exists(self, mock_home):
tmpdir = tempfile.mkdtemp()
acme_dir = Path(tmpdir) / ".acme.sh"
acme_dir.mkdir()
conf = acme_dir / "example.com.conf"
conf.touch()
mock_home.return_value = Path(tmpdir)
result = acme._has_auto_renew("example.com")
assert result is True
conf.unlink()
@patch("lib.acme.Path.home")
def test_false_when_conf_missing(self, mock_home):
mock_home.return_value = Path(tempfile.mkdtemp())
result = acme._has_auto_renew("nonexistent.com")
assert result is False