Repository navigation
br-util-postgres 0.1.1
·
1 commit
to main
since this release
0.1.1
Changed
ensure_app_rolerefuses an empty password. It returnsPostgresError::Configbefore any statement is sent; it used to clear the role password silently. A password containing a NUL byte is refused the same way.- The stored secret is always SCRAM-SHA-256, whatever
password_encryptionsays, because the crate sends a verifier and Postgres stores it as is. Clients without SCRAM support cannot log in as this role. - The verifier uses a fixed iteration count of 4096. The
ALTER ROLEruns as a non-persistent statement, so sqlx does not keep the verifier in its statement cache. - A server-side password policy hook such as
passwordcheckcannot see the plain password, because Postgres only receives the verifier.
Fixed
ensure_app_roleno longer fails when several callers create the same role at once. The check-then-createDOblock had no lock and no retry, so parallel first calls raced onCREATE ROLE(42710 duplicate_objector apg_authid_rolname_indexunique violation) and onALTER ROLE ... PASSWORD(XX000 tuple concurrently updated). The create and the password change now run in one transaction under a per-rolepg_advisory_xact_lock, which serialises callers of one database. Callers on different databases of one cluster, which an advisory lock cannot order, retry up to 6 attempts with a short backoff on exactly these three SQLSTATEs; any other error, and the last failed attempt, is returned asPostgresError::Db. The public signature is unchanged.tokiois a new direct dependency,timefeature only.grant_app_accessno longer fails when several callers grant at once. Its fiveGRANT/ALTER DEFAULT PRIVILEGESstatements ran autocommit with no lock and no retry, so replicas starting together on a fresh database failed withXX000 tuple concurrently updatedor apg_default_acl_role_nsp_obj_indexunique violation, including when two different app roles were granted at once. The five statements now run in one transaction under one database-widepg_advisory_xact_lock(its own key namespace, distinct from theensure_app_roleone), with the same bounded retry asensure_app_rolefor callers the lock cannot order; the retry helper is shared by both functions. The public signature and the error type are unchanged.
Security
ensure_app_roleno longer sends the clear password to Postgres. It used to buildALTER ROLE "r" PASSWORD $tag$clear$tag$, so the clear password sat in the statement text (server logs,pg_stat_statements, the wire). It now computes a SCRAM-SHA-256 verifier in the process (postgres-protocol, random 16-byte salt, 4096 iterations) and sends onlyALTER ROLE "r" PASSWORD 'SCRAM-SHA-256$4096:...';pg_authid.rolpasswordholds the verifier. The verifier is checked against the alphabet[A-Za-z0-9+/=$:-]before it is quoted, and a failed check isPostgresError::Config. The dollar-quote machinery and the buffer scrub are removed. The new dependency ispostgres-protocol0.6.12or later, the first release outside RUSTSEC-2026-0179 and RUSTSEC-2026-0180; it addsfallible-iteratorand the RustCrypto 0.11 line (hmac,sha2,md-5,digestand their small helper crates) next to the 0.10 linesqlxalready uses.