Repository navigation
fix(db): runtime Postgres roles no longer inherit the owner role - #1684
Conversation
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Access role definitions and checks packages/db/src/roles.ts, packages/db/package.json, packages/db/src/roles.test.ts |
The package exports read and read-write role mappings and tests the data and DDL permissions of roles that inherit them. |
Access-scoped branch credentials packages/db/scripts/planetscale-connection.ts, packages/db/scripts/audit-raw-sql.ts, packages/db/scripts/check-row-decoding.ts, packages/db/scripts/check-schema-drift.ts, packages/db/scripts/restore-test.ts |
withBranchConnection requires an access level. Its callers pass read access, and credential creation uses the roles configured for that access level. |
Runtime role configuration alchemy.run.ts, docs/infra.md |
Ingest and per-consumer roles inherit the read-write role set. The infrastructure notes describe runtime role permissions and the Electric and US production Hyperdrive exceptions. |
Priority:
Estimated code review effort: 3 (Moderate) | ~20 minutes
Change: Bug fix
Suggested labels: preview
Suggested reviewers: jeremyfunk
Merge Risk: 
Minimal · up to 9817b
-
No actionable merge-blocking defect was established. Confirm the production role transition during deployment.
Pre-merge checks: 
5
-
Full details: Docstring Coverage
-
Explanation
No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 8 files. (2 skipped: 2 unsupported.)
-
Finishing Touches
-
📝 Generate docstrings
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands.
The ingest gateway role and the EU api/alerting Hyperdrive roles inherited `postgres`, which owns every table, so each runtime login could run DDL. They now inherit pg_read_all_data + pg_write_all_data (DB_ACCESS_ROLES in @maple/db/roles): DML on every current and future table, no DDL, TRUNCATE or ownership. Migrations keep running on alchemy's temporary postgres role. Electric stays on postgres since PlanetScale grants REPLICATION only with it. The PlanetScale script broker now takes an explicit access level per call (read for audits and the restore drill, readWrite for backfills) instead of defaulting to postgres.
4ca9937 to
9817bae
Compare
Maple review🟢 Confidence 9/10 · safe to merge Narrows every declared prd runtime Postgres login from inheriting
Before merge
What was checked
|
There was a problem hiding this comment.
🔍 Devin Review: 2 flags
Not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)
|
Merged with 3 steps from "Before merge" still open. If they are done, tick them on the review comment; if not, now is the time.
|
Summary
db-api-role, EUdb-alerting-role) inheritedpostgres, which owns every table, so each service could alter or drop schemaDB_ACCESS_ROLES.readWrite(pg_read_all_data+pg_write_all_data, new@maple/db/roles). DML on every current and future table and sequence; no DDL, TRUNCATE, ownership or role management. Migrations still run on alchemy's temporarypostgresrolepackages/db/src/roles.test.ts: migrates the real schema in PGlite, then as each login checks reads, writes, sequencenextval, refusal of CREATE/DROP/ALTER/TRUNCATE/CREATE ROLE, and that a table added later is covered with no extra grant. WithreadWriteset back to["postgres"]the 4 DDL-refusal cases failplanetscale-connection.tsmintedpostgres-inheriting credentials by default for every data scriptwithBranchConnection(branch, access, fn)takes an explicit level:readfor audit-raw-sql, check-schema-drift, check-row-decoding and the restore drill (all current callers);readWriteis there for a future write script. The env override topostgresis goneWhy built-in roles instead of per-table GRANTs: PlanetScale's role API only accepts its built-in role list for
inherited_roles, and the role names it generates are not known when migrations run, so a migration cannotGRANTto them.pg_read_all_data/pg_write_all_dataapply to tables created later, which covers the "future migrations" case withoutALTER DEFAULT PRIVILEGES. A per-table matrix (below) is a follow-up if PlanetScale ever accepts custom inherited roles.Electric is unchanged: PlanetScale grants
REPLICATIONonly together withpostgres(documented on the alchemy resource). Its publication is already owned by a migration (ELECTRIC_MANUAL_TABLE_PUBLISHING), so it does not need ownership for that.Per-service inventory (from code)
ingest-gateway(ECS, pooled)org_ingest_keys,sources,org_clickhouse_settings,cloudflare_logpush_connectors,gcp_connectors,org_ingest_sampling_policies,org_ingest_attribute_mappingssources,cloudflare_logpush_connectors,gcp_connectorsdb-api-role(EU Hyperdrive)packages/backendservicespg_advisory_xact_lock)db-alerting-role(EU Hyperdrive)electric-db-role(ECS)electric_publication_defaultPostgresBranchpostgresrole, unchanged)Breaking-change risk
inheritedRolesis a create-first replace of each role: new credentials, the Hyperdrive configs and the ingest task env (MAPLE_PG_ROLE_ID) roll to them, then the old role is deleted with successorpostgres. Brief dual-credential window, no downtime expected.permission denied. Code search found none; the EU deploy is the first real exercise.pscale role create --inherited-roles pg_read_all_data,pg_write_all_data:pscale0.332.0role create --helpdocuments the flag as a comma-separated list and names both roles as standard values. Not run against a database.api/alertingHyperdrive configs are dashboard-managed (ref), so their credentials are untouched by this PR.Verification
bun run --cwd packages/db test -- src/roles.test.ts: 21 passed; 4 fail with the old grant (re-run after rebasing onto main 2026-10-25, so the tables added since, e.g. the security-audit store, are covered).bun run --cwd packages/db typecheck,tsrs -p tsconfig.alchemy.json,bun run lint: clean.Needs a human
Draft on purpose: this changes production database roles.
declarePreviewDb), so apreviewdeploy only proves nothing else regressed. Still worth one: labelpreview, then check sign-in and a dashboard load (api), an alert rule preview and a tick (alerting), MCPlist_services(ai), an OTLP post toingest-pr-<n>returning 2xx (ingest), and a live-updating list (Electric).declared: all three runtime roles change). Watch the deploy create the new roles, updatedb-api/db-alertingHyperdrive and roll the ingest tasks before deleting the old roles. Then verify on EU: API 2xx on dashboards/alerts, alerting ticks withoutpermission deniedin Maple's own logs, ingest key auth plussources.last_used_atadvancing, Electric shapes still syncing. Then US prd (onlyingest-gatewaychanges); same ingest checks.pg_read_all_data,pg_write_all_dataif you want parity.postgres).pg_write_all_datais offered on these clusters (it is in the API enum alchemy ships).Need help on this PR? Tag
@codesmith-botwith what you need.Summary by CodeRabbit