Skip to content

Commit 35df1b5

Browse files
committed
feat: grant REINDEX capability to analytics user in read-write mode
- PG < 16 read-write: use superuser (pg_maintain doesn't exist) - PG >= 16 read-write: grant pg_maintain for REINDEX/VACUUM/ANALYZE - PG >= 14 read-only: unchanged (pg_read_all_data only) - PG < 14: unchanged (superuser)
1 parent e5e6563 commit 35df1b5

3 files changed

Lines changed: 39 additions & 9 deletions

File tree

src/controllers/replica.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1167,7 +1167,8 @@ async fn reconcile_schema_migration(
11671167
return Err(Error::SchemaMigration(msg));
11681168
}
11691169

1170-
// The analytics user already has pg_write_all_data + CREATE ON DATABASE
1170+
// The analytics user already has write privileges (superuser on PG < 17,
1171+
// pg_write_all_data + pg_maintain + CREATE ON DATABASE on PG >= 17)
11711172
// when persistent_schemas is configured (read_only is effectively false),
11721173
// so we reuse the replica creds secret for write access to the target.
11731174
let target_superuser_secret_name = reader_secret_name.clone();

src/controllers/restore/builders.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,8 @@ fi
599599
600600
echo "Detected PG major version: $PG_MAJOR"
601601
602-
if [ "$PG_MAJOR" -ge 14 ]; then
602+
if [ "$PG_MAJOR" -ge 14 ] && [ "{read_only}" = "true" ]; then
603+
# PG >= 14 read-only: granular read role
603604
psql -U postgres -d postgres << SQLEOF
604605
DO \$\$
605606
BEGIN
@@ -612,13 +613,23 @@ END
612613
\$\$;
613614
GRANT pg_read_all_data TO ${{ANALYTICS_USERNAME}};
614615
SQLEOF
616+
echo "Read-only mode with PG >= 14, granted pg_read_all_data"
615617
616-
if [ "{read_only}" = "true" ]; then
617-
echo "Read-only mode with PG >= 14, granted pg_read_all_data"
618-
else
619-
echo "Read-write mode with PG >= 14, granting pg_write_all_data + CREATE ON DATABASE..."
620-
psql -U postgres -d postgres << SQLEOF
618+
elif [ "$PG_MAJOR" -ge 17 ]; then
619+
# PG >= 17 read-write: granular roles including pg_maintain
620+
psql -U postgres -d postgres << SQLEOF
621+
DO \$\$
622+
BEGIN
623+
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${{ANALYTICS_USERNAME}}') THEN
624+
CREATE ROLE ${{ANALYTICS_USERNAME}} WITH LOGIN PASSWORD '${{ANALYTICS_PASSWORD}}';
625+
ELSE
626+
ALTER ROLE ${{ANALYTICS_USERNAME}} WITH PASSWORD '${{ANALYTICS_PASSWORD}}';
627+
END IF;
628+
END
629+
\$\$;
630+
GRANT pg_read_all_data TO ${{ANALYTICS_USERNAME}};
621631
GRANT pg_write_all_data TO ${{ANALYTICS_USERNAME}};
632+
GRANT pg_maintain TO ${{ANALYTICS_USERNAME}};
622633
DO \$\$
623634
DECLARE
624635
dbname text;
@@ -630,9 +641,11 @@ BEGIN
630641
END
631642
\$\$;
632643
SQLEOF
633-
fi
644+
echo "Read-write mode with PG >= 17, granted pg_read_all_data + pg_write_all_data + pg_maintain + CREATE ON DATABASE"
645+
634646
else
635-
echo "PG < 14, granting superuser to analytics user..."
647+
# PG < 14, or PG 14-16 read-write: superuser
648+
echo "Granting superuser to analytics user (PG < 17 read-write or PG < 14)..."
636649
psql -U postgres -d postgres << SQLEOF
637650
DO \$\$
638651
BEGIN

tests/lifecycle.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,22 @@ async fn analytics_create_schema_read_write() {
399399
)
400400
.await;
401401

402+
println!("--- verifying analytics user can REINDEX");
403+
kubectl_exec(
404+
ns,
405+
&deploy_target,
406+
&[
407+
"psql",
408+
"-U",
409+
"analytics",
410+
"-d",
411+
"myapp",
412+
"-c",
413+
"REINDEX TABLE test_pgro_app.rw_test",
414+
],
415+
)
416+
.await;
417+
402418
println!("--- all read-write assertions passed, cleaning up");
403419
cleanup_namespace(&client, ns, &["rw-replica"]).await;
404420
}

0 commit comments

Comments
 (0)