db_query: the DATABASE_URL password is silently ignored, so any connection fails with SASL: client password must be a string unless ~/.pgpass happens to have a matching entry #281
Closed
opened 2026-09-20 22:19:44 +00:00 by david
·
0 comments
No Branch/Tag specified
main
feature/issue-342/mssql-write-access-check-and-startup-warning-never
feature/issue-331/mssql-write-extensions-mssql-readme-md-setup-tools
feature/issue-330/mssql-register-extension-add-tests-to-root-test-sc
feature/issue-329/mssql-index-ts-wiring-load-env-refuse-on-invalid-l
feature/issue-328/mssql-mssql-table-schema-tool-parameterised
feature/issue-327/mssql-mssql-list-tables-tool
feature/issue-326/mssql-mssql-query-and-mssql-query-one-tools
feature/issue-325/mssql-stream-runner-with-row-cap-cancel-and-timeou
feature/issue-324/mssql-pool-config-builder-encrypt-on-certificate-s
feature/issue-323/mssql-audit-log-writer-pi-mssql-audit-log-mode-060
feature/issue-322/mssql-read-only-guard-module-validatesql-with-corp
feature/issue-321/mssql-certificate-trust-setting-and-limit-validati
feature/issue-320/mssql-loadenvfile-and-mssql-url-parsing
feature/issue-319/mssql-extension-skeleton-permanent-corpora-and-dep
feature/issue-318/mssql-spike-write-result-md-apply-the-gate-open-th
feature/issue-317/mssql-spike-scoring-runner-for-both-candidates
feature/issue-316/mssql-spike-candidate-b-guard-using-the-antlr4-t-s
feature/issue-315/mssql-spike-candidate-a-guard-using-node-sql-parse
feature/issue-314/mssql-spike-must-accept-corpus
feature/issue-313/mssql-spike-scaffold-spike-directory-and-must-reje
feature/issue-311/mssql-spike-check-dependencies-mssql-node-sql-pars
feature/issue-312/mssql-spike-check-whether-extension-tests-run-in-c
feature/issue-299/verify-the-ste-style-live-in-a-short-grill-session
feature/issue-298/bump-the-grillme-extension-to-0-4-0-and-add-the-ch
feature/issue-297/rewrite-extensions-grillme-design-md-in-ste-style
feature/issue-296/rewrite-extensions-grillme-readme-md-in-ste-style
feature/issue-295/rewrite-the-grill-me-command-output-and-read-only
feature/issue-294/rewrite-the-grill-me-tool-metadata-to-the-ste-rule
feature/issue-293/extract-buildgrillprompt-and-add-the-prompt-integr
feature/issue-292/add-ste-style-test-ts-checks-for-the-rule-text-and
feature/issue-291/add-the-pure-ste-style-ts-module-and-inject-the-st
feature/issue-264/verify-the-vision-tool-live-against-the-deepseek-a
feature/issue-263/list-the-vision-extension-in-the-repo-root-readme
feature/issue-262/write-extensions-vision-readme-md-the-10-section-p
feature/issue-261/wire-the-vision-extension-into-package-json-manife
feature/issue-260/implement-extensions-vision-index-ts-factory-regis
feature/issue-258/implement-extensions-vision-src-tool-ts-the-vision
feature/issue-257/implement-extensions-vision-src-client-ts-request
feature/issue-256/implement-extensions-vision-src-usage-ts-usage-map
feature/issue-255/implement-extensions-vision-src-images-ts-read-val
feature/issue-254/implement-extensions-vision-src-config-ts-env-reso
feature/issue-253/implement-extensions-vision-src-errors-ts-toolerro
feature/issue-252/penpot-add-text-stages-zero-area-auto-width-text-p
feature/issue-216/add-the-penpot-skill-and-extension-to-the-repo-roo
feature/issue-217/register-the-penpot-tests-in-npm-test-complete-the
feature/issue-215/write-the-penpot-skill-md-core-workflow-token-conv
feature/issue-214/implement-and-run-fetch-penpot-docs-mjs-and-commit
feature/issue-213/validate-screenshot-reconstruction-against-the-liv
feature/issue-212/add-the-image-to-design-workflow-to-skills-penpot
feature/issue-211/validate-svg-import-icon-and-illustration-against
feature/issue-210/implement-the-penpot-add-svg-tool-with-svg-raw-fal
feature/issue-209/implement-the-svg-to-shapes-converter-in-src-svg-t
feature/issue-208/validate-component-instancing-against-the-live-ins
feature/issue-207/implement-penpot-instance-component-with-id-remapp
feature/issue-206/author-and-commit-the-component-library-artifact-u
feature/issue-205/implement-file-library-linking-and-validate-the-ex
feature/issue-204/implement-penpot-export-library-sse-uri-plus-artif
feature/issue-203/implement-penpot-import-library-multipart-upload-p
feature/issue-202/implement-the-transit-decoder-and-sse-stream-parse
feature/issue-201/validate-a-full-composed-screen-one-commit-one-rev
feature/issue-200/implement-penpot-add-image-with-media-upload
feature/issue-199/implement-asset-reference-resolution-plus-penpot-a
feature/issue-198/implement-penpot-add-frame-with-auto-layout-props
feature/issue-197/validate-asset-creation-atomicity-and-write-safety
feature/issue-196/implement-the-designated-target-write-guard-with-a
feature/issue-195/implement-penpot-commit-with-revn-tracking-conflic
feature/issue-194/implement-the-staged-changeset-store-and-the-colou
feature/issue-193/validate-read-primitives-against-the-live-penpot-i
feature/issue-192/implement-the-penpot-list-library-tool-with-name-t
feature/issue-191/implement-the-penpot-get-file-tool-pages-objects-a
feature/issue-190/implement-the-penpot-list-projects-tool-teams-and
feature/issue-189/implement-the-penpot-whoami-tool-and-wire-the-exte
feature/issue-188/implement-the-rpc-client-and-error-decoding-in-src
feature/issue-187/implement-penpot-url-penpot-token-resolution-in-sr
feature/issue-186/scaffold-the-penpot-extension-directory-and-regist
feature/issue-172/add-end-to-end-main-tests-for-the-fj-rg-tool-state
feature/issue-171/make-reminder-report-dynamic-install-skip-counts-r
feature/issue-170/wire-settings-json-filter-rewrite-into-dedupeandre
feature/issue-169/implement-buildpackagefilters-with-exhaustive-unit
feature/issue-168/refactor-preflight-to-skip-warn-for-missing-fj-rg
feature/issue-167/add-fj-rg-tool-detection-helpers-rgavailable-detec
feature/issue-148/reconcile-design-md-and-implementation-plan-with-t
feature/issue-146/verify-extension-load-behavior-with-and-without-mo
feature/issue-145/write-extensions-mongodb-readme-md
feature/issue-144/write-tool-description-promptsnippet-guidance-for
feature/issue-143/implement-index-ts-async-factory-lifecycle-with-te
feature/issue-142/implement-the-mongo-list-collections-tool-with-uni
feature/issue-141/implement-the-mongo-count-tool-with-unit-tests
feature/issue-140/implement-the-mongo-find-tool-with-unit-tests
feature/issue-139/implement-src-errors-ts-with-unit-tests-toolerror
feature/issue-138/implement-src-serialize-ts-with-unit-tests-ejson-t
feature/issue-136/implement-src-env-ts-with-unit-tests-mongodb-uri-r
feature/issue-135/register-the-mongodb-extension-in-the-repo-root-pa
feature/issue-133/initialize-the-extensions-mongodb-package-package
feature/issue-116/src-actions-ts-downloadrunlogs-zip-guarded-unzip-c
feature/issue-115/src-actions-ts-downloadjoblog-cache-first-attempt
feature/issue-114/src-actions-ts-metadata-queries-listactionruns-get
feature/issue-113/src-actionscache-ts-cache-paths-cache-first-read-w
feature/issue-112/add-zip-extraction-dependency-adm-zip-vs-yauzl
feature/issue-111/tracking-forgejo-actions-tooling-read-only-runs-jo
feature/issue-93/add-unit-tests-for-scripts-local-install-mjs-node
feature/issue-92/validate-install-local-end-to-end-on-the-dev-machi
feature/issue-90/implement-pi-registration-with-url-dedupe-and-relo
feature/issue-89/validate-install-local-from-a-scratch-clone-fresh
feature/issue-88/implement-git-pull-and-npm-install-steps-in-script
feature/issue-74/write-victorialogs-readme-md-and-reconcile-design
feature/issue-73/wire-up-index-ts-extension-factory-and-register-al
feature/issue-72/implement-logs-facets-tool-src-tools-facets-ts
feature/issue-71/implement-logs-hits-tool-src-tools-hits-ts
feature/issue-70/implement-logs-search-tool-src-tools-search-ts
feature/issue-69/implement-parsejsonlines-helper-in-src-client-ts
feature/issue-68/implement-victorialogsrequest-in-src-client-ts
feature/issue-67/implement-resolvebaseurl-in-src-env-ts
feature/issue-66/implement-totoolerror-in-src-errors-ts
feature/issue-65/implement-src-defaults-ts-shared-constants-and-app
feature/issue-64/scaffold-the-victorialogs-pi-extension-project
feature/issue-53/skip-issue-creation-for-chore-documentation-commit
feature/issue-45/fix-local-install-preflight-env-var-requirements-s
feature/issue-41/add-npm-run-local-install-script-to-update-and-ins
feature/issue-26/cross-reference-forgejo-list-milestones-from-issue
feature/issue-25/add-forgejo-milestone-delete-tool
feature/issue-24/add-forgejo-milestone-close-and-forgejo-milestone
feature/issue-23/add-forgejo-milestone-edit-tool
feature/issue-22/add-forgejo-milestone-view-tool
feature/issue-21/add-forgejo-list-milestones-tool
feature/issue-20/add-forgejo-milestone-create-tool
feature/issue-18/add-forgejo-label-create-tool
feature/issue-29/bug-forgejo-issue-create-view-edit-close-etc-crash
No results found.
Labels
No labels
bug
chore
documentation
enhancement
feature
ready
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
david/pi-extensions-and-skills#281
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
The postgres extension never uses the password in
DATABASE_URL.parseConnUrl()deliberately returns only{ host, port, database, user }, and the pool is built with apasswordProvideroption thatpgdoes not support, so it is silently ignored. The only remaining source of a password ispg's built-in~/.pgpasslookup — which means a perfectly validDATABASE_URLfails to connect whenever~/.pgpasshas no entry for that host/user.The resulting error names SCRAM, not the missing credential, so the failure looks like a bad password rather than an unread password:
Impact
DATABASE_URLwhose host/user/database triple is absent from~/.pgpasscannot be used at all. Switching from a remote dev DB to a local one is enough to break the tool with no configuration change on the extension side.pg'spgpasssupport is deprecated and removed inpg@9(node_modules/pg/lib/client.js:23-27), so on apgmajor upgrade the extension loses password resolution entirely, including the.pgpasspath that currently works by accident.db_query,db_list_tables,db_table_schema. The extension loads, logs a success line, and only fails at first query, which makes it look like a server-side problem.Environment
pi-extensions-and-skills@1a73f36(2026-09-18), branchmainpg8.23.0,pgpass1.0.6 (package.jsondeclarespg: ^8.13.0,pgpass: ^1.0.6).envofprocess.cwd()(the project pi is launched in)DATABASE_URL=postgresql://postgres:***@localhost:5432/shoppy_devSteps to reproduce
.envcontaining a complete URL, e.g.:DATABASE_URL=postgresql://postgres:secret@localhost:5432/shoppy_dev~/.pgpasshas no line matchinglocalhost:5432:shoppy_dev:postgres. (Confirmed by an existing~/.pgpassthat only lists a different host, e.g.10.1.1.243:5432:shoppy_dev:shoppy_dev:….)db_querywithSELECT 1.SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string.Adding
localhost:5432:shoppy_dev:postgres:secretto~/.pgpassmakes the identical call succeed — which isolates the cause to password resolution, not to the URL, the server, or the credentials.Expected
The password from
DATABASE_URLis used for the connection.~/.pgpassremains a fallback for password-less URLs and for deployments that deliberately keep the secret out of.env.Actual
The URL password is discarded before the pool is constructed,
passwordProvideris ignored,pgfinds no.pgpassentry, and the password staysundefined.Root cause
The password is dropped during URL parsing.
extensions/postgres/env.ts:parseConnUrl()mapsURL→ exactly those four fields (parsed.hostname,parsed.port,parsed.pathname,parsed.username). There is nopasswordfield anywhere in the file (grep -n password env.ts→ no matches).The intended fallback is not a
pgoption.extensions/postgres/index.ts:131-143builds the pool with:passwordProviderdoes not exist inpg8.23.0 — nothing innode_modules/pg/lib/orpg-pool/references it — so it is dropped on the floor and the closure never runs.pgthen supplies its ownpgpasslookup, and gives up silently on a miss.node_modules/pg/lib/client.js:296-310:With no matching
.pgpassline,passisundefined, no password is set, and the SCRAM handshake throwsclient password must be a string. Note the file's own comment on the supported form:i.e. the supported option is
password, notpasswordProvider.Proposed fix
The two changes together make the URL authoritative and keep
.pgpassas a genuine fallback:env.ts— carry the password through. Addpassword?: stringtoConnInfo, returnpassword: parsed.password || undefinedfromparseConnUrl()(normalising""toundefinedso password-less URLs still fall back), and include it inextractConnInfo().index.ts— use the supported option. Either letconnInfo.passwordflow into the pool and delete the provider entirely (relying onpg's own.pgpassfallback when the URL has no password), or rename the option topasswordas the deprecation notice instructs. If the explicitpgpasscall is kept, a no-match must resolve tonull/undefinedrather than""— an empty string is a valid string to SCRAM and produces a different, equally confusingpassword authentication failederror.Worth deciding explicitly whether
ConnInfoomitting the password is a deliberate security boundary. As it stands it is not one: the extension already reads the same secret out of.envvialoadEnvFile(), so dropping it after parsing only breaks the connection without protecting anything. Fix 1 above assumes that is true; if the omission is intentional, then thepgpassfallback is the load-bearing path and must work forpg@9— which its deprecation rules out.Workaround (no code change)
Add a matching line to
~/.pgpass(mode600):This works today but leaves the extension dependent on a deprecated
pgfeature.Acceptance criteria
DATABASE_URLand no matching~/.pgpassentry, all three tools connect and return results.DATABASE_URLand a matching~/.pgpassentry, behaviour is unchanged.client password must be a string.pg's deprecated built-inpgpasspath.Test plan
extensions/postgres/env.test.ts—parseConnUrl()carries the password; an empty password normalises toundefined;extractConnInfo()preserves it.extensions/postgres/index.test.ts— the pool/client config passed topgcontains the resolved password (fakepgmodule), and a password-less URL still falls back rather than passing"".~/.pgpassstates above against a local database.