Skip to content

feat(spec): refuse bound external.credentialsRef with a user-less mongo config.url at publish (#9041) - #9146

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-9041-credentialsref-url-no-user-refusal
Aug 16, 2026
Merged

feat(spec): refuse bound external.credentialsRef with a user-less mongo config.url at publish (#9041)#9146
os-zhuang merged 2 commits into
mainfrom
claude/issue-9041-credentialsref-url-no-user-refusal

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#9041

What

Refuses, at the authoring/publish door, the contradictory pair "external.credentialsRef bound + a mongo config.url whose userinfo names NO user" — a configuration that cannot work as written. Premise re-verified on the post-#9123 tree: buildMongoAuth in the driver factory injects the bound secret only when urlUserinfoUsername(url) names a user (MongoClient auth needs a username the URL must supply), so on a user-less URL the binding is a silent no-op — the datasource connects anonymously and the operator is told nothing. The factory's own #8696 comment defers the loud half to this door by name.

Where — the seam that sees both halves

DatasourceSchema's existing superRefine in packages/spec/src/data/datasource.zod.ts — the card measured this cannot be a MongoConfigSchema.superRefine (credentialsRef sits on the datasource, url inside config), and the datasource-level refinement is the one place in packages/spec both halves are visible at once (no fork: the PM's assumed seam exists on today's tree).

Fences (triage, adopted verbatim)

Composition (PM-mechanism pins)

Envelope

Per the sibling refusals' documented pattern (#8082/#9040 pins in the same test file): the zod issue's code: 'custom' + pathed location are the whole envelope at this layer; the publish door wraps every schema refusal uniformly as 422 INVALID_METADATA with these issues carried verbatim.

Breaking + ADR-0087

Accept-set narrowing shipped as @objectstack/spec minor with BREAKING annotation, matching the #8337/#9123 sibling convention (a stored row carrying a vestigial binding over a working anonymous connection now refuses — a real accept-set flip, not only dead configs). Semantic migration entry datasource-credentialsref-mongo-url-no-user-refused registered under major 18 (registry regenerated via gen:migration-registry); no mechanical rewrite is possible because the two fixes are contradictory intents (authenticate vs anonymous).

Consumer fixture sweep

Swept every file binding credentialsRef across packages/examples/content/skills: no fixture pairs it with a user-less mongo URL (service-datasource's bound-secret-dsn-branches.test.ts builds connection specs directly, below this schema; the #8155 migration keeps the username in the URL by prescription; the showcase example's credentialsRef is commented out and postgres). Zero flips expected, and the full spec suite confirms.

Verification (all at d4fbe7352, the head commit)

  • Full @objectstack/spec suite: 406 files / 10797 tests passed (includes the new describe block, 13 new cases).
  • Reverse verification, direction decided up front as red-on-ablation: with the refinement removed (fix committed first, ablation via script, restore via git checkout from the branch), the refusal test file went 4 failed / 129 passed — exactly the four refusal-asserting cases; accept pins stayed green. Restored and re-ran: 181/181 green. Vitest runs from src, so no dist rebuild was involved in the ablation loop (not a dogfood dist/ ablation).
  • pnpm --filter @objectstack/spec check:generated: all 13 artifacts up to date after rebuild (an earlier api-surface "stale" was the stale-dist phantom; rebuilt, clean, zero artifact diffs beyond the regenerated migration registry).
  • pnpm --filter @objectstack/spec typecheck green; check:type-check-coverage + check:type-check-debt --re-measure green (no surplus).
  • Diff-derived gates (node scripts/pm/dispatch-gates.mjs over the 5 changed paths), all green: check:changeset-gate-self-tests, check:cross-package-test-inputs (both spellings), check:doc-formula-expressions (after building the lint closure), check:merge-driver, check:objectui-changeset, check:spec-parsed-alias, check:type-source-resolution, check-adr-0087-registration (BREAKING changeset carries registered datasource-credentialsref-mongo-url-no-user-refused), check-changeset-no-major, check-empty-changeset, check-dev-prereqs (after full package build), plus the test-file convention gates check:query-options-erasure, check:engine-double-contract, check:where-matcher and check:nul-bytes.
  • Example apps validate (crm / showcase / todo): green (pre-existing warnings only).

Generated by Claude Code


Generated by Claude Code

…go config.url at publish (#9041)
The binding is a silent no-op at connect (MongoClient auth needs a username
the URL must supply; injecting a fabricated empty one is a measured handshake
failure), so the contradictory pair is refused at the datasource level — the
one door that sees both halves. Fences per triage: mongodb arm only (legacy
'mongo' alias-resolved), urlUserinfoUsername undefined only, message names
both fixes prescribing neither. ADR-0087 semantic entry + registry regen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01225pUjnCKWqxcc1PeqKFUq
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

106 hand-written doc(s) reference the affected code — list omitted above 15 rows. Re-derive: node scripts/docs-audit/affected-docs.mjs --json origin/main.

7 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang marked this pull request as ready for review August 16, 2026 14:52
@os-zhuang
os-zhuang added this pull request to the merge queueAug 16, 2026
Merged via the queue into main with commit d491625Aug 16, 2026
27 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-9041-credentialsref-url-no-user-refusal branch August 16, 2026 15:09
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:datasize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nothing refuses the contradictory pair "external.credentialsRef bound + a config.url naming no user" — the binding is a silent no-op at connect

2 participants

@os-zhuang@claude