Skip to content

fix(db): add missing RLS policy + app-role grant to PartnerProgram - #62

Open
keithfawcett wants to merge 1 commit into
mainfrom
fix/partner-program-rls
Open

fix(db): add missing RLS policy + app-role grant to PartnerProgram#62
keithfawcett wants to merge 1 commit into
mainfrom
fix/partner-program-rls

Conversation

@keithfawcett

Copy link
Copy Markdown
Contributor

What

PartnerProgram (formerly PartnerCampaign) is the only tenant-scoped table with no tenant_isolation RLS policy and no openpartner_app grant. Its create migration (20260511) ran after the global RLS/grant migrations (20260507*) and never added them; the rename migration's comment claims a policy "already existed" — it never did.

Prod is confirmed on the app role (DATABASE_URL_APP + OPENPARTNER_APP_DB_PASSWORD populated, OPENPARTNER_TENANCY=multi), so:

  • Queries to PartnerProgram fail permission denied whenever the partner↔program feature is used (latent until that route is hit — not yet observed in logs).
  • On a privileged-pool deploy, the absent policy means no tenant filter at all (the read path in partner-campaigns.ts leans on RLS, not an explicit tenantId column filter).

Found via an unsteered Codex review.

Fix

One migration mirroring the canonical pattern in 20260613000000_partner_postback.ts: enable + force RLS, add the tenant_isolation policy (USING + WITH CHECK on app.tenant_id / app.platform_admin), and an idempotent openpartner_app grant guarded on the role existing.

Verified locally after pnpm migrate: relrowsecurity/relforcerowsecurity = t, policy present (ALL), grant present (SELECT/INSERT/UPDATE/DELETE).

Deploy

Migrations don't auto-run on deploy here — run pnpm migrate against prod after merge (same as prior migration PRs).

🤖 Generated with Claude Code

PartnerProgram (formerly PartnerCampaign) was created after the global
RLS/grant migrations and never got its own tenant_isolation policy or
openpartner_app DML grant — every other tenant table created since
(PartnerPostback, etc.) does. The rename migration only assumed a policy
existed. Prod runs the app role (DATABASE_URL_APP + OPENPARTNER_APP_DB_PASSWORD
set, OPENPARTNER_TENANCY=multi), so PartnerProgram queries would fail
permission-denied when the partner↔program feature is exercised; on a
privileged-pool deploy the absent policy means no tenant filter.

Adds enable/force RLS + tenant_isolation policy + idempotent app-role grant,
mirroring 20260613000000_partner_postback.ts. Verified locally: relrowsecurity
+ relforcerowsecurity = t, policy present (ALL, USING+WITH CHECK), grant
present. NOTE: prod migrations are manual — run `pnpm migrate` against prod
after merge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
keithfawcett added a commit that referenced this pull request Aug 9, 2026
Turns the handoff brief into a status record: what each item was, what
actually shipped, and — the part that is still open — the staging
exercises that have to pass before either money path is trusted.

Item A (#10, PR #73): planner/executor split with a durable payout intent
and a frozen commission set. Item B (#12, PR #75): the three funding
races plus a live-Stripe backstop for missed refund/reversal webhooks.
Item C (#8, PR #74): the three missing tables, per-table primary keys, a
portable SQL dump, and two array round-trip bugs the test found.

No code left on any of the three; the remaining work is the staging
checklists in docs/direct-connect-payouts.md and section H of the funding
staging runbook, plus the two post-merge prod actions for #62 and #63.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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