fix(setup): make a fresh clone runnable + prove RLS denies cross-user access - #2
Merged
Merged
Conversation
…ross-user access A clean `git clone` could not follow the README past step 2: - `.gitignore`'s `.env*` swallowed `.env.example`, so `cp .env.example .env` failed. Added a `!.env.example` negation and committed a placeholder-only template that also documents DIRECT_URL, SUPABASE_SERVICE_ROLE_KEY, CRON_SECRET and NEXT_PUBLIC_SITE_URL. - `prisma/prisma.config.ts` was never loaded by the Prisma CLI (7.8 only looks in the cwd), so `prisma migrate dev` / `db push` died with "The datasource.url property is required in your Prisma config file" even with a correct .env. Moved it to the repo root; `db push` now works. - `dotenv` is imported by prisma.config.ts but was only present as a transitive dependency of prisma; declared it in devDependencies. RLS was version-controlled but nothing proved it denied anything. Added `prisma/rls/verify-rls.sql` + `npm run test:rls`: it stands up the Supabase pieces the policies depend on (auth.uid(), the authenticated/anon roles), applies the real 001_enable_rls.sql, seeds two users, then asserts that user A is denied every cross-user read, update, delete and forged insert across all 8 tables, and that an anonymous client sees nothing. One transaction, rolled back; refuses to run against a Supabase database. Verified green on Postgres 16 and verified red (exit 3) when the policy file is not applied. Also: - hooks/useRealtimeLogs.ts subscribed to `daily_logs` / `user_id` / `problems_solved`, but schema.prisma declares no @@Map, so the real names are "DailyLog" / "userId" / "problemsSolved" — the subscription could never fire. Corrected, with a note that the table must be added to the supabase_realtime publication. - playwright.config.ts: reuseExistingServer is now !process.env.CI, so CI can't silently test whatever else happens to be listening on :3000. - README: dropped the Framer Motion claim (not a dependency, never imported) and the "edge computing" claim (everything is the Node runtime); added the live URL, the unit-test/CI story, the RLS section, `npx playwright install`, and the credentials the e2e suite actually needs.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Verification pass on a clean clone of
main(Node 22, npm 10, macOS). Everything below was reproduced from a freshgit clone, not from the local working copy.What a stranger hit
mainnpm installpostinstall: prisma generatesucceeds with no env varscp .env.example .envcp: .env.example: No such file or directory..gitignore's.env*never let the template into the reponpx prisma generatenpx prisma migrate dev/db pushError: The datasource.url property is required in your Prisma config file.DEBUG=prisma:config*shows why:No config file found in the current working directory. Prisma 7.8 only looks in the cwd, and the config lives atprisma/prisma.config.tsnpm run dev/npm run buildDATABASE_URL; build dies at page-data collection withError: DATABASE_URL is not defined— true but undocumentednpm test(Playwright)npx playwright install(undocumented) and a live Supabase project + service-role keySo the documented setup path was broken in two places before anyone could see the app.
Fixes
.env.examplenow ships —!.env.examplenegation in.gitignore, template extended withDIRECT_URL,SUPABASE_SERVICE_ROLE_KEY,CRON_SECRET,NEXT_PUBLIC_SITE_URL,RLS_TEST_DATABASE_URL. Placeholders only.prisma.config.tsmoved to the repo root so the CLI actually loads it.npx prisma db pushverified working afterwards.dotenvdeclared in devDependencies —prisma.config.tsimports it but it was only present transitively viaprisma.hooks/useRealtimeLogs.tssubscribed to a table that does not exist. It listened ondaily_logs/user_id/problems_solved, butschema.prismahas no@@map, so the real names are"DailyLog"/"userId"/"problemsSolved". The subscription could never fire — the "realtime" feature was dead. Names corrected. Not verifiable offline: needs a live Supabase check plusALTER PUBLICATION supabase_realtime ADD TABLE "DailyLog";.playwright.config.ts:reuseExistingServer: !process.env.CI. It was unconditionallytrue, so a run would happily test whatever else was listening on :3000 (that actually happened during this verification — an unrelated dev server held the port).npx playwright install, and the e2e credential prerequisites.RLS is now proven, not asserted
prisma/migrations/001_enable_rls.sqlwas real and complete (RLS enabled + a policy on all 8 user-owned tables), but nothing tested that it denies anything. Addedprisma/rls/verify-rls.sqlandnpm run test:rls:It stands up the Supabase pieces the policies depend on (
auth.uid(), theauthenticated/anonroles),\ir-includes the real policy file, seeds two users, then asserts as user A that every cross-user read, update, delete and forged insert is denied on all 8 tables and that an anonymous client sees zero rows — while user A's own access still works. Any leak raises and exits non-zero. One transaction, rolled back, and it refuses to run against a Supabase database.Results on local Postgres 16:
Negative control (same script with the policy include removed, fresh DB):
ERROR: Tables without RLS coverage: User (RLS not enabled), DailyLog (RLS not enabled), ..., exit 3 — so the test is not vacuous.The README now also states the honest scope: RLS protects the Realtime/PostgREST paths; the app's own reads go through Prisma as the table owner, which bypasses RLS, so server-side isolation still comes from the
userIdfilters inlib/services/*.Gate
Ran exactly what
.github/workflows/ci.ymlruns, all green:npx prisma generate✅npm run type-check✅npm run lint✅npm run test:unit✅ — 37 passed (date 15, streak 10, scoring 7, recommendations 5), matching the claim exactlyPlus, on a fresh
git archiveof this branch:npm install→cp .env.example .env→npx prisma db push→ apply RLS →npm run test:rls(exit 0) →npm run devserving 200s.Still open (not fixed here)
page.waitForURL(/.*dashboard.*/)after 30s, then1 failed, 75 did not runfor chromium — 226 tests across 3 browsers, none executed. Needs a dedicated Supabase test project.types/index.ts:54still has// TODO: Add milestone types when created.docs/archive/tests/*.txtare committed stale test-failure logs./api/healthstill does not exist, and/api/cron/keepaliveis unauthenticated whenCRON_SECRETis unset.No secrets are or ever were tracked in git (
git ls-files | grep -i envis empty across all history);test-results/andplaywright-report/are correctly ignored.