Write Eval for RLS quickstart prompt - #168
Open
czenko wants to merge 1 commit into
Open
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
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.
Problem
supabase/supabase#48710 adds an
<AiPrompt id="row-level-security" />panel to the Row Level Security guide — an 11-rule checklist telling an agent how to enable RLS, scope grants, write one policy per operation, wrapauth.uid()in aselect, index the columns policies filter on, keep cross-table checks behind asecurity definerhelper in a private schema, and prove the result with pgTAP.Nothing measures whether an agent handed that prompt actually produces working policies and tests. The rules were assembled from the guide itself, the
security-rls-basics.md/security-rls-performance.mdreferences insupabase/agent-skills, and thecontent/row-level-securitymodule ofsupabase/supacademy— sound sources, but the prompt has only been reviewed by inspection. A rule that reads correctly can still produce SQL that does not run, or policies that pass review and fail to isolate.Existing coverage does not reach it.
build-tests-001-rls-tenant-isolationmeasures whether an agent can diagnose a planted policy bug from test results; no eval measures whether an agent can author a policy set and a test suite to a specification.Solution
Adds
build-cli-005-quickstart-rls, the sibling ofbuild-cli-004-quickstart-nextjsfor the RLS guide's prompt. Same shape: the docs prompt copied verbatim,skills: []so the prompt is measured standing alone rather than the prompt plus the agent-skills RLS references it was partly built from.PROMPT.md— therow-level-securityentry fromai-prompts.data.tsverbatim,suite: regression,services: [gotrue, kong, postgrest].local/— a four-table team wiki with nothing locked down: no RLS, no grants, no policies, no indexes beyond the primary keys, nosupabase/tests/. The prompt says how to write policies but not what access the app wants, so the intended rules live in comments at the top of the migration and the agent has to read them. Each omission maps to a rule:documentscovers 1-5, andteam_documentsis what makes 6 and 7 measurable — reading it needs a membership check against a table the comments say clients must never read, so the only design satisfying both is asecurity definerhelper in a private schema.team_membershas a(team_id, user_id)primary key, so rule 5's "a column that already leads a primary key does not need another one" is live: onlyuser_idneeds a new index.EVAL.ts— 25 checks, deterministic wherever possible:public, a separate policy per operation with noFOR ALLcatch-all,using+with checkon every update, everyauth.uid()/auth.jwt()call wrapped, policy-filtered columns indexed, asearch_path-pinnedsecurity definerhelper in a schema the agent created,team_documentscalling it rather than joiningteam_members, andhas_table_privilegefor grants in both directions.supabase test dbruns at least 8 assertions with none failing, and onejudge()over the test SQL for allow/deny coverage per operation across both roles.Manual testing
Verified against a hand-written reference solution on a real local stack, rather than by inspection.
evals/build-cli-005-quickstart-rls/local/to a scratch directory andsupabase start. Confirm the migration applies and no table has RLS, grants, policies, or extra indexes.security definermembership helper, RLS on all four tables, per-operation policies scopedto authenticatedwith(select auth.uid()), btree indexes ondocuments.owner_id/team_members.user_id/team_documents.team_id, grants forauthenticatedonly.psqlagainst that database. All nine return what the scorer expects:rolesrenders{authenticated}, quals render( SELECT auth.uid() AS uid)so the wrapped-call regex matches,indkey[0]finds the leading-column indexes, and the helper is the onlysecurity defineroutside the stack schemas.42501, and both silent-denial cases leave the target rows intact.anon.supabase test dbreportsResult: PASS, and the scorer's summary parse reads it correctly.Two scorer bugs surfaced this way and are fixed in the branch:
Tests=/Failed:alone. A suite whose plan does not match the assertions it ran printsTests: 6 Failed: 0while exiting non-zero withResult: FAIL— that would have scored as a pass. It now gates on the exit status too.with checkviolation or a missing grant genuinely does raise; only ausing-filtered row is silent. The rubric now distinguishes the two, so a correctthrows_okis no longer marked wrong.pnpm eval:dry -- --eval build-cli-005-quickstart-rls --experiment claude-code-sonnet-5,claude-code-sonnet-5-no-skillsconfirms discovery, frontmatter validation,mode=local-stack, and thatskills: []makes the no-skills experiment reportSKIP … (skipEval).tsc --noEmitandpnpm formatare clean.