Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion supabase/drift-manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"generated_at": "2026-07-13T08:06:40.593Z",
"generated_at": "2026-07-13T08:13:14.832Z",
"generator": "scripts/generate-drift-manifest.ts",
"postgres_image": "supabase/postgres:17.6.1.127",
"schema_sha256": "0a30a1ea8c8dbb3fd520115d28a17d99c94d9bc5164efe6c287c3b48969be81b",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- Codify the migration version already recorded on production. These two
-- retrieval helpers are server-only, so their EXECUTE posture matches the
-- schema-wide service-role-only policy in supabase/schema.sql.

set search_path = public, extensions, pg_temp;

revoke execute on function public.retrieval_owner_matches(uuid, uuid)
from public, anon, authenticated;
grant execute on function public.retrieval_owner_matches(uuid, uuid)
to service_role;

revoke execute on function public.search_document_chunks(uuid, text, integer, uuid)
from public, anon, authenticated;
grant execute on function public.search_document_chunks(uuid, text, integer, uuid)
to service_role;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-- Codify the migration version already recorded on production. The functions
-- are worker-only and must not retain PostgreSQL's default PUBLIC EXECUTE.

set search_path = public, pg_catalog, pg_temp;

revoke execute on function public.complete_ingestion_job(uuid, uuid, uuid, text, text)
from public, anon, authenticated;
grant execute on function public.complete_ingestion_job(uuid, uuid, uuid, text, text)
to service_role;

revoke execute on function public.fail_or_retry_ingestion_job(uuid, uuid, uuid, boolean, text, text, text, timestamp with time zone, text)
from public, anon, authenticated;
grant execute on function public.fail_or_retry_ingestion_job(uuid, uuid, uuid, boolean, text, text, text, timestamp with time zone, text)
to service_role;
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
-- Reconcile ingestion RPC permissions (revoke execute from public)
-- Recent migration 20260708130000 dropped and recreated complete_ingestion_job and fail_or_retry_ingestion_job.
-- Since migrations run as supabase_admin on Supabase, the default privileges for role postgres
-- do not apply. We must explicitly revoke PUBLIC execution on these new signatures.
-- NEUTRALIZED 2026-07-13 -- DO NOT DELETE THIS FILE.
--
-- Production recorded this ACL reconciliation under its generated migration
-- version, 20260709062443. That exact migration now lives in the repository.
-- Keep this later duplicate stem as a no-op so branches that previously saw it
-- retain monotonic history without applying the same grants twice.

set search_path = public, pg_catalog, pg_temp;

revoke execute on function public.complete_ingestion_job(uuid, uuid, uuid, text, text) from public, anon, authenticated;
grant execute on function public.complete_ingestion_job(uuid, uuid, uuid, text, text) to service_role;

