fix(smoke): repair the three production smoke checks (2 false failures + 1 false pass) #20
No reviewers
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!20
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix-prod-smoke-failures"
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?
The smoke checks ran against production for the first time today. Two failed and one passed. All three were wrong — none of it was a defect in the deployed app.
smoke_ws — could never pass
runWsSmoke's open handler calledws.close()on the line beforeresolve(). Bun dispatches thecloseevent synchronously from insideclose(), and the close listener rejects unconditionally, soreject()settled the promise first on every single run.code=1000, reason=''is exactly what a client-initiatedclose()with no args produces — the check was reporting its own socket teardown.Production WebSocket routing was never broken. From both a laptop and celilo-mgr:
Instrumented ordering proof (bun 1.3.3, live prod):
Fix: resolve before closing. The later
reject()then lands on a settled promise and is a no-op.Worth noting this was never covered anywhere —
e2e/tests/deploy.test.tsimports onlyrunSpaSmokeCheck, sorunWsSmokeandrunApiSmokehad never executed before today.smoke_spa — could never pass either
Both it and
smoke_apiauthenticated with thesmoketest_bot_tokenhook output. That is an Authentik API token (intent: 'api'— an opaque random key), not an OIDC access token. The server verifies bearers withjwtVerify(token, jwks)and the SPA decodes them withjwtDecode, so both rejected it:ERR_JWS_INVALID→ unauthenticated context →UNAUTHORIZEDdecodeJWTthrows →clearTokens()→ renders "Sign In"So
Header.tsx's{user.name}never rendered and thesmoketest_botmarker could not appear. Confirmed by re-runningcelilo module health lunacycleand correlating the app container's journal —Token verification failed: Invalid Compact JWSat the exact timestamps of both the SPA and API checks.health_check now performs a real OIDC authorization-code + PKCE login with
smoketest_bot_password(already a declared secret), the same flow the SPA's login button drives. This needs no celilo-side changes: the client id and authentik URL are already public in the SPA's ownconfig.js. It adds asmoke_logincheck and gives the login path production coverage for the first time.smoke_api — was unfalsifiable
responseMetainapps/lunacycle-server/src/index.tshard-codesstatus: 200on every tRPC response, errors included:resp.status !== 200therefore could not fail for any auth or application error. It reported ✓ while the server loggedERR_JWS_INVALIDfor that same request. Both the API and SPA checks now assert the body carries no tRPC error envelope.Also
celilo/scripts/health-check.tsnever passedartifactDir, so the screenshot + DOM + observed-request post-mortem thatspa-smoke.tscarefully writes on failure was discarded in production (e2e passes it). Now written to/tmp/lunacycle-smokeand named in the failure message.Verification
Against live production:
preferred_username,groups: ["lunacycle-admins"], correctisssmoke_api,smoke_ws,smoke_spaall pass with that tokenrunWsSmokereproduced the exact production message; the fixed one passesrunApiSmokewith a bad token now correctly fails withUNAUTHORIZEDinstead of reporting ✓Plus 6 new unit tests in
tests/unit/smoke-checks.test.ts(WS close-ordering regression, WS genuine-failure still detected, PKCE happy path, PKCE stage-stall, error-envelope detection). Full suite green: 58 vitest + 57 bun tests, lint clean, no new type errors.The end-to-end verification used
lunacycle_adminrather thansmoketest_bot, since the bot's password is a sealed module secret. The flow is credential-identical, and the bot can complete it —create_oidc_client'sgroupsargument only creates groups, and the application ispolicy_engine_mode: 'any'with no policy bindings. Worth confirming on the first real health run after deploy.Out of scope, flagged for follow-up
responseMetareturns 200 for every error. Breaks HTTP semantics for every client, not just these checks. The smoke fix works around it rather than fixing it.lunacycle_admin's password is hard-coded as'lunacycle-rules'incelilo/scripts/setup-web.tsand provisioned into production. A default admin credential in a git repo.smoketest_bot_tokenis now unused in-tree. Left in place (it's a legitimate Authentik-API service credential) with a comment so nobody wires it back into app auth.