a3256156908cecf11b6485efcbb1e1de84eb8dfc
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e28c3dcce4 |
fix(lsphp): correct the SIGPIPE explanation, drop the temp-dir boot precondition, close two scanner blind spots
Three non-blocking findings from the review of
|
||
|
|
8790b027a9 |
fix(lsphp): stop SIGPIPE+pipefail reporting the parity extension as missing
`entrypoint-lsphp.sh` decided whether cac_path_parity was loaded with
printf '%s\n' "$LSPHP_INFO" | grep -q '^cac_path_parity support => enabled$'
under `set -euo pipefail`. `grep -q` exits on its first match; printf is still
writing the remaining ~40 KB of `lsphp -i`, takes SIGPIPE, exits 141, and
pipefail prefers 141 over grep's 0. The branch therefore evaluated FALSE
*because the extension was present* — present early enough to stop the reader —
and every affected container fell back to the auto_prepend normaliser that a
customer's own .user.ini silently displaces, i.e. the exact failure the
extension exists to remove. Measured on whp02 against the published
cac-lsphp:php83: 5/5 runs status=141 with pipefail, 0 without.
The race is decided by pipe capacity, which is why it reproduced on whp02 and
not on other daemons: while the payload fits the pipe the writer never blocks
and always finishes first. Forced over the limit it is deterministic — 3x the
same `lsphp -i` (122100 bytes) gives 141 every time in the built image.
Fixed by reading with here-strings, which are not pipelines at all, so there is
no second exit status for pipefail to adopt. Same grep/awk patterns; plumbing
only. Same class fixed everywhere it existed under pipefail:
* entrypoint-lsphp.sh parity probe, and the SCAN_DIR awk probe
* entrypoint-litespeed.sh SCAN_DIR probe (a bare assignment: 141 there does
not degrade, `set -e` kills PID 1), and ols_running
* entrypoint-shared-ols.sh ols_running
* render-shared-ols-config.sh site.meta parsing (`sed | head -1`): measured
141 at 6000 duplicate keys, which under `set -e`
aborts the whole render
* fpm-parity-check.sh the `php-fpm -m` pre-flight, whose whole job is to
stop a harness fault being blamed on the extension
Also: the fallback used to announce "cac_path_parity extension not loadable in
this image" for every reason the branch was reached, including its own plumbing
breaking — a false diagnosis that sends operators to rebuild a good image whose
build gate passed. Verdicts now carry the evidence they rest on, and a probe
that produced nothing is reported as a probe failure that establishes nothing
about the image. Fail-open posture is unchanged: no probe failure is fatal.
Adds scripts/tests/lsphp-info-probe.test.sh, which runs the shipped probes
(extracted verbatim, so they cannot drift from what runs in production) under
`set -euo pipefail` against a realistic ~40 KB phpinfo body, and statically
outlaws the shape repo-wide. Against trunk it fails, naming all 9 offending
lines. Wired into CI as a new Shell-Checks job, because no existing gate ever
executed the entrypoint's branch logic — the .phpt suite and the Dockerfile's
own `lsphp -i | grep -q` probe (which has no pipefail) were both green for the
release whose entrypoint declared that same extension missing.
Verified: PHP 8.3 --no-cache build green, 10/10 .phpt, 9/9 FPM harness; the
built image logs `path parity = extension` and reports `Rewriting => active`
with .from/.to populated; ext-removed and probe-broken variants each produce
their own honest message and still start.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
08f35032c5 |
fix(shared-ols): re-review hardening — bounded flock + stale-tmp sweep
Follow-up to the review fixes, from a second review pass: - flock now uses -w 30 (bounded wait) so a hung render can't block the panel's docker-exec (and the site-save request) indefinitely; the dead-code timeout error path is now reachable. - sweep stale .httpd_config.conf.tmp.* left by a prior SIGKILL (trap EXIT doesn't run on SIGKILL); safe under flock since each render uses a unique $$ suffix. Verified: render still produces a valid config + serves; stale tmp is swept. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
6bb494c72f |
fix(shared-ols): review fixes — watcher starvation, atomic render, O(N) chown, safe meta parse
Addresses the local code-review on the OLS-tier images: - [HIGH] ols-htaccess-watcher.sh: the debounce drain read ALL inotify events unfiltered, so on a busy multi-tenant server it never timed out and the restart was STARVED (rewrite changes silently never applied). Now coalesces with a hard DEBOUNCE-bounded window. Verified under continuous noise. - [HIGH] render-shared-ols-config.sh: built httpd_config.conf in-place across several appends, so a concurrent OLS restart (watcher) or parallel render could read a half-written config and 503 the whole tier. Now flock-serialized, built in a temp file and atomically moved into place; refuses to publish empty. - [MED] render + entrypoint: replaced recursive chown of the whole conf tree (O(N-sites) on every single-site change / boot) with a targeted chown of just the file written. - [MED] render: parse site.meta with sed instead of sourcing it (do not execute panel-written data as shell). - [cleanup] removed the unused configs/shared-ols/vhconf.tpl (the panel copy is the single source; the image never read it). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
19db8f170a |
feat(shared-ols): shared OpenLiteSpeed tier image (webserver-only, fronts cac-lsphp sidecars)
One OLS container fronting many tenants' detached cac-lsphp sidecars — the
OLS analogue of shared-httpd. Runs NO PHP locally; every site's PHP goes to
its own sidecar over LSAPI (extProcessor type lsapi, address <sidecar>:9000).
Key design fact (established by PoC): OLS has NO top-level 'include' directive,
so render-shared-ols-config.sh assembles httpd_config.conf from the panel's
per-site files (vhconf.conf + site.meta) at boot and on every change — the
'include' OLS lacks. Per-site detail uses the OLS-native configFile +
vhost-scoped extprocessor model. LSCache is module-level (a configFile-loaded
vhost rejects a bare cache{} block); the WP LiteSpeed plugin controls
cacheability via X-LiteSpeed-Cache-Control headers.
- Dockerfile.shared-ols: litespeed base + inotify-tools/envsubst/openssl,
admin bound to loopback, :80/:443 self-signed, healthz HEALTHCHECK.
- entrypoint-shared-ols.sh: cert + health vhost + render + watcher, then
daemon-mode OLS supervision (reused from cac-litespeed so self-restarts
don't kill PID 1).
- render-shared-ols-config.sh: strip stock (incl local lsphp) + append base +
per-site stanzas + listeners with all maps + catch-all health vhost.
- ols-htaccess-watcher.sh: inotify debounce+floor -> lswsctrl restart (spec 5.3).
- configs/shared-ols/{httpd_config_base,vhconf}.tpl.
- CI: Build-Shared-OLS job.
Verified locally end-to-end: zero-site boot healthy on :443; add site via the
panel contract -> Host-routed to the right sidecar (SAPI=litespeed); real
client IP + HTTPS behind X-Forwarded headers; LSCache miss->hit; .htaccess
change triggers graceful restart; unknown Host hits health catch-all (200).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|