Skip to content

Promote dev to main: hardening pass + bulk dependency upgrade#31

Merged
brianfunk merged 46 commits into
mainfrom
dev
May 18, 2026
Merged

Promote dev to main: hardening pass + bulk dependency upgrade#31
brianfunk merged 46 commits into
mainfrom
dev

Conversation

@brianfunk

Copy link
Copy Markdown
Collaborator

Summary

Syncs `main` with `dev`. Brings everything that landed since the previous `main` cut into production:

Repo hardening (#23)

  • CLAUDE.md / AGENTS.md collaboration docs
  • CI: hardened ci.yml, new Trivy / Secret Scan / SBOM workflows, Dependabot config
  • Branch protection enabled on dev + main (1 reviewer, required checks, no force push)
  • Cypress removed; Playwright is the sole E2E
  • Dead migration scripts deleted, SETUP.md rewritten
  • ErrorBoundary at app root; DocketDetail copy-to-clipboard toast
  • Protoware license; legal page dates refreshed
  • Supabase RLS migration for commenter_info and docket_tags
  • Migration backlog resolved (pgcrypto pre-flight, enum-ADD-VALUE split)
  • React.lazy route splitting (initial bundle 837 KB → 367 KB)
  • Fresh-DB migration replay wired into CI

Bulk dependency upgrade (#30)

  • React 18 → 19, Supabase 2.52 → 2.105, Vite 7 → 8, Vitest 3 → 4, Playwright 1.58 → 1.60, lucide 0.344 → 0.577
  • All testing-, types-, and github-actions-group bumps
  • 0 vulnerabilities; all gates green

Test plan

  • Required checks (Lint & Type Check, Unit Tests, Build, Migration Validation) pass against main's strict-status requirement
  • Netlify production deploy succeeds on the merge commit
  • Smoke test the production site after deploy

Aligns OpenComments with the MetaPhase house standard used in dutystation,
ITspending, ceta, and minimis. Captures product invariants (RLS-on-everything,
WCAG 2.1 AA, anonymous-friendly submission), branch protection rules, release
gates, and PR review workflow.
Aligns CI with the MetaPhase house standard. New workflows are warn-only
where appropriate so flaky scans don't block merges, but findings surface
in the Security tab. Adds Dependabot weekly grouped updates for npm and
github-actions ecosystems.
- Drop Cypress (only Playwright remains as E2E framework). Removes the
  critical basic-ftp transitive advisory.
- Delete broken apply-migrations.js (called a non-existent exec_sql RPC)
  and the two loose fix-*.sql one-off patches.
- Remove the db:custom-migrate npm script; SETUP.md now points at
  'npx supabase db push' as the only documented path.
- Bump minimatch override to 10.2.5 to close the remaining high-severity
  advisories transitively pulled in via eslint and typescript-eslint.
- npm audit reports 0 vulnerabilities.
Closes the Supabase advisor 'rls_disabled_in_public' alert. Both tables
were created in the initial schema without ENABLE ROW LEVEL SECURITY.

Policies:
- commenter_info: service_role full access; active agency members of the
  parent docket's agency can read for moderation. No anon access.
- docket_tags: public SELECT (tags are part of public docket display);
  writes restricted to active agency members of the docket's owning agency.

Both tables are read in production only via SECURITY DEFINER search
functions (20250729100012, 20250729100013), so enabling RLS does not
break any existing client query path.
brianfunk and others added 16 commits May 17, 2026 21:42
- LICENSE.md (Protoware v1.0, U.S. gov use only) replaces MIT LICENSE.
  Mirrors CETA and other MetaPhase CivicTech repos.
- README badge and License section updated.
- About page 'Open Source' section now describes Protoware instead of MIT.
- Last-updated date on Privacy, Terms, Accessibility, Security, About,
  Onboarding, and UserGuide pages bumped to May 17, 2026.
- Add ErrorBoundary at app root so an unhandled render error no longer
  blanks the public site; users get a reload-friendly fallback.
- DocketDetail copy-to-clipboard now shows a polite toast on success/error
  instead of a silent TODO.
- Hotfix SQL at scripts/hotfix-enable-rls-initial-tables.sql lets the
  remote Supabase advisor be closed without forcing a full migration
  backlog replay.
- aquasecurity/trivy-action@0.28.0 is the briefly-compromised release;
  dependency-review-action flags it as critical. Move to 0.36.0 (matches
  dutystation's pin).
- Drop .github/workflows/codeql.yml. GitHub's default CodeQL setup is
  already enabled on this repo; the advanced workflow conflicts with
  it ('CodeQL analyses from advanced configurations cannot be processed
  when the default setup is enabled').
test-results/ leaked into the previous commit; ignore it (plus the
playwright-report/ and .cache directories) so local runs don't pollute
future commits.
Both gates pass cleanly on this branch (npm audit reports 0 production
vulnerabilities; all 13 axe routes pass), so continue-on-error: true is
no longer needed and was masking real regressions. Required checks now
fail the merge if a high-severity production dep advisory lands or an
axe critical violation is introduced.
…cleanly

Three changes lets the full chain replay against the linked Supabase
project:

1. New 20260211000050_enum_additions.sql extracts the ALTER TYPE ADD
   VALUE calls for agency_role and comment_status out of the reconcile
   migration. Postgres rejects using a freshly-added enum value in the
   same transaction (SQLSTATE 55P04 'unsafe use of new value'); the
   reconcile migration's RLS helper functions reference 'manager', so
   the value must commit first.
2. 20260211000100 now ensures the pgcrypto extension exists in the
   extensions schema and schema-qualifies gen_random_bytes() so the
   invitation-token default works regardless of the connection's
   search_path.
3. The reconcile migration's enum-add blocks are removed (now in
   ...000050) with a pointer comment so the split stays discoverable.

Verified with 'supabase db push --linked --include-all' — all 9
local migrations now present on remote, supabase advisor
'rls_disabled_in_public' alert is closed.

The scripts/hotfix-enable-rls-initial-tables.sql one-off is no longer
needed and has been removed.
- netlify.toml NODE_VERSION 18 -> 20 (CI already on 20).
- README tech-stack line no longer lists Cypress (removed earlier in
  this PR). Calls out Playwright + axe-core as the E2E/a11y stack.
- CLAUDE.md and AGENTS.md updated to reflect the unified Node 20 pin.
Combines a one-time fix and a permanent guardrail so the pgcrypto class
of bug stops biting us:

- supabase/migrations/20250729100000_create_initial_schema.sql now
  creates the 'extensions' schema and installs pgcrypto into it. Mirrors
  Supabase's managed layout. Every fresh deploy (local, CI, future
  branch) has the extension from migration zero. Idempotent: harmless on
  the already-applied remote since CREATE EXTENSION IF NOT EXISTS is a
  no-op there.
- scripts/validate-migrations-fresh.sh now creates the same extensions
  schema and aligns the test DB's search_path with Supabase's
  (public, extensions), so schema-qualified calls like
  extensions.gen_random_bytes() and unqualified calls both resolve the
  way they do in production.
- New CI job 'Migration Replay (fresh DB)' boots a throwaway
  PostgreSQL 16 and runs npm run db:validate:fresh. This catches the
  drift we just spent half this PR fixing — out-of-order enum value
  use, missing extension prerequisites, etc — before merge instead of
  after.

Verified locally: fresh replay against an empty Postgres applies all 17
migrations cleanly and produces 20 public tables.
Drops the initial bundle from 837 kB (199 kB gzipped) to 367 kB
(107 kB gzipped) — roughly 56 % off the first-paint payload — by
turning all 40 page components into dynamic imports. Each route now
ships as its own ~10–30 kB chunk fetched on demand.

A single top-level <Suspense> with an accessible RouteFallback (spinner
with aria-live='polite' and an sr-only 'Loading…' label) wraps the
router. Landing-page chrome (Header, Hero, StateDirectory,
FeatureHighlights, CalloutBanner, Footer) stays eager so '/' never
shows the fallback.

Why this matters: a public commenting platform takes meaningful traffic
on mobile and constrained connections. Cutting the JS payload in half
improves TTI for the audience the product is designed to reach, and
keeps the WCAG 2.1 AA release gate honest — slow networks disproportionately
affect users on assistive tech.

Verified:
- npm run typecheck — green
- npm run test:ci — 28/28 passing
- npm run test:a11y — 13/13 axe routes passing (Suspense fallback
  doesn't introduce critical violations)
- npm run build — succeeds; no Vite chunk-size warning
Repo hardening: CI security workflows, RLS fix, top maintenance items
Bumps the github-actions group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `4` | `6` |
| [actions/setup-node](https://github.com/actions/setup-node) | `4` | `6` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `4` | `7` |
| [actions/dependency-review-action](https://github.com/actions/dependency-review-action) | `4` | `5` |
| [github/codeql-action](https://github.com/github/codeql-action) | `3` | `4` |


Updates `actions/checkout` from 4 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v4...v6)

Updates `actions/setup-node` from 4 to 6
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](actions/setup-node@v4...v6)

Updates `actions/upload-artifact` from 4 to 7
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4...v7)

Updates `actions/dependency-review-action` from 4 to 5
- [Release notes](https://github.com/actions/dependency-review-action/releases)
- [Commits](actions/dependency-review-action@v4...v5)

Updates `github/codeql-action` from 3 to 4
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/dependency-review-action
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: github/codeql-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
…wright 1.60, lucide 0.577

Consolidates the six Dependabot grouped PRs (#24#29) into a single
upgrade pass with one CI run.

Runtime:
- react / react-dom: 18.3.1 -> 19.2.6
- react-router-dom: 7.7.1 -> 7.15.1
- @supabase/supabase-js: 2.52.1 -> 2.105.4
- lucide-react: 0.344.0 -> 0.577.0 (last 0.x; v1.x drops brand icons
  like Github/Linkedin that this codebase uses; staying on 0.x adds
  React 19 peer support without losing the icons)

Dev:
- @types/react / @types/react-dom: bumped to 19.x to match runtime
- vite: 7.0.6 -> 8.0.13 (now rolldown-powered)
- @vitejs/plugin-react: 4.7.0 -> 6.0.2
- vitest: 3.2.4 -> 4.1.6
- @playwright/test / playwright: 1.58.2 -> 1.60.0
- @axe-core/playwright: 4.10.2 -> 4.11.3
- @testing-library/jest-dom: 6.6.4 -> 6.9.1
- @testing-library/react: 16.3.0 -> 16.3.2
- jest-environment-jsdom: 30.0.5 -> 30.4.1
- eslint-plugin-react-refresh: 0.4.11 -> 0.5.2
- globals: 15.9.0 -> 17.6.0

Intentionally NOT bumped:
- eslint 9.x and @eslint/js 9.x kept (eslint 10 requires
  eslint-plugin-react-hooks 7, which adds strict React-Compiler rules
  that error on ~84 currently-fine patterns — orthogonal refactor).
- eslint-plugin-react-hooks 5.x kept for the same reason.

GitHub Actions:
- actions/checkout: v4 -> v6
- actions/setup-node: v4 -> v6
- actions/upload-artifact: v4 -> v7
- actions/dependency-review-action: v4 -> v5
- github/codeql-action: v3 -> v4

Verified locally:
- npm install — 0 vulnerabilities
- npm run typecheck — green
- npm run lint — 0 errors (170 pre-existing warnings unchanged)
- npm run build — 503 KB initial (still well under the pre-split 837 KB)
- npm run test:ci — 28/28 passing
- npm run test:a11y — 13/13 axe routes passing
- npm run db:validate:fresh — 17 migrations replay cleanly, 20 public tables
Vite 8 (rolldown) and a few other deps ship platform-specific native
binaries. npm install on macOS only writes the host platform's optional
deps into the lockfile, so npm ci on Linux runners fails with
'Missing: @emnapi/core@1.10.0 from lock file' even though everything
resolves correctly locally.

Trading strict ci reproducibility for the practical workaround other
repos in the org use. The lockfile is still committed and used by
npm install; --no-audit / --no-fund just keep the install output
focused on the real work.
…tions/github-actions-0d9431b73f

ci(deps): bump the github-actions group with 5 updates
Bulk dependency upgrade: React 19, Supabase 2.105, Vite 8, Vitest 4
@brianfunk brianfunk merged commit b43825b into main May 18, 2026
31 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ec132fbfa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/ci.yml
- name: Run a11y suite
env:
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL || 'https://example.supabase.co' }}
VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY || 'placeholder-anon-key' }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use valid fallback Supabase anon key in CI env

When repository secrets are unavailable (for example, PRs from forks), the workflow injects placeholder-anon-key, but validateSupabaseConfig rejects any key that does not start with eyJ or sb_ (src/lib/supabase.ts, key format guard). That makes the frontend throw during startup under Playwright, so the accessibility job can fail even though application code is fine. Use a syntactically valid dummy key (e.g., sb_...) for the fallback to keep CI runnable without secrets.

Useful? React with 👍 / 👎.

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.

1 participant