Skip to content

[FIX] Make /connect capture page work + unblock canopy-admin CI/deploy (Node 22, audit) - #3

Merged
ScottieR merged 2 commits into
mainfrom
claude/fix-connect-widget-mount-guard
Sep 10, 2026
Merged

ScottieR merged 2 commits into
mainfrom
claude/fix-connect-widget-mount-guard

Conversation

@ScottieR

@ScottieR ScottieR commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Makes the web-hosted /connect/{token} capture flow actually functional and gets canopy-admin CI + the Cloud Run deploy green. Consolidates what were three separate fixes (this PR supersedes #4, now closed).

1. The /connect page was non-functional (the operational bug)

The page is server-rendered by renderConnectPage, but the widget's main() bailed unless it found a connect-root element that no page ever emits (grep-confirmed: referenced only on that line). So root was always null, the submit handler never attached, and the Connect button silently did nothing — the pasted key was never encrypted or sent.

  • src/connect-widget/main.ts — drop the dead connect-root guard; key off status-message (which the page renders). Form controls are already re-checked before the handler wires up.
  • connections-routes.test.js — regression test that parses the widget's own getElementById(...) calls and asserts renderConnectPage emits each id, so the page↔widget contract can't drift silently again. Verified it fails on the pre-fix widget and passes after.

2. CI/deploy ran on Node 20, which can't run the test suite

connect-widget.test.js imports src/connect-widget/main.ts directly, and Node 20 cannot load .ts (ERR_UNKNOWN_FILE_EXTENSION; native type stripping needs Node ≥22.6). Both security.yml and deploy.yml's verify steps pinned node-version: '20', so npm test failed on main and on every PR — a pre-existing red. The repo's deps already require Node 22 (react-router@8.3.0>=22.22.0) and canopy standardizes on 22.

  • Bump both workflows to node-version: '22', .nvmrc → 22, engines>=22.12.0.
  • The Dockerfile stays node:20-alpine intentionally: it doesn't run the .ts test, react-router is client-bundled (never executed in node at runtime), and there's no engine-strict to hard-fail install. Flagging for a future consistency bump, not needed for this deploy.

3. npm audit --audit-level=high was failing the gate

4 high advisories (multer, nanoid, brace-expansion, browserslist). npm audit fix (no --force) clears all 9 within existing semver ranges — package-lock.json only, package.json deps untouched. multer (runtime, multipart uploads) → 2.3.0.

Verification (Node 22)

  • npm audit --audit-level=high exits 0 (0 vulnerabilities)
  • npm test54/54 pass (previously 1 fail: the .ts load error)
  • npm run build — clean · npm run lint — clean

Path to production

Merge to main, then promote main → production to trigger the Cloud Run deploy. The companion canopy change (browserslist bump for the deploy's "Verify Canopy" step + v0.4.0 prep) is ScottieR/canopy#119.

🤖 Generated with Claude Code

https://claude.ai/code/session_014AyPaJTiYLvCp5N6GiKZDS

…ount guard

The web-hosted connection capture page (renderConnectPage in
connections-routes.js) is server-rendered — every element the widget touches
already exists in the DOM. But the widget's main() bailed early unless it also
found an element with id="connect-root":

    const root = document.getElementById('connect-root');
    if (!root || !statusEl) return;

No page ever emits connect-root (grep confirms it was referenced only here), so
root was always null, main() returned before adding the form submit handler, and
the Connect button silently did nothing — the whole point of the flow (capture a
key from any browser) never worked. root was otherwise unused; status-message is
the real "are we on the connect page" sentinel and the form controls are
re-checked right before the handler is wired up.

Add a regression test that parses the widget's own getElementById lookups and
asserts renderConnectPage emits each id, so the page and widget can't drift apart
silently again (this exact bug is otherwise invisible until someone loads the
real page). Verified: the test fails against the pre-fix widget with a precise
diagnostic and passes after. Full suite 54/54, build and lint clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014AyPaJTiYLvCp5N6GiKZDS
… CI + deploy)

Two pre-existing failures were blocking every canopy-admin PR and the Cloud Run
deploy, independent of the /connect widget fix on this branch:

1. Node 20 can't run the test suite. CI (security.yml) and the deploy's verify
   steps (deploy.yml) both pinned `node-version: '20'`, but `connect-widget.test.js`
   imports `src/connect-widget/main.ts` directly, and Node 20 cannot load `.ts`
   (ERR_UNKNOWN_FILE_EXTENSION — native type stripping needs Node >=22.6). The
   repo's own dependencies already require Node 22 (react-router@8.3.0 →
   >=22.22.0), and canopy standardizes on Node 22, so pinning 20 was the bug.
   Bump both workflows to '22', `.nvmrc` to 22, and engines to >=22.12.0 to match.

2. `npm audit --audit-level=high` failed on 4 high advisories (multer, nanoid,
   brace-expansion, browserslist). `npm audit fix` (no --force) clears all 9
   within existing semver ranges — package-lock.json only, package.json deps
   untouched. multer (runtime, multipart uploads) moves to 2.3.0.

The Dockerfile build/runtime stay on node:20-alpine intentionally: they don't run
the .ts test, and react-router is client-bundled (never executed in node at
runtime), with no engine-strict to hard-fail install.

Verified on Node 22: audit --audit-level=high exits 0, 54/54 tests, build, lint
all pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014AyPaJTiYLvCp5N6GiKZDS
@ScottieR ScottieR changed the title [FIX] Make the web-hosted /connect capture page functional (dead connect-root guard) [FIX] Make /connect capture page work + unblock canopy-admin CI/deploy (Node 22, audit) Sep 9, 2026
@ScottieR
ScottieR merged commit 8dde342 into main Sep 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants