Skip to content

fix(vision): bind generated capabilities to provider transport - #581

Open
luvs01 wants to merge 3 commits into
devfrom
codex/propose-fix-for-vision-sidecar-vulnerability
Open

luvs01 wants to merge 3 commits into
devfrom
codex/propose-fix-for-vision-sidecar-vulnerability

Conversation

@luvs01

@luvs01 luvs01 commented Sep 21, 2026

Copy link
Copy Markdown
Owner

Motivation

  • A runtime change began consulting generated vendor capability metadata using only a provider name, which could misclassify same-named custom providers and cause images or adjacent text to be sent to an unrelated vision sidecar or be stripped before reaching the intended destination.

Description

  • Require the configured provider to match the registry transport before trusting generated vendor metadata by importing providerMatchesRegistryTransport and returning undefined (unknown) when the transport does not match in src/vision/eligibility.ts.
  • Preserve the legacy unknown-capability semantics for supported same-name custom destinations so images are not redirected or stripped when the adapter/baseUrl differ from the registry row.
  • Add a focused regression test tests/vision/vision-eligibility.test.ts that verifies a zhipu-bigmodel-responses custom preset does not inherit the vendor's text-only verdict and that requiresVisionPreprocessing remains permissive for the custom destination.
  • Update documentation in structure/runtime.md to state that registry/vendor metadata applies only when the configured adapter and destination still match the registry transport.

Testing

  • Ran the focused vision unit tests with ./node_modules/.bin/bun test tests/vision/vision-eligibility.test.ts which passed (23 tests, 0 failures) after switching to the repository-pinned Bun (1.4.0) when the system Bun lacked node:zlib exports.
  • Ran ./node_modules/.bin/bun run structure:check which passed and ./node_modules/.bin/bun run typecheck which completed successfully.
  • Verified git diff --check reported no whitespace issues and committed the change as fix(vision): bind metadata to provider transport.

Codex Task


Devin Review

devin-ai-integration Bot and others added 2 commits September 20, 2026 13:22
…forwarded role (lidge-jun#5334 follow-up)

lidge-jun#5334 made the developer wire role tri-state: an undeclared destination folds
it to system. Two suites asserting role:"developer" on the Chat wire were
missed because they are about tool-result repair ordering and document parts,
not role selection — declare the destination, per the convention the change
established.

Verified: both files fail on dev@600075d2 with system-for-developer wire roles
and pass with the declaration.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Sep 21, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Repository: luvs01/opencodex/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 9b7940cd-ea67-499c-a585-ccf09d3f8624


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 21, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-21T00:32:34.246145Z a2aadb7 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Sep 21, 2026
devin-ai-integration[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

…etadata alias

The transport guard added in a2aadb7 looked the provider name up as a
registry id only, so a provider saved under a canonical metadata alias
(gemini, anthropic-key, gemini-vertex, ...) failed the lookup and its
vendor metadata verdict was discarded — generated text-only models fell
back to unknown, bypassing vision preprocessing and picker exclusion.

providerMatchesRegistryTransportOrAlias resolves the name to the entry
that owns it (by id or declared extraMetadataAliases, case-folded like
resolveMetadataProvider) and validates the configured transport against
that entry, so an aliased row follows its owner's pinning rule.

Co-Authored-By: Epinephrine <luvs01@hanmail.net>
@devin-ai-integration

Copy link
Copy Markdown

Fixed in 3cb3d0a. Added providerMatchesRegistryTransportOrAlias in src/providers/registry.ts: resolves a configured name to its owning registry row — by id, or by extraMetadataAliases (geminigoogle, anthropic-keyanthropic, gemini-vertex, antigravity/gemini-antigravity) case-folded the way resolveMetadataProvider accepts saved keys — then validates the configured adapter/endpoint against that row. The eligibility guard now uses it, so an alias-named provider on the canonical transport keeps its metadata verdict (text-only gemini-live-2.5-flash-preview-native-audiofalse, sidecar required), while a same-named custom destination still returns undefined. Regression tests 11e (alias + text-only model, incl. case-folded Gemini) and 11f (alias-named custom destination parity) added in tests/vision/vision-eligibility.test.ts.

@devin-ai-integration

Copy link
Copy Markdown

Fixed in 3cb3d0a — same root cause. The guard now calls providerMatchesRegistryTransportOrAlias, which resolves metadata aliases to the registry entry that declares them (geminigoogle, etc.) before comparing transport, so the alias keeps the owner's verdict instead of falling to undefined. Covered by new tests 11e/11f (canonical alias with text-only generated model; same-named custom destination).

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

Devin Review

Comment thread src/providers/registry.ts
Comment on lines +134 to +139
const lower = name.toLowerCase();
const entry = getProviderRegistryEntry(name)
?? PROVIDER_REGISTRY.find(row =>
row.id.toLowerCase() === lower
|| (row.extraMetadataAliases ?? []).some(alias => alias.toLowerCase() === lower));
return entry !== undefined && providerMatchesRegistryTransport(entry.id, provider);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Metadata aliases still misclassify custom destinations

A custom gemini, anthropic-key, or case-varied provider is accepted through its metadata owner. Routing preserves that custom transport, so generated capabilities can still divert or strip its images.

Learn more

extraMetadataAliases feeds generated model metadata, but it is not a routing alias. The router looks up registry entries by the exact configured provider name in routedProviderConfig. Therefore, a configured provider named gemini keeps its own adapter and base URL, while this helper finds the google row and applies google's permissive transport rule. The same mismatch affects aliases such as anthropic-key and case-varied registry names.

Example: Configure gemini with adapter: "openai-chat" and baseUrl: "https://operator.example/v1". Routing sends requests to that endpoint unchanged. This helper resolves gemini to google, returns true because google does not set preserveCustomDestination, and a generated text-only verdict can send the image to a sidecar or strip it.

Recommended fix: For names that are not exact registry IDs, require the configured adapter, auth mode, and normalized endpoint to match the resolved alias owner directly. Do not reuse the owner's pinning rule, because routing does not canonicalize extraMetadataAliases. Add regression coverage for a custom alias-named destination and a case-varied custom provider.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread src/providers/registry.ts
Comment on lines +130 to +139
export function providerMatchesRegistryTransportOrAlias(
name: string,
provider: Pick<OcxProviderConfig, "baseUrl" | "adapter"> & Partial<Pick<OcxProviderConfig, "authMode">>,
): boolean {
const lower = name.toLowerCase();
const entry = getProviderRegistryEntry(name)
?? PROVIDER_REGISTRY.find(row =>
row.id.toLowerCase() === lower
|| (row.extraMetadataAliases ?? []).some(alias => alias.toLowerCase() === lower));
return entry !== undefined && providerMatchesRegistryTransport(entry.id, provider);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Description omits alias ownership expansion

The description promises adapter-and-destination matching. The implementation additionally treats metadata aliases and case-varied names as registry-owned, so the stated scope needs revision.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

aardvark bug Something isn't working codex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant