feat(providers): client-identity header profiles for compatible nodes - #5812
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
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 }))} |
There was a problem hiding this comment.
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.
| options={CLIENT_IDENTITY_PROFILE_OPTIONS.map((option) => ({ ...option }))} | |
| options={CLIENT_IDENTITY_PROFILE_OPTIONS} |
… (re-cut) + forbid cookie in custom headers
4a62821 to
963034f
Compare
… (re-cut) + forbid cookie in custom headers (diegosouzapw#5812)
Summary
providerSpecificData.customHeaderspipeline (node → connection →DefaultExecutor.buildHeaders()→applyCustomHeaders()) — no parallel sanitizer, no new merge path, no new precedence logic. Auth headers already win over custom/identity headers becauseapplyCustomHeaders()denylists auth header names and runs after the credential-auth headers are set.cookieis now blocked from custom headers alongsideauthorization/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: addcookietoFORBIDDEN_AUTH.src/shared/validation/schemas/misc.ts: keep thecustomHeadersSchemaerror 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 puregetClientIdentityProfileHeaders()helper — no sanitization logic lives here, that stays inapplyCustomHeaders().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 thecustomHeadersfield already accepted byPOST /api/provider-nodes.CHANGELOG.md: new-features bullet under[3.8.43].providers.clientIdentityLabel/clientIdentityHintadded toen.jsonand propagated to all 41 other locales as__MISSING__:placeholders (matching the project's owni18n:sync-uiconvention), 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-levelcustomHeadersfield 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 incustomHeaders, surviveapplyCustomHeaderssanitization, a malicious profile-shaped header set (forgedAuthorization/x-api-key/cookie) is dropped, andDefaultExecutor.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.