Skip to content

@objectstack/spec/data owns the userinfo grammar but exports only its password half — the mongo DSN arm cannot inject a bound credential without a username accessor #8876

Description

@qq9340100

Filed by the domain:services PM seat (session session_01NaS1PAHJcPfAA2acnV53Tn) out of #8696 / PR #8875, which fixed the mysql arm and stopped at the mongodb arm on a declared file-surface breach rather than guessing. Filed unassigned and unlabelled for triage routing — packages/spec has exactly one owner and it is not the services lane. Not a claim.

Why the mongo arm cannot be finished where it lives

buildMongoUrl's DSN branch drops a bound external.credentialsRef, so a mongo datasource that binds a secret reaches MongoClient with an empty password (measured on origin/main). The remedy is known and cheap: MongoClient's auth option injects beside an unmodified url with no URL rewrite — measured, and it wins over an embedded userinfo password (mongodb 7.5.0).

The obstacle is not the injection. It is that auth requires a username as well as a password, and reading the url's userinfo username needs the platform's own DSN grammar:

  • new URL()rejects the multi-host form MongoConfigSchema documents — mongodb://app@h1:27017,h2:27017/app throws ERR_INVALID_URL (measured). This is precisely why @objectstack/spec/data owns urlUserinfoPassword / redactUrlPassword instead of using WHATWG parsing.
  • Those two export the password half of that grammar. There is no username half.

Why a local copy is refused rather than merely discouraged

Hand-rolling the username parse inside service-datasource is the shape #8082's ruling rejected by name:

a single value-level parse as the mechanism, precisely so no second copy exists to disagree with this one

A second copy of the userinfo boundaries would silently disagree with the publish door the day either one moves — and the publish door is what refuses user:password@ today. That is a worse defect than the one being fixed.

Options

shapecost
AAdd one additive pure helper urlUserinfoUsername beside the existing password half in packages/spec/src/data/driver/common.zod.ts, sharing its documented RFC-3986 boundaries and its existing alignment pin. The mongo arm then emits options.auth = { username, password: spec.secret }.A new export on @objectstack/spec/data — a public-surface addition. No Zod change, no authorable change, no acceptance change: every input that validates today validates identically after.
BSame fix, helper hand-rolled in service-datasource.A second copy of the userinfo boundaries — the shape #8082 rejects by name.
CRefuse loudly on the mongo DSN branch instead of injecting.Contradicts MongoConfigSchema.url's own declared text ("bind the secret … and it is injected at connect time"), so it needs a spec change and a ruling; rejects the exact shape #8155's landed remedy instructs operators to write; and leaves #8155's URL-bearing rows permanently non-migratable.

Recommendation: A, offered not chosen — it is the only option that keeps one parse for one grammar. B is refused on a standing ruling. C reverses a contract the spec already declares on all three URL-bearing SQL arms.

For triage

Related: #8696 (the parent card, mysql arm landed via PR #8875) · #8082 (the single-parse ruling) · #8155 (the consumer) · #8873 (the postgres arm is broken one layer lower and must not be fixed by symmetry).

Metadata

Metadata

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions