| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
…t check The paired-release cutover (deploy/INSTALL-paired-release.md) rewrites two live lines from /etc/kayak/host.yaml via `levels render-serving`: - the served-docroot nginx `root` in levels-common.conf - the PHP-FPM pool `open_basedir` in kayak.conf These now legitimately diverge from the generic repo templates, so the weekly config-drift check reported 2 false DIFFERS (and would OnFailure-ping) on the cut-over host — which is why kayak-config-drift.timer was held stopped post-flip. Mask ONLY those two lines (preserving the ACME `root /var/www/certbot;`, which is NOT rendered) before comparing, so the rest of each file is still byte-compared and a real regression is still caught. The mask is a no-op on a pre-cutover host (the lines already match the template), so it is safe for every host. Verified: shellcheck clean; post-cutover levels-common.conf + kayak.conf normalize to match their templates, while a tampered ACME root still flags as drift. Authored on the live host during the cutover; routed through the normal branch/PR flow rather than edited in-place in the live ~/kayak tree (whose shell consumers run check-config-drift.sh directly). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adversarial review — PR #198 (config-drift: exempt the 4C host-rendered nginx/FPM lines)Disclosure: I designed this change during the cutover, so I've reviewed it extra-critically rather than rubber-stamp it. Reviewed on the live host (where kayak-config-drift.timer is currently held inactive, the exact reason this exists). CI still running; I verified shellcheck --severity=warning clean myself (the CI invocation) and re-ran the normalizer against the live files. Correct and well-scoped — approve. One real trade-off to acknowledge, plus minors. What's right (verified on the live files)
1. (Medium — conscious trade-off) The mask exempts the lines entirely, so tampering on two security-relevant lines is no longer caught by config-driftMasking the whole line means config-drift no longer verifies the content of the served-docroot root or the FPM open_basedir — only that everything else matches. I confirmed the gap on the live pool: adding /tmp: to open_basedir (a sandbox-weakening edit) normalizes to a match → not flagged. open_basedir is a security control and root decides what's served, so these are exactly the lines you'd most want continuously watched — and they're now blind spots between deploys. The deployer's serving-path gate checks them, but only at deploy time, not weekly like drift. The stronger alternative is to verify the live lines against render-serving's current output (drift = "live root/open_basedir ≠ what host.yaml renders") rather than blanking them — that keeps continuous correctness and catches tampering. It's heavier (couples the drift check to the renderer + host.yaml + a levels binary), so the mask is a defensible pragmatic v1 — but I'd record this as a known limitation (and a candidate follow-up), because "config-drift now passes" reads as "these files are fully monitored" when two security lines no longer are. 2. (Low) RENDER_NORMALIZED duplicates the FPM pool path/etc/php/8.4/fpm/pool.d/kayak.conf now appears in both the MANIFEST and RENDER_NORMALIZED. A PHP-version bump (→ php8.5/...) must update both; updating only the manifest silently re-introduces the false drift. Minor — worth a comment linking the two, or deriving the path once. 3. (Low, forward-looking) Follow-up #2 will re-introduce drift on levels-common.confThe cutover's open follow-up #2 re-points the favicon.ico/security.txt aliases (/home/pat/public_html/static/… → /var/cache/kayak/docroot/static/…). Those alias lines aren't masked here (correctly — they're not rendered yet), so once #2 lands, the installed file will diverge from the template on the alias lines and config-drift will flag them. normalize_rendered (or the template) will need extending then — flagging so it's expected, not a surprise. 4. (Low, nice-to-have) No test for non-trivial logicThe normalizer has subtle behavior (the negated certbot address, surgical single-line mask). A small tests/test_scripts/ test — run check-config-drift.sh against a clean + a tampered rendered fixture and assert (a) rendered-line drift is exempt, (b) a tampered certbot root still flags — would lock the certbot-exclusion against a future sed edit. Not a blocker (the repo doesn't unit-test every shell script), but this one earns it. VerdictApprove. It does what it's for, the mask is genuinely surgical, and it unblocks re-arming the timer. The only thing I'd want consciously accepted (not silently) is #1 — exempting open_basedir/root from drift detection in exchange for no false alarms; the verify-against-render-serving upgrade is the natural way to close that gap later. — Claude Opus-4.8(1M)/xhigh |
Sorry, something went wrong.
…add tests - #1 (the conscious trade-off): document the KNOWN LIMITATION inline — masking the whole line means config-drift no longer verifies the *content* of `root` / `open_basedir` between deploys (a manual tamper of just those lines wouldn't be flagged). Note that the deployer's serving-path gate still verifies them at deploy time, and record the verify-against-`render-serving` upgrade as the follow-up that closes the continuous-monitoring gap. - #2: comment the FPM-pool-path duplication (RENDER_NORMALIZED + MANIFEST) so a PHP-version bump updates both, not just one. - #4: add tests/test_scripts/test_config_drift.py — sources the script in a new lib mode (KAYAK_DRIFT_LIB=1, early-return before the /etc manifest walk) and drives normalize_rendered directly, locking the surgical mask: the docroot `root`/`open_basedir` are exempt, but the ACME `root /var/www/certbot;` stays byte-checked (a tampered ACME root still differs). Guards the certbot exclusion against a future sed edit. #3 (the favicon/security.txt aliases re-introducing drift) is mooted by PR #199, which makes those aliases docroot-relative (try_files) rather than hardcoding the cache path — so they stay generic and need no mask. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks — all four addressed in 3b90b6a. #1 (the conscious trade-off) — documented inline. Took your recommended path (record as known limitation rather than build the heavier verifier now): the comment block now spells out that masking the whole line stops config-drift from verifying the content of root/open_basedir between deploys, notes the deployer's serving-path gate still checks them at deploy time, and records the verify-against-render-serving upgrade as the follow-up that closes the continuous-monitoring gap. Consciously accepted, not silent. #2 — commented. The FPM-pool-path duplication (RENDER_NORMALIZED ↔ MANIFEST) now has a note that a PHP-version bump must update both. #4 — test added. tests/test_scripts/test_config_drift.py sources the script in a new lib mode (KAYAK_DRIFT_LIB=1, early-return before the /etc walk) and drives normalize_rendered directly: asserts the docroot root/open_basedir are exempt and the ACME root /var/www/certbot; stays byte-checked (a tampered ACME root still differs). That locks the certbot exclusion against a future sed edit — your exact concern. 5 tests, green; shellcheck still clean. #3 — mooted by #199. Rather than hardcode /var/cache/kayak/docroot/static/… (which would re-introduce drift as you predicted), #199 makes the favicon/security.txt aliases docroot-relative (try_files /static/… =404;, matching the apple-touch-icon block). They stay generic and identical between template and live, so normalize_rendered needs no extension for them. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
config-drift truing-up — exempt the 4C host-rendered nginx/FPM lines
Follow-up #1 from the live paired-release cutover (2026-06-14). kayak-config-drift.timer is currently held stopped on the live host because the cutover rewrote two lines to host-rendered values that now legitimately diverge from the generic repo templates the whole-file drift check diffs. Re-arming as-is = 2 false DIFFERS + a weekly OnFailure ping. This makes those two lines drift-exempt so the timer can be re-armed.
The two rendered lines
levels render-serving writes them from /etc/kayak/host.yaml:
Approach
A normalize_rendered() pass masks only those two lines (→ @@RENDERED@@) on both the repo template and the installed copy before comparing. Everything else in each file is still byte-compared, so a real regression elsewhere is still caught. Two deliberate properties:
Verification
Provenance / why a PR
Authored on the live host during the cutover, then routed through the normal branch/PR flow instead of being edited in-place in the live ~/kayak tree — post-cutover the engine is pinned to /opt/kayak/current, but the shell consumers (including check-config-drift.sh itself) still ExecStart from ~/kayak/{scripts,systemd}/, so an in-place edit there would change live behavior unreviewed.
Deploy step (after merge)
git -C /home/pat/kayak pull (brings the updated script onto the host), then re-arm sudo systemctl start kayak-config-drift.timer. A manual sudo systemctl start kayak-config-drift.service should then exit 0.
🤖 Generated with Claude Code