mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-11-09 05:24:49 +09:00
Plan 75 §G2 + §G4, together because they are the same physical files and G4 is built on G2's helper. §G2 — write_privileged_file(). The write-a-root-owned-file sequence was pasted 15+ times in two competing forms: run_privileged(['tee', path], input=...) and a raw subprocess.run(['sudo', 'tee', ...]). The second hardcodes sudo instead of asking _needs_sudo(), so it fails on a panel already running as root in a container with no sudo binary — plan 74's outage shape. All core-service tee sites now go through one helper that owns the sudo decision, the result shape, and honest failure: a missing tee or a timeout reports the failure instead of being swallowed (§A). §G4 — NginxService.write_vhost()/read_vhost(). environment_domain_service re-implemented write → symlink → nginx -t → reload with raw sudo calls, and nginx_advanced_service wrote the vhost with a plain unprivileged open() — PermissionError against a root-owned sites-available, with no config test and no reload. Both now go through NginxService. The rollback is the part no copy had: a vhost that fails nginx -t used to stay on disk and symlinked, so the next unrelated reload (a cert renewal, another site going live) failed and the blame landed on whatever triggered it. write_vhost restores the previous content, or removes a file that did not exist before, and never reloads a config that failed the test. SITES_AVAILABLE/SITES_ENABLED were independently declared in four files, so an NGINX_CONF_DIR override — the env var NginxService honours, and what tests redirect — silently did not apply to the other three. One declaration now. Mutation-checked: disabling the rollback fails two tests. Also lands unit_is_active() in app/utils/system.py; its adopters are in the following commit (§G6). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>