diff --git a/AGENTS.md b/AGENTS.md index e65a814..3f18c90 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -74,9 +74,6 @@ description: What this skill does and when to use it. | `license` | No | License name or reference to bundled license file. | | `metadata` | No | Arbitrary key-value pairs (e.g., `author`, `version`). | -**Version bumps:** Any change to `SKILL.md` or files in `references/` must bump -the `version` in the skill's frontmatter metadata before committing. - ### Name Field Rules - Lowercase letters, numbers, and hyphens only (`a-z`, `0-9`, `-`) diff --git a/skills/supabase/SKILL.md b/skills/supabase/SKILL.md index 53b8056..0cba9a1 100644 --- a/skills/supabase/SKILL.md +++ b/skills/supabase/SKILL.md @@ -44,7 +44,7 @@ When working on any Supabase task that touches auth, RLS, views, storage, or use - **RLS, views, and privileged database code** - **Views bypass RLS by default.** In Postgres 15 and above, use `CREATE VIEW ... WITH (security_invoker = true)`. In older versions of Postgres, protect your views by revoking access from the `anon` and `authenticated` roles, or by putting them in an unexposed schema. - **UPDATE requires a SELECT policy.** In Postgres RLS, an UPDATE needs to first SELECT the row. Without a SELECT policy, updates silently return 0 rows — no error, just no change. - - **Do not put `security definer` functions in an exposed schema.** Keep them in a private or otherwise unexposed schema. + - **`SECURITY DEFINER` functions bypass RLS and are callable by all roles by default.** A `SECURITY DEFINER` function runs with its creator's privileges — typically a superuser with `bypassrls`. Supabase also grants `EXECUTE` to `anon`, `authenticated`, and `service_role` for all new functions in `public` by default, making any such function a public API endpoint until that grant is explicitly revoked. Never add `SECURITY DEFINER` to resolve a permission error; it silently removes access control without fixing the underlying cause. Prefer `SECURITY INVOKER`. When `SECURITY DEFINER` is genuinely needed (e.g., bypassing RLS on an internal lookup table), keep the function in a non-exposed schema and always include an `auth.uid()` check in the function body. After any changes involving functions, run `supabase db advisors` and address any findings. - **Storage access control** - **Storage upsert requires INSERT + SELECT + UPDATE.** Granting only INSERT allows new uploads but file replacement (upsert) silently fails. You need all three.