Skip to content

feat(providers): client-identity header profiles for compatible nodes - #5812

Merged
diegosouzapw merged 1 commit into
release/v3.8.44from
feat/port-pr-2255-client-identity-profiles
Jul 3, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.44from
feat/port-pr-2255-client-identity-profiles

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Summary

  • Adds a small catalog of named "client identity" header presets (Claude CLI, Codex CLI, Gemini CLI) for OpenAI-/Anthropic-compatible provider nodes, selectable from a new "Client Identity" dropdown in the compatible-provider creation modal.
  • Built entirely on top of the existing providerSpecificData.customHeaders pipeline (node → connection → DefaultExecutor.buildHeaders() → applyCustomHeaders()) — no parallel sanitizer, no new merge path, no new precedence logic. Auth headers already win over custom/identity headers because applyCustomHeaders() denylists auth header names and runs after the credential-auth headers are set.
  • Includes a small, independent hardening: cookie is now blocked from custom headers alongside authorization / x-api-key / x-goog-api-key / api-key, since a forwarded session cookie can hijack the upstream credential just as effectively as a forged auth header.

Attribution

Thanks to @nguyenha935 for the original implementation.

Changes

  • src/shared/constants/upstreamHeaders.ts: add cookie to FORBIDDEN_AUTH.
  • src/shared/validation/schemas/misc.ts: keep the customHeadersSchema error message in sync with the new denylist entry.
  • src/shared/constants/clientIdentityProfiles.ts (new): small catalog of 4 profiles (default, claude-cli, codex-cli, gemini-cli) with a pure getClientIdentityProfileHeaders() helper — no sanitization logic lives here, that stays in applyCustomHeaders().
  • src/app/(dashboard)/dashboard/providers/components/AddCompatibleProviderModal.tsx: adds a "Client Identity" <Select> in the advanced-settings section; on submit, the selected profile's headers are merged into the customHeaders field already accepted by POST /api/provider-nodes.
  • CHANGELOG.md: new-features bullet under [3.8.43].
  • i18n: providers.clientIdentityLabel / clientIdentityHint added to en.json and propagated to all 41 other locales as __MISSING__: placeholders (matching the project's own i18n:sync-ui convention), without staging the unrelated pre-existing translation drift a full sync run would otherwise pull in.

Scoped down from the original idea: no manual custom-header textarea, no "custom" profile option, and only one modal (AddCompatibleProviderModal) instead of all three compatible-provider modals — the node-level customHeaders field already propagates to every connection created under that node, so a single creation-time selector is enough to prove the feature end-to-end without duplicating UI/plumbing across modals.

Testing

  • node --import tsx/esm --test tests/unit/upstream-headers-sanitize.test.ts — TDD: isForbiddenCustomHeaderName("cookie") fails red before the fix, passes after.
  • node --import tsx/esm --test tests/unit/client-identity-profiles.test.ts — 9 new tests: profile headers land in customHeaders, survive applyCustomHeaders sanitization, a malicious profile-shaped header set (forged Authorization/x-api-key/cookie) is dropped, and DefaultExecutor.execute() actually sends the selected profile's headers over the wire for a compatible-node connection.
  • node --import tsx/esm --test tests/unit/db-models-crud.test.ts tests/unit/client-identity-profiles.test.ts tests/unit/upstream-headers-sanitize.test.ts tests/unit/modelscope-policy.test.ts tests/unit/provider-page-helpers-3501.test.ts tests/unit/custom-headers-provider-nodes.test.ts — 81/81 pass (no regressions in every suite that touches the shared denylist/customHeaders pipeline).
  • npm run typecheck:core — clean.
  • npx eslint <changed files> — clean.
  • npm run check:cycles — no cycles introduced.
  • npm run check:docs-sync — PASS.
  • node scripts/i18n/check-ui-keys-coverage.mjs --threshold=65 (the actual CI invocation) — PASS, all 41 locales above threshold.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces client identity header presets (such as Claude CLI, Codex CLI, and Gemini CLI) for compatible provider nodes, allowing operators to merge preset headers into custom headers. It also enhances security by blocking the cookie header in custom headers to prevent session hijacking. Comprehensive unit tests have been added to verify these changes. The review feedback suggests a performance optimization in AddCompatibleProviderModal.tsx to pass CLIENT_IDENTITY_PROFILE_OPTIONS directly to the Select component, avoiding redundant array mapping and object copying on every render.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

)}
<Select
label={t("clientIdentityLabel")}
options={CLIENT_IDENTITY_PROFILE_OPTIONS.map((option) => ({ ...option }))}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

There is no need to map and shallow copy each option object in CLIENT_IDENTITY_PROFILE_OPTIONS on every render. You can pass CLIENT_IDENTITY_PROFILE_OPTIONS directly to the options prop of the Select component to avoid redundant array and object allocations.

Suggested change
options={CLIENT_IDENTITY_PROFILE_OPTIONS.map((option) => ({ ...option }))}
options={CLIENT_IDENTITY_PROFILE_OPTIONS}

@diegosouzapw
diegosouzapw changed the base branch from release/v3.8.43 to release/v3.8.44 July 2, 2026 16:18
@diegosouzapw
diegosouzapw force-pushed the feat/port-pr-2255-client-identity-profiles branch from 4a62821 to 963034f Compare July 3, 2026 05:23
@diegosouzapw
diegosouzapw merged commit e12bbd3 into release/v3.8.44 Jul 3, 2026
2 of 3 checks passed
@diegosouzapw
diegosouzapw deleted the feat/port-pr-2255-client-identity-profiles branch July 3, 2026 05:23
@diegosouzapw diegosouzapw mentioned this pull request Jul 4, 2026
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
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.

1 participant