fix(postmaster): honor AUTOPG_PG_PASSWORD for initdb and the admin pool - #142
Conversation
PostgresManager always accepted options.password (initdb --pwfile on fresh clusters + the TCP admin pool), but the postmaster entry never wired it, silently pinning the built-in default. Supervisors that rotate the superuser password (the k8s chart's provision Job) then crash-loop the postmaster on every restart: the admin pool re-authenticates fresh at each boot and is refused (observed in the omni k8s node-restart incident, 2026-07-03). Resolution order mirrors settings-schema server.pgPassword: AUTOPG_PG_PASSWORD > PGSERVE_PG_PASSWORD (legacy) > default. Empty strings are treated as unset. The source (never the value) is logged, and postmaster --help documents the env.
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 34520702 | Triggered | Generic Password | 5832467 | tests/lib/postmaster-password.test.js | View secret |
| 34520702 | Triggered | Generic Password | 5832467 | tests/lib/postmaster-password.test.js | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secrets safely. Learn here the best practices.
- Revoke and rotate these secrets.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Code Review
This pull request introduces managed superuser password resolution for the postmaster entry point. It resolves the password from the AUTOPG_PG_PASSWORD or PGSERVE_PG_PASSWORD (legacy) environment variables, falling back to 'postgres' by default, and wires it into PostgresManager. This prevents crash-loops when the superuser password is rotated. Feedback suggests improving the robustness of resolvePostmasterPassword by using the nullish coalescing operator (??) to safely handle null arguments instead of only relying on default parameters, and adding corresponding test coverage for null and undefined inputs.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| export function resolvePostmasterPassword(env = process.env) { | ||
| for (const name of POSTMASTER_PASSWORD_ENV_VARS) { | ||
| const value = env[name]; |
There was a problem hiding this comment.
In JavaScript, default parameters (e.g., env = process.env) only apply when the argument is undefined. If null is explicitly passed to resolvePostmasterPassword(null), the function will throw a TypeError when attempting to access env[name].
Using the nullish coalescing operator (??) inside the function body ensures that both null and undefined are safely handled by falling back to process.env, improving the robustness of the password resolution.
export function resolvePostmasterPassword(env) {
const targetEnv = env ?? process.env;
for (const name of POSTMASTER_PASSWORD_ENV_VARS) {
const value = targetEnv[name];| test('defaults to the built-in password with an empty environment', () => { | ||
| expect(resolvePostmasterPassword({})).toEqual({ | ||
| password: DEFAULT_POSTMASTER_PASSWORD, | ||
| source: 'default', | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Update the test case to verify that resolvePostmasterPassword handles null and undefined inputs robustly without throwing a TypeError.
| test('defaults to the built-in password with an empty environment', () => { | |
| expect(resolvePostmasterPassword({})).toEqual({ | |
| password: DEFAULT_POSTMASTER_PASSWORD, | |
| source: 'default', | |
| }); | |
| }); | |
| test('defaults to the built-in password with an empty environment, null, or undefined', () => { | |
| expect(resolvePostmasterPassword({})).toEqual({ | |
| password: DEFAULT_POSTMASTER_PASSWORD, | |
| source: 'default', | |
| }); | |
| expect(resolvePostmasterPassword(null)).toEqual({ | |
| password: DEFAULT_POSTMASTER_PASSWORD, | |
| source: 'default', | |
| }); | |
| expect(resolvePostmasterPassword(undefined)).toEqual({ | |
| password: DEFAULT_POSTMASTER_PASSWORD, | |
| source: 'default', | |
| }); | |
| }); |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 58324677d1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return { password: value, source: name }; | ||
| } | ||
| } | ||
| return { password: DEFAULT_POSTMASTER_PASSWORD, source: 'default' }; |
There was a problem hiding this comment.
Honor server.pgPassword from settings.json
In installs where the operator sets the documented secret with autopg config set server.pgPassword ... (or edits ~/.autopg/settings.json) and then restarts the pm2/systemd postmaster, this resolver still falls back to 'postgres' unless an env var is present. I checked src/settings-loader.cjs, which defines the effective precedence as defaults < file < env, and docs/settings-schema.md documents server.pgPassword as the backend superuser password; bypassing that file layer means the admin pool can still authenticate with the wrong password and crash-loop in the same restart scenario this change is intended to fix.
Useful? React with 👍 / 👎.
Postmaster ignores the managed superuser password
The bug (found debugging a k8s node-restart incident, 2026-07-03):
PostgresManagerhas always acceptedoptions.password— it flows into initdb's--pwfileon fresh clusters (src/postgres.js:717-730) and into the TCP admin pool (:787). But thepostmastersubcommand never wires it:parsePostmasterArgshas no password surface and the constructor call passes none, sothis.passwordsilently pins to the built-in'postgres'(src/postgres.js:542).Impact: any supervisor that rotates the superuser password (e.g. a k8s Helm provision job doing
ALTER USER postgres PASSWORD ...) crash-loops the postmaster on every restart — the admin pool re-authenticates fresh at each boot and is refused:It works until the first restart, which makes it a latent production landmine. Note
cli-ui.cjs:366already honorsserver.pgPassword— the postmaster was the odd one out.The fix: a small resolver (
src/lib/postmaster-password.js) wired into the postmaster entry, mirroring thesettings-schema.cjs server.pgPasswordenv chain:AUTOPG_PG_PASSWORD>PGSERVE_PG_PASSWORD(legacy) >'postgres'AUTOPG_PG_PASSWORD=in a unit file can't blank the pool password).postmaster --helpdocuments the env.secretKeyRef, pm2 via env files.Tests:
tests/lib/postmaster-password.test.js— 7 cases (default, both env vars, precedence, empty-string, schema-name lock,--helpadvertisement). Full suite: 701 pass / 1 pre-existing failure (tests/console/smoke.test.js— bundled console asset absent on a clean clone; fails identically ondevwithout this change).eslint src/ bin/clean.Downstream: with this shipped, the k8s chart (#141) can restore superuser-password rotation by setting
AUTOPG_PG_PASSWORDfrom its Secret — rotation was removed there as a workaround for this exact bug.