revoke execute on function public.fail_or_retry_ingestion_job(uuid, uuid, uuid, boolean, text, text, text, timestamp with time zone, text) from public, anon, authenticated;
grant execute on function public.fail_or_retry_ingestion_job(uuid, uuid, uuid, boolean, text, text, text, timestamp with time zone, text) to service_role;
select 1 where false;
29 changes: 29 additions & 0 deletions tests/supabase-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ const ingestionJobsOneOpenMigration = readFileSync(
new URL("../supabase/migrations/20260708170000_ingestion_jobs_one_open_per_document.sql", import.meta.url),
"utf8",
).replace(/\s+/g, " ");
const retrievalPublicExecuteMigration = readFileSync(
new URL("../supabase/migrations/20260708150150_harden_retrieval_public_execute.sql", import.meta.url),
"utf8",
).replace(/\s+/g, " ");
const ingestionRpcPrivilegesMigration = readFileSync(
new URL("../supabase/migrations/20260709062443_reconcile_ingestion_rpc_privileges_production.sql", import.meta.url),
"utf8",
).replace(/\s+/g, " ");
const ingestionRpcPrivilegesDuplicateMigration = readFileSync(
new URL("../supabase/migrations/20260709150000_reconcile_ingestion_rpc_privileges.sql", import.meta.url),
"utf8",
).replace(/\s+/g, " ");
const atomicReindexMigration = readFileSync(
new URL("../supabase/migrations/20260628000000_atomic_reindex_generation_commit.sql", import.meta.url),
"utf8",
Expand Down Expand Up @@ -954,4 +966,21 @@ describe("Supabase Preview replay guards", () => {
expect(ingestionJobsOneOpenMigration).toContain("ingestion_jobs_one_open_per_document_uidx");
expect(ingestionJobsOneOpenMigration).not.toContain("concurrently");
});

it("codifies production ACL migration versions and neutralizes the later duplicate", () => {
expect(retrievalPublicExecuteMigration).toContain(
"revoke execute on function public.retrieval_owner_matches(uuid, uuid)",
);
expect(retrievalPublicExecuteMigration).toContain(
"revoke execute on function public.search_document_chunks(uuid, text, integer, uuid)",
);
expect(ingestionRpcPrivilegesMigration).toContain(
"revoke execute on function public.complete_ingestion_job(uuid, uuid, uuid, text, text)",
);
expect(ingestionRpcPrivilegesMigration).toContain(
"revoke execute on function public.fail_or_retry_ingestion_job(uuid, uuid, uuid, boolean, text, text, text, timestamp with time zone, text)",
);
expect(ingestionRpcPrivilegesDuplicateMigration).toContain("NEUTRALIZED 2026-07-13");
expect(ingestionRpcPrivilegesDuplicateMigration).toContain("select 1 where false;");
});
Comment on lines +970 to +985

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Assert the complete ACL and no-op contracts.

These assertions would remain green if service_role grants were removed, the revoked roles changed, or the neutralized migration retained active ACL SQL. Assert both the exact from public, anon, authenticated and to service_role clauses for all four functions, and assert the duplicate contains no set search_path, revoke execute, or grant execute statements.

Suggested assertions
+    for (const [migration, signature] of [
+      [retrievalPublicExecuteMigration, "public.retrieval_owner_matches(uuid, uuid)"],
+      [retrievalPublicExecuteMigration, "public.search_document_chunks(uuid, text, integer, uuid)"],
+      [ingestionRpcPrivilegesMigration, "public.complete_ingestion_job(uuid, uuid, uuid, text, text)"],
+      [ingestionRpcPrivilegesMigration, "public.fail_or_retry_ingestion_job(uuid, uuid, uuid, boolean, text, text, text, timestamp with time zone, text)"],
+    ] as const) {
+      expect(migration).toContain(
+        `revoke execute on function ${signature} from public, anon, authenticated;`,
+      );
+      expect(migration).toContain(
+        `grant execute on function ${signature} to service_role;`,
+      );
+    }
+    expect(ingestionRpcPrivilegesDuplicateMigration).not.toMatch(
+      /set search_path|revoke execute on function|grant execute on function/,
+    );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it("codifies production ACL migration versions and neutralizes the later duplicate", () => {
expect(retrievalPublicExecuteMigration).toContain(
"revoke execute on function public.retrieval_owner_matches(uuid, uuid)",
);
expect(retrievalPublicExecuteMigration).toContain(
"revoke execute on function public.search_document_chunks(uuid, text, integer, uuid)",
);
expect(ingestionRpcPrivilegesMigration).toContain(
"revoke execute on function public.complete_ingestion_job(uuid, uuid, uuid, text, text)",
);
expect(ingestionRpcPrivilegesMigration).toContain(
"revoke execute on function public.fail_or_retry_ingestion_job(uuid, uuid, uuid, boolean, text, text, text, timestamp with time zone, text)",
);
expect(ingestionRpcPrivilegesDuplicateMigration).toContain("NEUTRALIZED 2026-07-13");
expect(ingestionRpcPrivilegesDuplicateMigration).toContain("select 1 where false;");
});
it("codifies production ACL migration versions and neutralizes the later duplicate", () => {
expect(retrievalPublicExecuteMigration).toContain(
"revoke execute on function public.retrieval_owner_matches(uuid, uuid)",
);
expect(retrievalPublicExecuteMigration).toContain(
"revoke execute on function public.search_document_chunks(uuid, text, integer, uuid)",
);
expect(ingestionRpcPrivilegesMigration).toContain(
"revoke execute on function public.complete_ingestion_job(uuid, uuid, uuid, text, text)",
);
expect(ingestionRpcPrivilegesMigration).toContain(
"revoke execute on function public.fail_or_retry_ingestion_job(uuid, uuid, uuid, boolean, text, text, text, timestamp with time zone, text)",
);
for (const [migration, signature] of [
[retrievalPublicExecuteMigration, "public.retrieval_owner_matches(uuid, uuid)"],
[retrievalPublicExecuteMigration, "public.search_document_chunks(uuid, text, integer, uuid)"],
[ingestionRpcPrivilegesMigration, "public.complete_ingestion_job(uuid, uuid, uuid, text, text)"],
[ingestionRpcPrivilegesMigration, "public.fail_or_retry_ingestion_job(uuid, uuid, uuid, boolean, text, text, text, timestamp with time zone, text)"],
] as const) {
expect(migration).toContain(
`revoke execute on function ${signature} from public, anon, authenticated;`,
);
expect(migration).toContain(
`grant execute on function ${signature} to service_role;`,
);
}
expect(ingestionRpcPrivilegesDuplicateMigration).toContain("NEUTRALIZED 2026-07-13");
expect(ingestionRpcPrivilegesDuplicateMigration).toContain("select 1 where false;");
expect(ingestionRpcPrivilegesDuplicateMigration).not.toMatch(
/set search_path|revoke execute on function|grant execute on function/,
);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/supabase-schema.test.ts` around lines 970 - 985, Strengthen the ACL
migration test in the existing test case by asserting the exact from public,
anon, authenticated and to service_role clauses for all four functions,
preserving each function signature. Extend the duplicate-migration assertions to
verify it contains no set search_path, revoke execute, or grant execute
statements while retaining its neutralized marker and false no-op assertion.

});