chromium.launch() is unguarded — a browser-cache miss crashes health_check instead of recording a check #56
Labels
No labels
area/auth
area/backend
area/ci
area/deploy
area/e2e
area/frontend
area/shared
blocked
good-first-issue
needs-info
priority/high
priority/low
priority/medium
type/bug
type/chore
type/docs
type/feature
type/tech-debt
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
celilo/lunacycle#56
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found while re-reading
runSpaSmokefor the #54 playwright discussion. Not the defect that discussion started from, and worse than it.What
celilo/scripts/health-check.ts,runSpaSmoke:The module load is guarded. The smoke run is guarded. The
launch()between them is bare. Anything it throws propagates straight out ofrunSpaSmoke, out oflunacycleHealthCheck, and out of the hook.Why that matters
The hook's whole contract is to collect check items and throw one aggregated
Health checks failed: <names>at the end. A bare throw fromlaunch()bypasses that entirely:smoke_spaitem is recorded, so the failure is not attributable to a named check.smoke_api,smoke_ws) never run.browserType.launch: Executable doesn't exist at /root/.cache/ms-playwright/chromium-1223/...— instead of a health check name.And it takes out two things at once, because the same hook backs both: the 15m health monitor, and the deploy verification that gates
VERIFIED.This is live today for any launch failure — a missing browser, a sandbox/seccomp problem, OOM on a 512MB-class host, a stale cache after a disk sweep. It is not hypothetical or bump-specific.
Where it intersects #54
#54 aligns
playwright-core~1.55.1→~1.60.0. Playwright resolves its browser from a revision-keyed cache directory, and there is noexecutablePathanywhere in the hook. Read from each package's ownbrowsers.json:chromium-1193chromium-1223So the bump changes which directory
launch()looks in. Unless revision 1223 is already present on celilo-mgr, the first health check after that deploy throws — and because of this bug it throws uncaught rather than recording a failedsmoke_spa.Note also that nothing in the module installs a browser:
celilo/scripts/package.jsonhas nopostinstall, and the root'splaywright install chromium-headless-shellruns in the repo, not on celilo-mgr. Whatever chromium is on that box got there by some other route, so "it works today" is not evidence 1223 will be there tomorrow.Worth checking before #54 lands: whether
chromium-1223exists in celilo-mgr's playwright cache. If it does not, #54 needs the browser provisioned first, in whatever form the platform-vs-module question settles on.Fix
Independent of #54, and worth doing either way — bring
launch()inside a guard so a launch failure becomes an attributable check rather than a crash:failrather thanwarn: unlike "playwright-core is not installed at all", a browser that is present but unlaunchable is a real regression on a host that is supposed to be able to run this.Worth a test alongside it — the
loadChromiumseam already makes this reachable: a stub whoselaunch()rejects should produce a failedsmoke_spacheck and letsmoke_api/smoke_wsstill run. #53 (PR #55) adds the harness that makes that a two-line test.Widening this:
smoke-handler.tshas the same defect in a worse form, and I only checked it because celilo/playwright-platform is writing a spec requirement against this issue.smoke-handler.tsis worse thanhealth-check.tsThree ways this is worse than the health-check version:
health-check.tsat least wrapsloadChromium()and degrades to awarn. Here, a missingplaywright-corethrows just like a missing browser does.addCheckat all. This is a bus handler, not a hook — there is no check list to record into, so a throw is simply a failed event-bus job. Nothing is attributable tosmoke_spa, because no such item exists on this path.max_attempts: 1in the manifest, so there is no retry to paper over a transient launch failure.And the same cascade: the API and WS smoke calls sit after the browser block, so a launch failure means they never run. Identical shape to the health-check case — one failure taking out the other two checks — but with even less to diagnose from.
There is also no
loadChromiumseam here, so unlikehealth-check.ts(which #53/PR #55 makes testable) this path cannot be unit-tested at all as written.Scope correction
The issue title and body describe
health-check.tsonly. The fix has to cover both call sites. On the subscriber path "record a named check" is not available, so the equivalent is: catch, log with the same detail, and let the API and WS smoke still run rather than dying at the browser.Not an instance of #57
Worth stating so nobody over-applies it:
smoke-handler.tscallsrunApiSmoke({ fetchImpl: fetch })with the global fetch, and that is correct here. A bus subscriber gets no injectedFetcher— the file's own docblock explains that the hook runner's privilege model does not extend to subscriber subprocesses, which is why it shells out tocelilo module config getfor its config. #57 is abouthealth-check.ts, where an injected fetcher does exist and is bypassed. This path has nothing to bypass.Minor, fold into the same PR
smoke-handler.ts's docblock illustrates the wiring withtimeout_ms: 120000.manifest.ymlsays90000. Stale comment (Rule 1.5).