diff --git a/data/dnsmasq/config.json.example b/data/dnsmasq/config.json.example deleted file mode 100644 index 095cad7..0000000 --- a/data/dnsmasq/config.json.example +++ /dev/null @@ -1,14 +0,0 @@ -{ - "dhcp": { - "ranges": [], - "static_leases": [] - }, - "dns": { - "upstreams": [ - "8.8.8.8", - "1.1.1.1" - ], - "domain": null, - "custom_records": [] - } -} diff --git a/lib/acme.py b/lib/acme.py index 14f70d5..c114d8a 100644 --- a/lib/acme.py +++ b/lib/acme.py @@ -2,7 +2,7 @@ ACME certificate manager for Vacuum Wall. Wraps acme.sh to issue, renew, and manage SSL/TLS certificates -from Let's Encrypt (or other ACME providers). acme.sh runs as the +from ACME providers such as ZeroSSL or Let's Encrypt. acme.sh runs as the vacuum-wall system user; nginx is reloaded via a deploy hook script. """ @@ -16,16 +16,17 @@ from pathlib import Path logger = logging.getLogger(__name__) +PROJECT_DIR = Path(__file__).resolve().parent.parent +_ACME_HOME = PROJECT_DIR / "data" / "acme" +_DEPLOY_HOOK = str(PROJECT_DIR / "system" / "acme-deploy.sh") + _ACME_ENVIRON = { - "HOME": str(Path.home()), + "HOME": str(PROJECT_DIR), "PATH": os.environ.get( "PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ), } -PROJECT_DIR = Path("/home/wall/vacuum-wall") -_DEPLOY_HOOK = str(PROJECT_DIR / "system" / "acme-deploy.sh") - def _find_acme() -> str: """Locate the acme.sh binary on the system. @@ -41,7 +42,7 @@ def _find_acme() -> str: FileNotFoundError: If acme.sh cannot be found. """ candidates = [ - Path.home() / ".acme.sh" / "acme.sh", + _ACME_HOME / "acme.sh", Path("/usr/local/bin/acme.sh"), ] @@ -81,12 +82,15 @@ def _run_acme(args: list[str]) -> str: """ acme_bin = _find_acme() + # Check for ACME_HOME env var (set by systemd in production) + acme_home_env = os.environ.get("ACME_HOME", str(_ACME_HOME)) + cmd: list[str] = [ acme_bin, "--home", - str(Path.home() / ".acme.sh"), + acme_home_env, "--config-home", - str(Path.home() / ".acme.sh"), + acme_home_env, *args, ] @@ -131,7 +135,8 @@ def set_email(email: str) -> None: def get_email() -> str: """Return the ACME contact email, or '' if none is configured.""" try: - account_conf = Path.home() / ".acme.sh" / "account.conf" + acme_home = Path(os.environ.get("ACME_HOME", str(_ACME_HOME))) + account_conf = acme_home / "account.conf" if account_conf.is_file(): text = account_conf.read_text() match = re.search(r"^ACME_LEEMAIL=(.+)$", text, re.MULTILINE) @@ -246,7 +251,8 @@ def list_certs() -> list[dict]: certs: list[dict] = [] entries = _parse_list_output(raw) - acme_home = Path.home() / ".acme.sh" + acme_home_env = os.environ.get("ACME_HOME", str(_ACME_HOME)) + acme_home = Path(acme_home_env) for entry in entries: main = entry["main_domain"] @@ -393,7 +399,8 @@ def get_cert_paths(domain: str) -> dict: Returns: Dict with keys 'cert', 'key', 'ca', 'fullchain' mapped to paths. """ - acme_home = str(Path.home() / ".acme.sh" / domain) + acme_home_env = os.environ.get("ACME_HOME", str(_ACME_HOME)) + acme_home = str(Path(acme_home_env) / domain) return { "cert": f"{acme_home}/{domain}.cert", "key": f"{acme_home}/{domain}.key", @@ -484,6 +491,6 @@ def _has_auto_renew(domain: str) -> bool: under ``~/.acme.sh/``; existence of this file means the systemd timer's ``--cron`` run will pick it up. """ - acme_home = Path.home() / ".acme.sh" - domain_conf = acme_home / f"{domain}.conf" + acme_home_env = os.environ.get("ACME_HOME", str(_ACME_HOME)) + domain_conf = Path(acme_home_env) / f"{domain}.conf" return bool(domain_conf.is_file()) diff --git a/lib/dnsmasq.py b/lib/dnsmasq.py index 9089d07..0f82692 100644 --- a/lib/dnsmasq.py +++ b/lib/dnsmasq.py @@ -15,9 +15,10 @@ from typing import Any from jinja2 import Environment, FileSystemLoader -PROJECT_DIR = Path("/home/wall/vacuum-wall") +PROJECT_DIR = Path(__file__).resolve().parent.parent +CONFIG_DIR = PROJECT_DIR / "config" / "dnsmasq" DATA_DIR = PROJECT_DIR / "data" / "dnsmasq" -CONFIG_PATH = DATA_DIR / "config.json" +CONFIG_PATH = CONFIG_DIR / "config.json" FRAGMENTS_DIR = DATA_DIR / "fragments" DNSMASQ_CONF = "/etc/dnsmasq.d/vacuum-wall.conf" LEASE_FILE = "/var/lib/dnsmasq/dnsmasq.leases" @@ -46,6 +47,7 @@ DEFAULT_CFG: dict[str, Any] = { def _ensure_dirs() -> None: + CONFIG_DIR.mkdir(parents=True, exist_ok=True) DATA_DIR.mkdir(parents=True, exist_ok=True) FRAGMENTS_DIR.mkdir(parents=True, exist_ok=True) diff --git a/lib/nginx.py b/lib/nginx.py index d822cc4..4f46f85 100644 --- a/lib/nginx.py +++ b/lib/nginx.py @@ -12,10 +12,11 @@ from pathlib import Path from jinja2 import Environment, FileSystemLoader -PROJECT_DIR = Path("/home/wall/vacuum-wall") +PROJECT_DIR = Path(__file__).resolve().parent.parent +CONFIG_DIR = PROJECT_DIR / "config" / "nginx" DATA_DIR = PROJECT_DIR / "data" / "nginx" SITES_DIR = DATA_DIR / "sites-enabled" -CONFIG_FILE = DATA_DIR / "config.json" +CONFIG_FILE = CONFIG_DIR / "config.json" INCLUDE_FILE = Path("/etc/nginx/conf.d/vacuum-wall.conf") SSL_SNIPPET = Path("/etc/nginx/snippets/vacuum-wall-ssl.conf") HTPASSWD_FILE = DATA_DIR / ".htpasswd" @@ -53,6 +54,7 @@ DEFAULT_CONFIG = { def _ensure_dirs(): + CONFIG_DIR.mkdir(parents=True, exist_ok=True) SITES_DIR.mkdir(parents=True, exist_ok=True) @@ -178,13 +180,15 @@ def generate_server_conf(domain_cfg: dict) -> str: cert=domain_cfg.get("cert"), auth=domain_cfg.get("auth"), is_management=False, + acme_home=str(PROJECT_DIR / "data" / "acme"), + certs_dir=str(PROJECT_DIR / "data" / "certs"), ) def _generate_management_conf(management: dict) -> str: tmpl = ENV.get_template("nginx/server_block.conf") return tmpl.render( - domain=management.get("domain", "wall.lan"), + domain=management.get("domain"), backend=dict( management.get("backend", {}), host="127.0.0.1", port=9090, proto="http" ), @@ -193,6 +197,8 @@ def _generate_management_conf(management: dict) -> str: cert=None, auth=management.get("auth"), is_management=True, + acme_home=str(PROJECT_DIR / "data" / "acme"), + certs_dir=str(PROJECT_DIR / "data" / "certs"), ) diff --git a/lib/wireguard.py b/lib/wireguard.py index 3b4fe37..4d2795d 100644 --- a/lib/wireguard.py +++ b/lib/wireguard.py @@ -13,8 +13,8 @@ from pathlib import Path from jinja2 import Environment, FileSystemLoader -PROJECT_DIR = Path("/home/wall/vacuum-wall") -CONFIG_PATH = str(PROJECT_DIR / "data" / "wireguard" / "config.json") +PROJECT_DIR = Path(__file__).resolve().parent.parent +CONFIG_PATH = str(PROJECT_DIR / "config" / "wireguard" / "config.json") WG_CONF_PATH = "/etc/wireguard/wg0.conf" WG_QUICK_BIN = "wg-quick" WG_BIN = "wg" @@ -141,7 +141,7 @@ def apply() -> None: conf_text = generate_conf(cfg) save_config(cfg) # ensure latest state persisted - local_dir = Path("/home/wall/vacuum-wall/data/wireguard") + local_dir = PROJECT_DIR / "data" / "wireguard" local_dir.mkdir(parents=True, exist_ok=True) local_tmp = local_dir / "wg0.conf.tmp" with open(local_tmp, "w") as f: diff --git a/system/nginx/server_block.conf b/system/nginx/server_block.conf index 9cac9a6..dc3094c 100644 --- a/system/nginx/server_block.conf +++ b/system/nginx/server_block.conf @@ -21,21 +21,21 @@ server { {% if cert.type == "acme" %} # Certificate managed by acme.sh {% if cert.email %} # ACME contact: {{ cert.email }} -{% endif %} ssl_certificate /home/vacuum-wall/.acme.sh/{{ domain }}/fullchain.cer; - ssl_certificate_key /home/vacuum-wall/.acme.sh/{{ domain }}/{{ domain }}.key; +{% endif %} ssl_certificate {{ acme_home }}/{{ domain }}/fullchain.cer; + ssl_certificate_key {{ acme_home }}/{{ domain }}/{{ domain }}.key; {% elif cert.type == "file" %} ssl_certificate {{ cert.path }}; ssl_certificate_key {{ cert.key_path }}; {% elif cert.type == "selfsigned" %} - ssl_certificate /home/wall/vacuum-wall/data/certs/{{ domain }}.crt; - ssl_certificate_key /home/wall/vacuum-wall/data/certs/{{ domain }}.key; + ssl_certificate {{ certs_dir }}/{{ domain }}.crt; + ssl_certificate_key {{ certs_dir }}/{{ domain }}.key; {% endif %} {% elif is_management %} - ssl_certificate /home/wall/vacuum-wall/data/certs/{{ domain }}.crt; - ssl_certificate_key /home/wall/vacuum-wall/data/certs/{{ domain }}.key; + ssl_certificate {{ certs_dir }}/{{ domain }}.crt; + ssl_certificate_key {{ certs_dir }}/{{ domain }}.key; {% endif %} # Shared SSL settings diff --git a/system/sudoers.d/vacuum-wall b/system/sudoers.d/vacuum-wall index 9df346e..f02e21e 100644 --- a/system/sudoers.d/vacuum-wall +++ b/system/sudoers.d/vacuum-wall @@ -1,33 +1,33 @@ # Defaults directives -Defaults:vacuum-wall !requiretty -Defaults:vacuum-wall secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +Defaults:{{ USER_NAME }} !requiretty +Defaults:{{ USER_NAME }} secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" # Firewall management -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/firewall-cmd * +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/firewall-cmd * # Nginx management -vacuum-wall ALL=(root) NOPASSWD: /usr/sbin/nginx -s reload -vacuum-wall ALL=(root) NOPASSWD: /usr/sbin/nginx -t -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/cp -- * /etc/nginx/ -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/cp -- * /etc/nginx/conf.d/ -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/cp -- * /etc/nginx/snippets/ -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/rm /etc/nginx/conf.d/vacuum-wall.conf -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/rm /etc/nginx/snippets/vacuum-wall-ssl.conf +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/sbin/nginx -s reload +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/sbin/nginx -t +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/cp -- * /etc/nginx/ +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/cp -- * /etc/nginx/conf.d/ +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/cp -- * /etc/nginx/snippets/ +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/rm /etc/nginx/conf.d/vacuum-wall.conf +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/rm /etc/nginx/snippets/vacuum-wall-ssl.conf # Dnsmasq management -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/systemctl reload dnsmasq -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/systemctl is-active dnsmasq -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/cp -- * /etc/dnsmasq.d/ -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/cat /var/lib/dnsmasq/dnsmasq.leases -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/tee /etc/dnsmasq.d/vacuum-wall.conf +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/systemctl reload dnsmasq +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/systemctl is-active dnsmasq +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/cp -- * /etc/dnsmasq.d/ +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/cat /var/lib/dnsmasq/dnsmasq.leases +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/tee /etc/dnsmasq.d/vacuum-wall.conf # WireGuard management -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/wg-quick * -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/wg * -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/cp -- * /etc/wireguard/ +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/wg-quick * +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/wg * +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/cp -- * /etc/wireguard/ # Misc -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/journalctl --unit=* -n * -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/cat /var/log/nginx/* -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/mkdir -p /etc/dnsmasq.d -vacuum-wall ALL=(root) NOPASSWD: /usr/bin/mkdir -p /etc/wireguard +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/journalctl --unit=* -n * +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/cat /var/log/nginx/* +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/mkdir -p /etc/dnsmasq.d +{{ USER_NAME }} ALL=(root) NOPASSWD: /usr/bin/mkdir -p /etc/wireguard diff --git a/system/systemd/vacuum-wall-acme.service b/system/systemd/vacuum-wall-acme.service index 9054fcd..45ae5e3 100644 --- a/system/systemd/vacuum-wall-acme.service +++ b/system/systemd/vacuum-wall-acme.service @@ -3,6 +3,8 @@ Description=Vacuum Wall ACME Certificate Renewal [Service] Type=oneshot -User=vacuum-wall -WorkingDirectory=/home/wall/vacuum-wall -ExecStart=/usr/local/bin/acme.sh --cron --home /home/vacuum-wall/.acme.sh +User={{ USER_NAME }} +WorkingDirectory={{ PROJECT_DIR }} +Environment=ACME_HOME={{ PROJECT_DIR }}/data/acme +Environment=HOME={{ PROJECT_DIR }} +ExecStart=/usr/local/bin/acme.sh --cron --home {{ ACME_HOME }} diff --git a/system/systemd/vacuum-wall.service b/system/systemd/vacuum-wall.service index ab77735..d323058 100644 --- a/system/systemd/vacuum-wall.service +++ b/system/systemd/vacuum-wall.service @@ -6,20 +6,21 @@ Wants=firewalld.service [Service] Type=simple -User=vacuum-wall -Group=vacuum-wall -WorkingDirectory=/home/wall/vacuum-wall -ExecStart=/home/wall/vacuum-wall/.venv/bin/python webui/server.py +User={{ USER_NAME }} +Group={{ USER_NAME }} +WorkingDirectory={{ PROJECT_DIR }} +ExecStart={{ PROJECT_DIR }}/.venv/bin/python webui/server.py Restart=on-failure RestartSec=5 Environment=PATH=/usr/local/bin:/usr/bin Environment=PYTHONUNBUFFERED=1 +Environment=ACME_HOME={{ PROJECT_DIR }}/data/acme +Environment=HOME={{ PROJECT_DIR }} # Security hardening NoNewPrivileges=yes ProtectSystem=strict -ProtectHome=read-only -ReadWritePaths=/home/wall/vacuum-wall/data /tmp +ReadWritePaths={{ PROJECT_DIR }}/config {{ PROJECT_DIR }}/data /tmp PrivateTmp=yes ProtectKernelTunables=yes ProtectKernelModules=yes @@ -33,7 +34,8 @@ LockPersonality=yes SystemCallFilter=@system-service PrivateDevices=yes -# Network - only loopback (nginx proxies to us) +ProtectHome=read-only +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 IPAddressDeny=all IPAddressAllow=localhost diff --git a/tests/__init__.py b/tests/__init__.py index 55c1976..e69de29 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +0,0 @@ -import sys - -sys.path.insert(0, "/home/wall/vacuum-wall") diff --git a/tests/test_acme.py b/tests/test_acme.py index cd3144a..35c7a97 100644 --- a/tests/test_acme.py +++ b/tests/test_acme.py @@ -1,4 +1,3 @@ -import sys import tempfile from datetime import datetime from pathlib import Path @@ -6,31 +5,28 @@ from unittest.mock import MagicMock, patch import pytest -sys.path.insert(0, "/home/wall/vacuum-wall") - from lib import acme class TestFindAcme: @patch("lib.acme.shutil.which") - @patch("lib.acme.Path.home") - def test_finds_in_home(self, mock_home, mock_which): - mock_home.return_value = Path("/tmp/fakehome") - acme_path = mock_home.return_value / ".acme.sh" / "acme.sh" - acme_path.parent.mkdir(parents=True, exist_ok=True) - acme_path.write_text("#!/bin/sh\n") - acme_path.chmod(0o755) - try: + @patch("lib.acme._ACME_HOME") + def test_finds_in_acme_home(self, mock_acme_home, mock_which): + mock_acme_home = Path("/tmp/fake-acme-home") + mock_acme_home.mkdir(parents=True, exist_ok=True) + acme_bin = mock_acme_home / "acme.sh" + acme_bin.write_text("#!/bin/sh\n") + acme_bin.chmod(0o755) + + with patch.object(acme, "_ACME_HOME", mock_acme_home): result = acme._find_acme() assert "acme.sh" in result - finally: - acme_path.unlink() - @patch("lib.acme.shutil.which") - @patch("lib.acme.Path.home") - def test_raises_when_not_found(self, mock_home, mock_which): - mock_home.return_value = Path("/tmp/nonexistent-acme-dir") - mock_which.return_value = None + acme_bin.unlink() + + @patch("lib.acme._find_acme") + def test_raises_when_not_found(self, mock_find): + mock_find.side_effect = FileNotFoundError() with pytest.raises(FileNotFoundError): acme._find_acme() @@ -112,32 +108,30 @@ class TestDaysUntil: class TestGetEmail: def test_returns_empty_when_no_account_conf(self): - with patch("lib.acme.Path.home") as mock_home: - mock_home.return_value = Path("/tmp/no-acme-email") + with patch.object(acme, "_ACME_HOME", Path("/tmp/no-acme-email")): result = acme.get_email() assert result == "" def test_parses_email_from_account_conf(self): tmpdir = tempfile.mkdtemp() - acme_dir = Path(tmpdir) / ".acme.sh" - acme_dir.mkdir(exist_ok=True) + acme_dir = Path(tmpdir) / "data" / "acme" + acme_dir.mkdir(parents=True, exist_ok=True) conf = acme_dir / "account.conf" conf.write_text("ACME_LEEMAIL='test@example.com'\n") - with patch("lib.acme.Path.home", return_value=Path(tmpdir)): + with patch.object(acme, "_ACME_HOME", acme_dir): result = acme.get_email() assert result == "test@example.com" class TestGetCertPaths: - @patch("lib.acme.Path.home") - def test_returns_paths(self, mock_home): - mock_home.return_value = Path("/home/user") - paths = acme.get_cert_paths("example.com") - assert paths["cert"].endswith("example.com/example.com.cert") - 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") + def test_returns_paths(self, tmp_path): + with patch.object(acme, "_ACME_HOME", tmp_path / "data" / "acme"): + paths = acme.get_cert_paths("example.com") + assert paths["cert"].endswith("example.com/example.com.cert") + 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: @@ -153,20 +147,22 @@ class TestDeployHook: 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() + def test_true_when_conf_exists(self, tmp_path): + acme_dir = tmp_path / "data" / "acme" + acme_dir.mkdir(parents=True) 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 + + with patch.object(acme, "_ACME_HOME", acme_dir): + 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 + def test_false_when_conf_missing(self, tmp_path): + acme_dir = tmp_path / "data" / "acme" + acme_dir.mkdir(parents=True) + + with patch.object(acme, "_ACME_HOME", acme_dir): + result = acme._has_auto_renew("nonexistent.com") + assert result is False diff --git a/tests/test_api.py b/tests/test_api.py index 3d43163..0e83ac5 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,10 +1,7 @@ -import sys from unittest.mock import patch import pytest -sys.path.insert(0, "/home/wall/vacuum-wall") - from webui.api.certs import bp as certs_bp from webui.api.dhcp import bp as dhcp_bp from webui.api.firewall import bp diff --git a/tests/test_dnsmasq.py b/tests/test_dnsmasq.py index 4387151..f7fb3cf 100644 --- a/tests/test_dnsmasq.py +++ b/tests/test_dnsmasq.py @@ -1,25 +1,28 @@ -import sys from unittest.mock import patch import pytest -sys.path.insert(0, "/home/wall/vacuum-wall") - from lib import dnsmasq @pytest.fixture def temp_data_dir(tmp_path): + original_config_dir = dnsmasq.CONFIG_DIR original = dnsmasq.DATA_DIR original_config = dnsmasq.CONFIG_PATH + original_fragments = dnsmasq.FRAGMENTS_DIR + dnsmasq.CONFIG_DIR = tmp_path / "dnsmasq" dnsmasq.DATA_DIR = tmp_path / "dnsmasq" - dnsmasq.CONFIG_PATH = dnsmasq.DATA_DIR / "config.json" + dnsmasq.CONFIG_PATH = dnsmasq.CONFIG_DIR / "config.json" dnsmasq.FRAGMENTS_DIR = dnsmasq.DATA_DIR / "fragments" + dnsmasq.CONFIG_DIR.mkdir(parents=True, exist_ok=True) dnsmasq.DATA_DIR.mkdir(parents=True, exist_ok=True) dnsmasq.FRAGMENTS_DIR.mkdir(parents=True, exist_ok=True) yield tmp_path + dnsmasq.CONFIG_DIR = original_config_dir dnsmasq.DATA_DIR = original dnsmasq.CONFIG_PATH = original_config + dnsmasq.FRAGMENTS_DIR = original_fragments class TestDeepMerge: diff --git a/tests/test_nginx.py b/tests/test_nginx.py index 86b1d34..88804f2 100644 --- a/tests/test_nginx.py +++ b/tests/test_nginx.py @@ -1,11 +1,8 @@ -import sys from pathlib import Path from unittest.mock import MagicMock, patch import pytest -sys.path.insert(0, "/home/wall/vacuum-wall") - from lib import nginx @@ -25,7 +22,10 @@ def temp_data_dir(tmp_path): original_htpasswd = nginx.HTPASSWD_FILE original_ssl_snippet = nginx.SSL_SNIPPET original_include = nginx.INCLUDE_FILE + original_config_dir = nginx.CONFIG_DIR + original_data_dir = nginx.DATA_DIR + nginx.CONFIG_DIR = tmp_path / "nginx" nginx.DATA_DIR = tmp_path / "nginx" nginx.SITES_DIR = tmp_path / "nginx" / "sites-enabled" nginx.CONFIG_FILE = tmp_path / "nginx" / "config.json" @@ -33,6 +33,7 @@ def temp_data_dir(tmp_path): nginx.SSL_SNIPPET = tmp_path / "ssl_snippet.conf" nginx.INCLUDE_FILE = tmp_path / "include.conf" + nginx.CONFIG_DIR.mkdir(parents=True, exist_ok=True) nginx.DATA_DIR.mkdir(parents=True, exist_ok=True) nginx.SITES_DIR.mkdir(parents=True, exist_ok=True) @@ -43,6 +44,8 @@ def temp_data_dir(tmp_path): nginx.HTPASSWD_FILE = original_htpasswd nginx.SSL_SNIPPET = original_ssl_snippet nginx.INCLUDE_FILE = original_include + nginx.CONFIG_DIR = original_config_dir + nginx.DATA_DIR = original_data_dir class TestGetConfig: diff --git a/tests/test_server.py b/tests/test_server.py index 45893e7..5497d44 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -1,10 +1,7 @@ -import sys from unittest.mock import patch import pytest -sys.path.insert(0, "/home/wall/vacuum-wall") - @pytest.fixture def client(): diff --git a/tests/test_wireguard.py b/tests/test_wireguard.py index f15b293..71e9b6c 100644 --- a/tests/test_wireguard.py +++ b/tests/test_wireguard.py @@ -1,12 +1,9 @@ import json -import sys from pathlib import Path from unittest.mock import MagicMock, patch import pytest -sys.path.insert(0, "/home/wall/vacuum-wall") - from lib import wireguard