From eece69cd705624eb8cda81c9c131b189dfb93268 Mon Sep 17 00:00:00 2001 From: fwazb Date: Thu, 23 Jul 2026 22:41:24 -0700 Subject: [PATCH] Fix Cloud SQL staging-function provisioning order Cloud SQL's postgres role is cloudsqlsuperuser, not a true superuser. After ALTER FUNCTION ... OWNER TO leoclean_kb_stage_owner, it can no longer revoke ACLs on the transferred function: ERROR: permission denied for function stage_leoclean_proposal Reorder so ACL normalization and the runtime GRANT happen while postgres still owns the function, then transfer ownership. Identical end state. Observed on teleo-pgvector-standby during M2 Step 4 provisioning (BOOTSTRAP_EXIT=3 at SQL line 800). Co-Authored-By: Claude Opus 4.6 (1M context) --- ops/gcp_leoclean_runtime_role.sql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ops/gcp_leoclean_runtime_role.sql b/ops/gcp_leoclean_runtime_role.sql index 1e27889..a383dc3 100644 --- a/ops/gcp_leoclean_runtime_role.sql +++ b/ops/gcp_leoclean_runtime_role.sql @@ -799,15 +799,11 @@ begin end $function$; -alter function kb_stage.stage_leoclean_proposal(text, text, text, text, jsonb) - owner to leoclean_kb_stage_owner; -revoke create on schema kb_stage from leoclean_kb_stage_owner; - -- Normalize explicit ACL entries left by CREATE OR REPLACE or an earlier grant. -- A newly-created function starts with owner EXECUTE, while CREATE OR REPLACE -- preserves an existing ACL on reruns. Revoke every scoped/default entry here --- so the first successful provision already has the same runtime-only ACL as --- every later provision. +-- while postgres still owns the function, so Cloud SQL's cloudsqlsuperuser +-- privilege is sufficient for the revoke. revoke all on function kb_stage.stage_leoclean_proposal(text, text, text, text, jsonb) from public, leoclean_kb_runtime, leoclean_kb_stage_owner; select format( @@ -828,6 +824,10 @@ select format( grant execute on function kb_stage.stage_leoclean_proposal(text, text, text, text, jsonb) to leoclean_kb_runtime; +alter function kb_stage.stage_leoclean_proposal(text, text, text, text, jsonb) + owner to leoclean_kb_stage_owner; +revoke create on schema kb_stage from leoclean_kb_stage_owner; + select format('revoke leoclean_kb_stage_owner from %I', current_user) where current_user <> 'leoclean_kb_stage_owner' \gexec