Skip to content

feat(claude): restore configurable OAuth billing entrypoint - #7

Merged
TechNickAI merged 3 commits into
release/v3.8.50from
nick/restore-claude-entrypoint
Aug 3, 2026
Merged

TechNickAI merged 3 commits into
release/v3.8.50from
nick/restore-claude-entrypoint

Conversation

@TechNickAI

Copy link
Copy Markdown
Owner

Restores the fork's core CLAUDE_CC_ENTRYPOINT patch on the current release/v3.8.50 line.\n\n- keeps cc_entrypoint and Claude CLI User-Agent suffix aligned\n- supports cli and sdk-cli, defaulting safely to cli\n- covers executor, identity bootstrap, and OAuth provider paths\n- restores the existing unit test and env documentation\n\nProduction currently sets CLAUDE_CC_ENTRYPOINT=sdk-cli, but its deployed standalone bundle does not contain this patch, so that setting is currently inert. This PR restores the code required for the setting to work in the next verified deployment.

…RYPOINT

Anthropic meters `cli`-labelled third-party OAuth traffic against the account's extra-usage balance ("You're out of extra usage" 400s), while the Agent SDK entrypoint (`sdk-cli`) counts as plan usage. This affects even the official Claude Code (anthropics/claude-code#45203).

Add an opt-in `CLAUDE_CC_ENTRYPOINT` env var (`cli`|`sdk-cli`, default `cli` — no behavior change), routed through one helper that sets both the `cc_entrypoint` field of `x-anthropic-billing-header` and the matching `(external, <entrypoint>)` claude-cli User-Agent suffix together, across all native Claude OAuth sites (executor, identity bootstrap, oauth provider). Same wire image the CC-Compatible provider already uses.

Only the native Claude OAuth path is affected; API-key requests are unchanged. Adds unit tests (default / sdk-cli / explicit-cli / whitespace / invalid-fallback).

(cherry picked from commit fe2eb72)
(cherry picked from commit 7cc2066)
Comment thread open-sse/config/anthropicHeaders.ts

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 076acd9c83

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread open-sse/config/anthropicHeaders.ts Outdated
return getClaudeCodeUserAgent(getClaudeEntrypoint());
}

export const CLAUDE_CLI_USER_AGENT = claudeCliUserAgent();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep static Claude headers on the CLI entrypoint

When CLAUDE_CC_ENTRYPOINT=sdk-cli, this module-level constant also changes getClaudeCliHeaders() in open-sse/config/providers/shared.ts, which the Claude registry snapshots for every connection. Consequently, a native Claude API-key request that does not enter the OAuth/Claude-Code cloak still sends the sdk-cli User-Agent, despite the new setting being documented as OAuth-only and API-key requests being explicitly described as unaffected. Keep this static registry identity on cli and use the dynamic helper only in the OAuth-specific request paths.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Triage complete against current main. The version-parameter concern is fixed; two OAuth header-scope/override defects remain and need a focused follow-up. — automated pr-review-sweep

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Valid catch. Fixed in PR #9: CLAUDE_CLI_USER_AGENT is now a hardcoded literal claude-cli/${CLAUDE_CLI_VERSION} (external, cli) — it no longer calls claudeCliUserAgent() at module load, so CLAUDE_CC_ENTRYPOINT=sdk-cli cannot leak into API-key connection headers via getClaudeCliHeaders(). The dynamic helper is only called at native OAuth call sites in base.ts.

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e91eb8d. Configure here.

