Conversation
…ter-6.30.4-open-redirect fix(deps): upgrade react-router-dom to 6.30.4 (CVE-2026-40181)
Remove stale JSDoc, use path-based main-module detection, parse help markdown synchronously, and scope lazy ProfileEditor state to the component.
* Restore 100% package coverage after Vitest 4 upgrade. Vitest 4's v8 coverage counts branch paths more strictly; add targeted tests for async cancellation, dynamic import fallbacks, and edge-case branches across billing, admin, connections, observability, and shared packages. * Address Copilot review feedback on coverage tests. Use a call-through setTimeout spy to exercise the debounce cancellation guard without stubbing clearTimeout, and assert no unmounted-component warnings when Sentry resolves after ObservabilityProvider unmounts.
|
CI Coverage & Test Summary
Suites: 64 passed, 0 failed (64 total) · Tests: 666 passed, 0 failed (666 total) ✅ All reported test suites passed. Coverage artifacts: Updated at: June 3, 2026 at 5:19 PM PDT |
There was a problem hiding this comment.
Pull request overview
This release promotion PR brings the last three develop commits onto main, primarily to ship a React Router security patch (CVE-2026-40181), clean up setup/help flows, and restore/lock in full package coverage after the Vitest 4 upgrade.
Changes:
- Upgrade
react-router-domto^6.30.4across web/admin/articles (and lockfile) to address CVE-2026-40181. - Improve robustness/clarity in setup + help tooling (setup main-module detection; synchronous
marked.lexer/marked.parserhelp parsing). - Add targeted tests (and a small billing hook typing fix) to cover previously uncovered/edge branches, including unmount/cancellation behavior and dynamic import fallbacks.
Reviewed changes
Copilot reviewed 20 out of 21 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/setup-full.mjs | Improves imports formatting, branding read readability, removes stale JSDoc, and switches main-module detection to path-based comparison. |
| packages/waitlist/src/hooks/useSignupMode.test.tsx | Adds an unmount/cancellation coverage test for waitlist settings fetching. |
| packages/shared-tests/tests/components/navigation/UserMenu.test.tsx | Adds coverage for closing the user menu when navigating via “Connections”. |
| packages/observability/src/tests/sentryDynamicImport.coverage.test.ts | New coverage test ensuring UI survives rejected Sentry dynamic imports (web + native). |
| packages/observability/src/tests/ObservabilityProvider.web.test.tsx | Adds unmount safety coverage for late-resolving Sentry imports. |
| packages/marketing-email/src/tests/kitClient.test.ts | Adds coverage for response body read failures on HTTP error paths. |
| packages/help/scripts/build-help.ts | Ensures help markdown parsing is synchronous via marked.lexer + marked.parser. |
| packages/connections/src/hooks/useConnections.test.tsx | Adds coverage for refresh() and debounced realtime reload cancellation on unmount. |
| packages/billing/src/utils/parseBillingFunctionError.test.ts | Adds coverage for whitespace-only error string handling. |
| packages/billing/src/hooks/useUsage.ts | Refines fetchUsageRef typing and call-site safety via optional chaining. |
| packages/billing/src/hooks/useInvoices.test.tsx | Adds coverage that loadMore failures preserve existing items and stop pagination. |
| packages/billing/src/hooks/useBillingState.test.tsx | Adds coverage for trialing subscriptions with trial_end: null. |
| packages/billing/src/components/SubscriptionStatusBadge.native.test.tsx | Adds coverage for unknown subscription statuses preserving raw label text. |
| packages/billing/src/BillingProvider.test.tsx | Adds several unmount/cancellation coverage tests and fixes a mock leak (mockImplementationOnce). |
| packages/articles/package.json | Bumps react-router-dom peer + dev dependency to ^6.30.4. |
| packages/admin/src/components/AdminTable.web.test.tsx | Adds coverage for ignoring non-activation keys on clickable rows. |
| packages/admin/src/components/AdminDetailDrawer.web.test.tsx | Adds coverage around Tab trap behavior in the admin detail drawer. |
| packages/admin/package.json | Bumps react-router-dom to ^6.30.4. |
| package-lock.json | Updates resolved react-router-dom / react-router / @remix-run/router versions to match the bump. |
| apps/web/package.json | Bumps react-router-dom to ^6.30.4. |
| apps/mobile/src/screens/ProfileScreen.tsx | Scopes lazy-loaded ProfileEditor to component state instead of module-level mutable state and drops unused navigation prop passing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
* fix(test): strengthen unmount and Tab-trap coverage assertions Address Copilot review on #401: use userEvent.tab() to verify focus advances when Tab is not trapped, and assert no React unmounted warnings in post-unmount async tests for billing, waitlist, and admin packages. * fix(test): harden console.error unmount warning assertions Wrap console.error spies in try/finally so failed assertions cannot leak mocks into later tests, and scan all console.error arguments when detecting React unmounted-component warnings.
diego-artificerinnovations
left a comment
There was a problem hiding this comment.
Reviewed all four commits. No blockers. Approving for promotion.
react-router-dom 6.30.3 → 6.30.4 (CVE-2026-40181) ✓ — Correct bump across all three consumers (apps/web, packages/admin, packages/articles). package-lock.json changes are consistent.
ProfileScreen.tsx — Module-level state → component state ✓ — Moving ProfileEditor from a module-level let to useState is the right fix. Module-level mutable state persists across remounts and hot-reloads; component state is correctly scoped. setProfileEditor(() => module.ProfileEditor) uses the functional-update form to avoid treating the component type as an initializer. Effect deps updated to [isEditing, ProfileEditor] — correct.
build-help.ts — marked.parser(marked.lexer(body)) over marked.parse() as string ✓ — marked.parse() returns string | Promise<string> depending on configuration; the cast was a latent runtime hazard. lexer + parser are both synchronous with no overload ambiguity. Correct fix.
setup-full.mjs — main-module detection ✓ — process.argv[1] && path.resolve(process.argv[1]) === __filename is cleaner than the old url.pathToFileURL(process.argv[1] || '').href form, which had a latent bug: pathToFileURL('') returns the cwd URL, not the script URL, so an empty argv[1] could give a false positive. The new form explicitly guards the empty case. Assuming __filename is declared at the top of the file via fileURLToPath(import.meta.url) (standard ESM pattern; CI would catch it immediately if missing).
useUsage.ts — ref init undefined + optional chain ✓ — useRef(undefined) with fetchUsageRef.current?.() is more honest than a no-op stub; it correctly represents the pre-assignment state and avoids silently swallowing subscription events before fetchUsage is wired.
Coverage tests (#400) and Copilot fixes (#402) ✓ — Already reviewed and approved individually.
Adopter notes in the PR body look accurate (no new migrations, no new secrets, correct merge-conflict callouts).
CalVer release notes
Summary
This promotion brings three commits to production since CalVer tag 2026.005: a security patch for React Router, targeted code-quality fixes in setup and mobile help flows, and restored 100% package test coverage after the Vitest 4 upgrade. The headline change for adopters is upgrading
react-router-domto 6.30.4, which addresses open-redirect vulnerability CVE-2026-40181. There are no new database migrations, required secrets, or pending npm changesets in this release.Highlights
react-router-domto 6.30.4 across web, admin, and articles packages (CVE-2026-40181) (fix(deps): upgrade react-router-dom to 6.30.4 (CVE-2026-40181) #398)ProfileEditorstate to the component instead of module-level mutable state (Fix AI code quality findings in setup, help, and mobile profile #399)setup-full.mjs; parse help markdown synchronously viamarked.lexer/marked.parser(Fix AI code quality findings in setup, help, and mobile profile #399)Stats: 3 commits, +453 / −42 lines across 21 files.
Adopter notes
package-lock.json,apps/web/package.json,packages/admin/package.json,packages/articles/package.json(react-router bump); fork-customizedscripts/setup-full.mjs,apps/mobile/src/screens/ProfileScreen.tsxMaintainer checklist
Merge instructions
Use “Create a merge commit” — do NOT squash. Required by CONTRIBUTING.md and enforced by check-merge-strategy.yml.
Post-merge
mainmain(uses this PR’s CalVer section + git-cliff changelog)Test plan
developat promotion SHA