Skip to content

Signed-in people can read their wedding again on the hosted project - #21

Merged
JFrusher merged 1 commit into
mainfrom
claude/quirky-wright-mxysvu
Sep 30, 2026
Merged

JFrusher merged 1 commit into
mainfrom
claude/quirky-wright-mxysvu

Conversation

@JFrusher

Copy link
Copy Markdown
Owner

Summary

The hosted Supabase project no longer matched the migrations, and no signed-in person could read their wedding. This PR brings into the repository the two migrations that fixed it. Both are already applied to the hosted project, under the versions it recorded, so merging changes nothing there. It keeps supabase/migrations/ in step with the project's migration history, so a later supabase db push doesn't find versions it lacks.

What was wrong

  • is_wedding_member(uuid) could not be executed by authenticated, and ran as its caller (security invoker).
  • delete_my_account() could not be executed by authenticated either.

Every migration says otherwise, and none changes them. These are two of the Security Advisor's own remedies for its warnings on these functions. What applied them isn't in the project's logs, which go back to 2026-09-20.

The effect is in the logs. After signing in on 2026-09-29 at 07:45 UTC, every GET /rest/v1/wedding_members returned 403, with Postgres logging permission denied for function is_wedding_member. Deleting an account failed for the same reason.

With the grant restored, the check still ran as its caller. It asked the wedding_members policy, which asks the check again, so reads failed with stack depth limit exceeded until the second migration made it security definer again.

Changes

  • supabase/migrations/20260930155142_member_grants.sql
    • grants is_wedding_member(uuid) and delete_my_account() to authenticated again;
    • revokes the trigger function announce_wedding_document() from anon and authenticated. Postgres already refused to run it outside a trigger; this takes it off the API.
  • supabase/migrations/20260930155610_member_definer.sql makes is_wedding_member(uuid) security definer again.
  • suite/lib/documents/history.migrations.test.ts adds a PGlite test that reproduces the drift, asserts both refusals, applies the two migrations, and checks the member reads their wedding and can delete their account. The anon-grants test also covers the trigger function.
  • suite/lib/testing/database.ts: the harness grants usage on its auth schema to anon and authenticated, as Supabase does.
  • docs/SELF-HOSTING.md warns against the Security Advisor's remedies for these functions: the 16 callable by signed-in people, and the 3 link functions open to anyone. Those warnings describe the design.
  • docs/superpowers/specs/2026-09-29-database-review.md records this as D8.

Verification

On the hosted project, after both migrations:

  • a signed-in stranger sees no weddings, members, documents or history, and gets no error;
  • the account holder sees their one wedding, membership and document, and 40 history entries (counts only);
  • the security advisor lists only the intended functions.

Every other function's definition matches the migrations exactly, once the dashboard's \r\n line endings are ignored.

Locally: 1,906 suite tests, typecheck and lint pass. The new test fails when the definer migration is blanked.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1


Generated by Claude Code

The hosted project had drifted from the migrations: is_wedding_member ran
as its caller and, with delete_my_account, could not be executed by
authenticated. Every read of a wedding was refused (403, "permission
denied for function is_wedding_member") and deleting an account failed.
Granted again, the check recursed through the policy it serves ("stack
depth limit exceeded"), so it is a security definer again too.

Both migrations are applied to the hosted project under the versions it
recorded, and change nothing where the functions never drifted. The
trigger function is taken from anon and authenticated. A PGlite test
models the drift and the fix; the harness grants the auth schema to the
API roles, as Supabase does. The self-hosting guide warns against the
Security Advisor's remedies for these functions; the review records D8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
@vercel

vercel Bot commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
trousseau-suite Ready Ready Preview Sep 30, 2026 4:05pm UTC

@JFrusher
JFrusher merged commit ce429f1 into main Sep 30, 2026
8 of 10 checks passed

This branch was successfully deployed

1 active deployment
Preview — 38747ae5 Deployed Sep 30, 2026 by vercel[bot]
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