refactor: daemon collectors, thin webui proxies, pure config reads
- move state collectors from lib/state.py to daemon/collectors/ (7 modules, registration side-effect; daemon/server.py imports the package before the first populate()) - webui/api: new daemon_route() decorator factory in common.py collapses the try/except daemon-proxy boilerplate in all 8 blueprints (rules/params/body/transform keep responses identical) - firewall: interface-coverage invariant — config is the source of truth for zone interfaces (absent key = empty, no hands-off zones); pure validate_coverage() enforced at save (400) and apply (409, force: true overrides), top-level `unmanaged` exemption - lib: get_config() reads are now pure (no dir creation or writes); new lib/bootstrap.py creates runtime dirs and persists the one-shot nginx legacy migration at daemon start, after system_import (lib.nginx.migrate_config_file) - lib/common: compute_pending() apply-bookkeeping helper - daemon: emit_and_refresh() handler helper; refresh_state(bump=) so /status/refresh no longer bumps versions (poll/mutation only) - acme: move --log last so acme.sh never treats a real arg as the log-file argument - docs: AGENTS.md, config.md, state-model.md, api.md updated; HARDEN.md dropped (plan implemented); apply-confirm force wording Tests: 917 passed; ruff check + format clean.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
"""Tests for the daemon-startup filesystem bootstrap (lib.bootstrap)."""
|
||||
|
||||
import pytest
|
||||
|
||||
from lib import bootstrap, dnsmasq, firewall, network, nginx, wireguard
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def sandbox(tmp_path, monkeypatch):
|
||||
"""Point every bootstrap-referenced path into a throwaway tree."""
|
||||
cfg = tmp_path / "config"
|
||||
data = tmp_path / "data"
|
||||
monkeypatch.setattr(dnsmasq, "CONFIG_DIR", cfg / "dnsmasq")
|
||||
monkeypatch.setattr(dnsmasq, "DATA_DIR", data / "dnsmasq")
|
||||
monkeypatch.setattr(dnsmasq, "FRAGMENTS_DIR", data / "dnsmasq" / "fragments")
|
||||
monkeypatch.setattr(firewall, "CONFIG_DIR", cfg / "firewall")
|
||||
monkeypatch.setattr(firewall, "DATA_DIR", data / "firewall")
|
||||
monkeypatch.setattr(network, "CONFIG_DIR", cfg / "network")
|
||||
monkeypatch.setattr(network, "DATA_DIR", data / "networkd")
|
||||
monkeypatch.setattr(nginx, "CONFIG_DIR", cfg / "nginx")
|
||||
monkeypatch.setattr(nginx, "DATA_DIR", data / "nginx")
|
||||
monkeypatch.setattr(nginx, "SITES_DIR", data / "nginx" / "sites-enabled")
|
||||
monkeypatch.setattr(nginx, "CONFIG_FILE", cfg / "nginx" / "config.json")
|
||||
monkeypatch.setattr(wireguard, "CONFIG_PATH", cfg / "wireguard" / "config.json")
|
||||
return tmp_path
|
||||
|
||||
|
||||
def test_creates_runtime_dirs(sandbox):
|
||||
bootstrap.bootstrap()
|
||||
assert dnsmasq.FRAGMENTS_DIR.is_dir()
|
||||
assert firewall.DATA_DIR.is_dir()
|
||||
assert network.DATA_DIR.is_dir()
|
||||
assert nginx.SITES_DIR.is_dir()
|
||||
assert wireguard.CONFIG_PATH.parent.is_dir()
|
||||
|
||||
|
||||
def test_does_not_create_config_files(sandbox):
|
||||
# Config files are left for system-import (first start) or the first
|
||||
# save_config — bootstrap must not pre-empt either.
|
||||
bootstrap.bootstrap()
|
||||
assert not nginx.CONFIG_FILE.exists()
|
||||
assert not (dnsmasq.CONFIG_DIR / "config.json").exists()
|
||||
assert not (network.CONFIG_DIR / "config.json").exists()
|
||||
assert not (firewall.CONFIG_DIR / "config.json").exists()
|
||||
assert not wireguard.CONFIG_PATH.exists()
|
||||
|
||||
|
||||
def test_persists_nginx_migration(sandbox):
|
||||
nginx.save_config({"domains": {"app.example.com": {"backend": "myapp"}}})
|
||||
bootstrap.bootstrap()
|
||||
on_disk = nginx.get_config()
|
||||
assert on_disk["backends"]["webui"]["_migrated"] is True
|
||||
raw = nginx.CONFIG_FILE.read_text()
|
||||
assert '"_migrated": true' in raw or '"_migrated":True' in raw
|
||||
|
||||
|
||||
def test_idempotent(sandbox):
|
||||
nginx.save_config({"domains": {}})
|
||||
bootstrap.bootstrap()
|
||||
mtime = nginx.CONFIG_FILE.stat().st_mtime_ns
|
||||
bootstrap.bootstrap()
|
||||
assert nginx.CONFIG_FILE.stat().st_mtime_ns == mtime
|
||||
Reference in New Issue
Block a user