Comment thread open-sse/executors/base.ts
@TechNickAI
TechNickAI merged commit 53a6311 into release/v3.8.50 Aug 3, 2026
7 of 14 checks passed
@TechNickAI
TechNickAI deleted the nick/restore-claude-entrypoint branch August 3, 2026 22:02
TechNickAI pushed a commit that referenced this pull request Aug 12, 2026
… t06 gate (diegosouzapw#9779)

The release-green verdict (diegosouzapw#9737) lists check:route-validation:t06 as a HARD
failure and it is STILL red on the current tip: four routes call
request.json() and hand-roll `typeof x === "string"` checks instead of using
Zod, which Hard Rule #7 requires and the gate enforces (it scans source and
has no allowlist).

- src/app/api/plugins/marketplace/install (diegosouzapw#9445): InstallBodySchema; the
  400 'Missing or invalid name field' response is preserved verbatim.
- src/app/api/services/dario/admin/accounts (diegosouzapw#8523): DeleteAccountBodySchema
  for the optional { alias } DELETE body; query-param path untouched.
- src/app/api/services/dario/admin/login-start (diegosouzapw#8523): LoginStartBodySchema;
  trimming now happens in the schema, so the forward body is unchanged.
- src/app/api/services/dario/admin/import-from-omniroute (diegosouzapw#8523):
  ImportBodySchema for connectionId/alias; invalid shapes fall back to the
  same 'connectionId is required' 400 as before.

All four keep their exact status codes and messages — this is a validation
mechanism swap, not a contract change (plugins route suite still 33/33).

Adds tests/unit/route-body-validation-t06.test.ts, which runs the gate's own
rule inside the unit suite so the next such route fails on ITS OWN PR instead
of surfacing weeks later in a base-red sweep. Guard verified by mutation:
renaming .safeParse( in one route makes it fail (1 fail), restored from a
pre-probe copy.

Gates: route-validation:t06, file-size, test-discovery, mutation-test-coverage,
dead-code exit 0; typecheck:core clean; eslint clean.

Refs diegosouzapw#9737

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
TechNickAI pushed a commit that referenced this pull request Aug 12, 2026
…e — every handler 500'd (diegosouzapw#9737) (diegosouzapw#9785)

* fix(api): validate request bodies with Zod in 4 routes — restores the t06 gate

The release-green verdict (diegosouzapw#9737) lists check:route-validation:t06 as a HARD
failure and it is STILL red on the current tip: four routes call
request.json() and hand-roll `typeof x === "string"` checks instead of using
Zod, which Hard Rule #7 requires and the gate enforces (it scans source and
has no allowlist).

- src/app/api/plugins/marketplace/install (diegosouzapw#9445): InstallBodySchema; the
  400 'Missing or invalid name field' response is preserved verbatim.
- src/app/api/services/dario/admin/accounts (diegosouzapw#8523): DeleteAccountBodySchema
  for the optional { alias } DELETE body; query-param path untouched.
- src/app/api/services/dario/admin/login-start (diegosouzapw#8523): LoginStartBodySchema;
  trimming now happens in the schema, so the forward body is unchanged.
- src/app/api/services/dario/admin/import-from-omniroute (diegosouzapw#8523):
  ImportBodySchema for connectionId/alias; invalid shapes fall back to the
  same 'connectionId is required' 400 as before.

All four keep their exact status codes and messages — this is a validation
mechanism swap, not a contract change (plugins route suite still 33/33).

Adds tests/unit/route-body-validation-t06.test.ts, which runs the gate's own
rule inside the unit suite so the next such route fails on ITS OWN PR instead
of surfacing weeks later in a base-red sweep. Guard verified by mutation:
renaming .safeParse( in one route makes it fail (1 fail), restored from a
pre-probe copy.

Gates: route-validation:t06, file-size, test-discovery, mutation-test-coverage,
dead-code exit 0; typecheck:core clean; eslint clean.

Refs diegosouzapw#9737

* fix(memory): register the sqlite backend on the /api/memory/[id] route — every handler 500'd

GET/PUT/DELETE /api/memory/[id] threw `Primary backend "sqlite" not
registered` and returned 500. diegosouzapw#8752 (MemoryBackend provider pattern) wired the
route to `@/lib/memory/manager` directly, but the registry is populated by an
import-time side effect in the module INDEX (src/lib/memory/index.ts:23,
`memoryManager.register(sqliteBackend)`). Importing the bare manager gives an
empty registry.

In production the failure is order-dependent, which is why it went unnoticed:
if /api/memory (which imports the index) is hit first in the same process, the
singleton is already populated and [id] works. Reached first — the common case
for a client that edits a known memory id — every request 500s. The sibling
route is the only other consumer and already imports the index; this was the
lone direct-manager import in src/.

- Fix: import from `@/lib/memory` (index) with a comment stating WHY the
  indirection matters, so the next refactor does not simplify it back.
- Guard: tests/integration/memory-route-put.test.ts already covered this and
  was failing 2/5 on the base (it only surfaced now because the integration
  suite runs on the release-PR CI, not per-PR). Now 5/5.

Also fixes a test-isolation defect in the same run:
tests/integration/combo-matrix/context-relay-codex.test.ts reused one combo
name across both tests, and the control failed with `UNIQUE constraint failed:
combos.name` — resetStorage() unlinks the DB file but the previous
better-sqlite3 handle keeps writing to the same inode. Gave the control its own
combo name and parameterized the request builder; the assertion is unchanged
(it never depended on the name). 2/2.

Integration suite on this tip: 936 tests, 32m19s — under the 40min ceiling the
old verdict reported as exceeded (diegosouzapw#9737 item 6), which the migration-135
collision was causing.

Refs diegosouzapw#9737

---------

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
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