Skip to content

fix(providers): hidden models leak into GET /v1/models (#11300) - #11309

Merged
diegosouzapw merged 1 commit into
release/v3.8.50from
fix/11300-hidden-models-leak-v1-models
Aug 24, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.50from
fix/11300-hidden-models-leak-v1-models

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Summary

  • PATCH /api/provider-models?provider=<key>&modelId=<id> (the eye-toggle on a
    provider's dashboard page) persists the isHidden override under whatever
    key the page's [id] route param happened to be — an alias (cc/gh/cx/
    ag/xao), a canonical provider id, a compatible-provider node UUID, or its
    configured prefix.
  • catalog.ts's isModelHiddenBulk() only did a single-key lookup, so a
    hidden model stayed listed in GET /v1/models whenever the write key and a
    given catalog loop's read key diverged (static PROVIDER_MODELS loop only
    checked canonicalProviderId; the Codex-native-unprefixed loop only checked
    "codex"; the synced-discovery loop only checked the raw connection
    providerId, missing a hide keyed by the node's configured prefix).
  • isModelHiddenBulk is now multi-key aware: given a provider key and an
    optional already-resolved canonical id, it checks the raw key, its resolved
    canonical provider id, that canonical id's alias, and the
    compatible-provider-node prefix for either. Updated every catalog loop call
    site to pass along whichever raw/canonical pair it already has in scope.

Closes #11300

Test plan

TDD (Hard Rule #18) — tests/unit/hidden-models-leak-v1-models-11300.test.ts,
3 cases, each independently confirmed RED against the pre-fix code and GREEN
after the fix:

  • A: static model hidden under its alias (cc) stays excluded under both
    cc/ and claude/ ids
  • B: Codex-native unprefixed model hidden via the openai provider page
    excludes the bare model id
  • C: compatible-node synced model hidden under its configured prefix
    excludes prefix/<model>
  • Sibling regressions green: synced-model-hide-persist-3782,
    model-catalog-policy-invalidation-8728,
    specialty-model-hidden-openrouter-9293, 8327-models-owned-by-prefix,
    8958-alias-backed-node-prefix, 9034-alias-backed-prefix-id-repro
    (18/18), plus a 104-file catalog/hidden/alias sibling batch (604/605 —
    the one failure, 9147-catalog-eventloop-yield, is a pre-existing
    devbox-load timing flake reproduced identically on the unmodified base
    code under the same contention, not a regression from this change)
  • npm run typecheck:core clean
  • eslint (with the project's suppressions) clean on both changed files

⚠️ base-red inherited: #9985

The visibility toggle on a provider's dashboard page (PATCH
/api/provider-models) persists the hidden-model override under whatever key
the page's [id] route param happened to be — an alias (cc/gh/cx/ag/xao), a
canonical provider id, a compatible-provider node UUID, or its configured
prefix. catalog.ts's isModelHiddenBulk() only ever did a single-key lookup,
so a hidden model stayed listed in GET /v1/models whenever the write key and
the loop's read key diverged.

Make isModelHiddenBulk multi-key aware: given a provider key and an optional
already-resolved canonical id, it now checks the raw key, its canonical
provider id, that canonical id's alias, and the compatible-provider-node
prefix for either — covering every key the dashboard could plausibly have
written under. Updated every catalog loop call site (static PROVIDER_MODELS,
Codex-native-unprefixed, synced-discovery, custom models, alias-backed
models, managed-fallback) to pass along whichever raw/canonical pair it
already has in scope.
@jonlwheat2-gif

Copy link
Copy Markdown
Contributor

Independent fix for #11300 over in #11308 — same root-cause diagnosis and an overlapping catalog change, so flagging two functional differences before these collide on the isModelHiddenBulk region (they will conflict as-is):

1. getModelIsHidden() is still exact-key after this PR.
src/lib/db/apiKeys.ts:1541 uses it for per-key public-model filtering (allowedModels / isPublic), and the combo picker path reads it too — so a hide stored under a non-identical key still leaks outside /v1/models: a key-scoped consumer keeps seeing the model as available. #11308 rewrites it to walk the same equivalence set (src/lib/db/models.ts:966-981 post-fix).

2. Connection-family aliases aren't resolved here.
buildAliasMaps() only carries the dashboard .alias field, but hides can be saved under PROVIDER_CONNECTION_FAMILY_ALIASES keys — concretely xai ↔ xao / xai-oauth, and magnific ↔ freepik. This is not hypothetical: reproduced as a failing test pre-fix (hide stored under xao, queried as xai → model still listed). #11308 covers it by adding getProviderConnectionFamilyIds(canonical) to the key set.

Everything else in this PR — explicit canonicalProviderId at the static/synced/custom call sites, the codex-native openai check — is functionally equivalent to #11308's approach (mine derives canonical inside the helper and keeps call sites zero-diff; same coverage).

Happy to rebase #11308 onto this branch — keeping this PR's catalog shape and its integration-style test, adding the db-layer piece and family-alias coverage on top — or fold those two pieces into this PR directly if that's easier on your side. The two test suites compose fine: model-hide-multikey-11300.test.ts (unit seam, 7 cases incl. the xao RED case) alongside the integration test here.

@diegosouzapw
diegosouzapw merged commit 07d1816 into release/v3.8.50 Aug 24, 2026
20 of 22 checks passed
@diegosouzapw
diegosouzapw deleted the fix/11300-hidden-models-leak-v1-models branch August 25, 2026 02:36
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…11300) (diegosouzapw#11309)

Merging --admin: only fails are ESLint warnings ratchet drift (inherited) and dast-smoke (advisory, isRequired:null). Zero overlap with this PR's file scope (src/app/api/v1/models/catalog.ts).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Models toggled to 'Hidden' on Provider pages are still listed in GET /v1/models

3 participants