From 9076b85304014b02e8ee4cf86cb7ad85306b2a92 Mon Sep 17 00:00:00 2001 From: Robert Syrnicki Date: Wed, 7 Oct 2026 16:24:51 +0200 Subject: [PATCH] test: simulate permission errors in wireguard tests instead of chmod 000 CI runs pytest as root, which ignores directory permissions, so the 0o000-directory tests didn't hit the error path: the enable test went on to call the real systemctl and failed, and the status test passed only by accident. Monkeypatch the PermissionError instead, and stub reload so the enable test can never shell out. Co-Authored-By: Claude Opus 5.5 --- tests/test_wireguard.py | 42 +++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/tests/test_wireguard.py b/tests/test_wireguard.py index ba792f7..b5ae07a 100644 --- a/tests/test_wireguard.py +++ b/tests/test_wireguard.py @@ -6,6 +6,7 @@ to its pre-call state. """ import subprocess +from pathlib import Path import pytest @@ -59,14 +60,20 @@ def test_enable_requires_wg_config(tmp_path): wireguard.set_tunnel_enabled(True, conf_path=tmp_path / "furtka-gw.conf") -def test_enable_surfaces_clean_error_on_unreadable_conf_dir(tmp_path): - restricted = tmp_path / "restricted" - restricted.mkdir(mode=0o000) - try: - with pytest.raises(wireguard.WireguardError, match="could not access"): - wireguard.set_tunnel_enabled(True, wg=WG, conf_path=restricted / "furtka-gw.conf") - finally: - restricted.chmod(0o700) +def test_enable_surfaces_clean_error_on_unreadable_conf_dir(tmp_path, monkeypatch): + # Simulated rather than via a 0o000 directory: CI runs as root, which + # ignores directory permissions. + def denied(self, *a, **kw): + raise PermissionError(13, "Permission denied", str(self)) + + monkeypatch.setattr(Path, "mkdir", denied) + + def must_not_reload(action): + raise AssertionError("systemctl must not run when the conf can't be written") + + conf_path = tmp_path / "restricted" / "furtka-gw.conf" + with pytest.raises(wireguard.WireguardError, match="could not access"): + wireguard.set_tunnel_enabled(True, wg=WG, conf_path=conf_path, reload=must_not_reload) def test_default_conf_path_uses_env_override(monkeypatch, tmp_path): @@ -157,20 +164,23 @@ def test_status_not_configured(tmp_path): assert s == {"configured": False, "latest_handshake": None} -def test_status_survives_unreadable_conf_path(tmp_path): +def test_status_survives_unreadable_conf_path(tmp_path, monkeypatch): """Regression: an inaccessible parent directory raises PermissionError even for a path that doesn't exist yet — confirmed by actually hitting this against a real box's /etc/wireguard/ as a non-root user, which crashed the whole /api/gateway/status request with a raw traceback. A read-only status check must degrade to "not configured", never 500. """ - restricted = tmp_path / "restricted" - restricted.mkdir(mode=0o000) - try: - s = wireguard.status(conf_path=restricted / "furtka-gw.conf") - assert s == {"configured": False, "latest_handshake": None} - finally: - restricted.chmod(0o700) # so tmp_path cleanup can remove it + + # Simulated rather than via a 0o000 directory: CI runs as root, which + # ignores directory permissions. + def denied(self): + raise PermissionError(13, "Permission denied", str(self)) + + monkeypatch.setattr(Path, "is_file", denied) + + s = wireguard.status(conf_path=tmp_path / "restricted" / "furtka-gw.conf") + assert s == {"configured": False, "latest_handshake": None} def test_status_configured_reports_handshake(tmp_path):