Use raw role names verbatim for worker connections - #364
Conversation
Pass the pg_roles.rolname value directly to the connection builder instead of reinterpreting it as a quoted SQL identifier. This keeps quote-wrapped catalog names from collapsing onto a different login role. Cover both the rejected superuser-identity substitution and successful execution as a literal quote-wrapped role.
There was a problem hiding this comment.
Pull request overview
This PR hardens pg_durable’s worker connection authentication by ensuring the background worker passes catalog role names (rolname) verbatim to the libpq/sqlx connection builder, avoiding any reinterpretation of quote-wrapped names as SQL identifiers (which could otherwise collapse onto a different login role).
Changes:
- Remove SQL-identifier-style “unquoting/normalization” from the worker connection username path and pass the role name through unchanged.
- Extend E2E coverage for quote-sensitive role-name edge cases, including a boundary case where a role name literally includes quote bytes.
- Update the unreleased changelog to document the security-relevant fix.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/types.rs |
Stops normalizing role names for connections; passes user directly into PgConnectOptions::username. |
tests/e2e/sql/49_quoted_role_names.sql |
Adds a boundary regression ensuring a role named "quoteedge" (quotes included) runs as itself, not as quoteedge. |
tests/e2e/sql/17_superuser_guc.sql |
Adds a negative test that a quoted catalog role resembling postgres cannot authenticate as the real superuser. |
CHANGELOG.md |
Documents the fix under the unreleased version. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Pino de Candia (pinodeca)
left a comment
There was a problem hiding this comment.
One test reliability issue found. The production change is directionally correct and the positive current_user assertion covers the central quote-wrapped-role regression, but the new negative superuser test has a race that can yield a false pass.
| SET SESSION AUTHORIZATION df_e2e_user; | ||
| INSERT INTO _su_guc_t6 | ||
| SELECT df.start( | ||
| 'INSERT INTO su_guc_quoted_role_sentinel VALUES (''unexpected superuser identity'')', | ||
| 'su-guc-test6-quoted-role-identity' | ||
| ); | ||
| RESET SESSION AUTHORIZATION; | ||
|
|
||
| SET SESSION AUTHORIZATION su_guc_forger; | ||
| DO $forge_quoted_role$ | ||
| DECLARE | ||
| inst TEXT; | ||
| BEGIN | ||
| SELECT instance_id INTO inst FROM _su_guc_t6; | ||
| UPDATE df.instances | ||
| SET submitted_by = ( | ||
| SELECT oid::regrole FROM pg_roles WHERE rolname = chr(34) || 'postgres' || chr(34) | ||
| ) | ||
| WHERE id = inst; | ||
| UPDATE df.nodes | ||
| SET submitted_by = ( | ||
| SELECT oid::regrole FROM pg_roles WHERE rolname = chr(34) || 'postgres' || chr(34) | ||
| ) | ||
| WHERE instance_id = inst; | ||
| END $forge_quoted_role$; | ||
| RESET SESSION AUTHORIZATION; |
There was a problem hiding this comment.
P2 — Make submission and forgery atomic. df.start() commits before these updates, so the worker can load or execute the graph as the original df_e2e_user first. That role also cannot insert into su_guc_quoted_role_sentinel, producing exactly the asserted failed status and empty sentinel; the test can therefore pass without exercising the quoted-role connection path. Please wrap submission plus both identity updates in one explicit transaction so the worker cannot observe the instance until the forged identity is committed. It would also help to assert the failure detail identifies authentication of the literal quoted role rather than accepting any failure.
Summary
Security impact
Catalog role names are literal strings, not quoted SQL identifiers. Reinterpreting a quote-wrapped name could collapse it onto a distinct login role and make the worker execute under the wrong identity.
Validation
cargo fmt -p pg_durable -- --checkcargo check --features pg17cargo clippy --features pg17 -- -D warnings./scripts/test-e2e-local.sh --verbose 17_superuser_guc(passed)./scripts/test-e2e-local.sh --verbose 49_quoted_role_names(passed)