fix(anthropic): wire buildGuardedModelFetch into the Cloudflare createClient branch#98003
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 3, 2026, 6:13 AM ET / 10:13 UTC. Summary PR surface: Source +2, Tests +63. Total +65 across 3 files. Reproducibility: yes. from source: current main constructs the Cloudflare Anthropic client without a custom fetch, and the PR test demonstrates the missing guard by blocking a private-IP base URL before global fetch is reached. I did not run tests in this read-only review checkout. Review metrics: 1 noteworthy metric.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the narrow Cloudflare constructor parity fix once a maintainer accepts the intentional guarded-transport compatibility risk and normal merge/check gating is satisfied. Do we have a high-confidence way to reproduce the issue? Yes from source: current main constructs the Cloudflare Anthropic client without a custom fetch, and the PR test demonstrates the missing guard by blocking a private-IP base URL before global fetch is reached. I did not run tests in this read-only review checkout. Is this the best way to solve the issue? Yes, this is the best narrow fix for the reported gap: the Anthropic SDK exposes a constructor AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 6b869a618856. Label changesLabel justifications:
Evidence reviewedPR surface: Source +2, Tests +63. Total +65 across 3 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
0b924d0 to
099a584
Compare
099a584 to
c22001f
Compare
|
@altaywtf Thanks for running the hosted Anthropic smoke. I don't have access to a live Cloudflare AI Gateway account or gateway secrets, so I can't generate the dashboard evidence you asked for on my own. Could you (or another maintainer with Cloudflare AI Gateway credentials / Testbox provisioning rights) either:
If neither is available, please let me know if the current loopback/SSRF-block proof plus your hosted Anthropic smoke should be accepted as the practical coverage ceiling for this S-sized wiring PR. I'll update the PR body to reflect whatever decision. |
|
Thanks for confirming. I want to be pretty direct here: if you do not have access to a real Cloudflare AI Gateway setup, please do not expand this PR with large synthetic “proof” blocks to compensate for that missing coverage. 😅 The actual code change is small and reasonable: wiring
The 188-line loopback test and large PR-body proof section make the PR harder to review without proving the thing I asked about: a real Cloudflare AI Gateway-routed request with dashboard/log evidence. A local fake SSE server is not Cloudflare Gateway coverage. Please either:
I’m not asking for more synthetic proof here. The concern is reviewability and signal, not line count. Thanks for your understanding. |
|
@altaywtf Thanks for the direct feedback. I have trimmed the PR down:
CI is green on the trimmed branch. Please let me know if this matches the review signal you want, or if anything else is needed. |
89a1828 to
348a191
Compare
|
@clawsweeper re-review Trimmed the proof per maintainer feedback:
CI is now green on the latest HEAD. |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
I created a Cloudflare AI Gateway myself and ran a maintainer-side live proof against this PR head. That fills the Cloudflare-routed coverage gap we discussed earlier. Findings, with secrets/account details redacted:
So the current small patch now has the missing real Cloudflare AI Gateway behavior proof: the Cloudflare Anthropic constructor path works with 🤖 AI-assisted via Codex, GPT-5.5, high reasoning |
Wire the Cloudflare AI Gateway Anthropic SDK client through buildGuardedModelFetch so this path gets the same SSRF and transport policy as sibling providers. Keep the behavior proof focused on the regression: a Cloudflare Anthropic request pointed at a link-local address must fail before the SDK reaches global fetch.
…thetic loopback server
348a191 to
c83252d
Compare
|
Thanks @altaywtf for taking the time to provision a real Cloudflare AI Gateway and run the maintainer-side live proof. That closes the only proof gap that was missing from the contributor side, and the redacted dashboard/log evidence (provider=cloudflare-ai-gateway, api=anthropic-messages, model=claude-sonnet-4-6, HTTP 200 text/event-stream, stopReason=stop) is exactly the Cloudflare-routed coverage this PR needed. This PR is now fully proven on the live path:
I will not expand this PR further. The "What was not tested" gap is now closed by your live run rather than by extra contributor-side synthetic tests, which is the cleaner outcome for reviewability. Ready for merge at maintainer discretion. |
|
Merged via squash.
|
…eClient branch (openclaw#98003) * fix(anthropic): guard Cloudflare Anthropic fetches Wire the Cloudflare AI Gateway Anthropic SDK client through buildGuardedModelFetch so this path gets the same SSRF and transport policy as sibling providers. Keep the behavior proof focused on the regression: a Cloudflare Anthropic request pointed at a link-local address must fail before the SDK reaches global fetch. * fix(anthropic): add loopback proof test to cloudflare fetch wiring * test(anthropic-cloudflare): trim proof to SSRF-block only, remove synthetic loopback server
…ient branch Reopens openclaw#98014 after packages/ai extraction (openclaw#99059) moved anthropic.ts out of src/llm/providers. Adds a single fetch line to the github-copilot createClient branch, parallel to the cloudflare branch wired by openclaw#98003 and the same-shape api-key/oauth/foundry siblings landing in this series. Bytes-cap verification is owned by buildModelFetch itself; this PR proves the constructor wiring via inline test through production streamAnthropic.
…ient branch Reopens openclaw#98014 after packages/ai extraction (openclaw#99059) moved anthropic.ts out of src/llm/providers. Adds a single fetch line to the github-copilot createClient branch, parallel to the cloudflare branch wired by openclaw#98003 and the same-shape api-key/oauth/foundry siblings landing in this series. Bytes-cap verification is owned by buildModelFetch itself; this PR proves the constructor wiring via inline test through production streamAnthropic.
…ient branch Reopens openclaw#98014 after packages/ai extraction (openclaw#99059) moved anthropic.ts out of src/llm/providers. Adds a single fetch line to the github-copilot createClient branch, parallel to the cloudflare branch wired by openclaw#98003 and the same-shape api-key/oauth/foundry siblings landing in this series. Bytes-cap verification is owned by buildModelFetch itself; this PR proves the constructor wiring via inline test through production streamAnthropic.
…ient branch Reopens openclaw#98014 after packages/ai extraction (openclaw#99059) moved anthropic.ts out of src/llm/providers. Adds a single fetch line to the github-copilot createClient branch, parallel to the cloudflare branch wired by openclaw#98003 and the same-shape api-key/oauth/foundry siblings landing in this series. Bytes-cap verification is owned by buildModelFetch itself; this PR proves the constructor wiring via inline test through production streamAnthropic.
What Problem This Solves
The Anthropic provider (
anthropic.ts) creates fiveAnthropicSDK clients — one for Cloudflare AI Gateway, one for GitHub Copilot, one for Microsoft Foundry bearer auth, one for OAuth, and one for the API-key fallback. None of them passed a customfetchoption. Streaming Anthropic calls from these providers bypassed the guarded provider transport — SSRF protection, request timeout, retry-hint injection, and response lifecycle management that every other Anthropic SDK path already has.This PR injects
fetch: buildGuardedModelFetch(model)into the Cloudflare AI Gateway SDK constructor specifically, bringing that branch to guarded-fetch parity with:anthropic-transport-stream.ts:788(managed Anthropic transport)openai-responses.ts(fix(openai-responses): bound SSE response reads via buildGuardedModelFetch #97848)openai-completions.ts(fix(openai-completions): bound SSE response reads via buildGuardedModelFetch #97228)azure-openai-responses.tsThis is one of five split PRs that supersede #97868.
Why This Change Was Made
buildGuardedModelFetchis the canonical fetch wrapper applied to every Anthropic SDK constructor in the codebase. The Anthropic SDK acceptsfetch?: Fetchper its constructor options. The Cloudflare branch was missing this wrapper.The change is 2 lines in production code (
+1 import, +1 fetch:option). The proof is focused on showing the guard is actually in scope and active:anthropic.test.ts.globalThis.fetchand proves the guard intercepts a private IP before the SDK reaches the default fetch.Evidence
Results:
Layer 1: Constructor wiring
anthropic.test.tsasserts the Cloudflare branch config now includes afetch:function.Layer 2: SSRF-block guard-specific proof
anthropic-cloudflare.fetch-proof.test.tsstubsglobalThis.fetchas a call counter, configuresbaseUrl: http://169.254.169.254/v1, and assertsglobalFetchCalled === 0. This provesbuildGuardedModelFetchintercepts the blocked target before the SDK falls back toglobalThis.fetch.Maintainer-hosted smoke
@altaywtf ran a hosted live smoke against the fixed
cloudflare-ai-gatewayAnthropic constructor branch using a real Anthropic API request; that passed.Real behavior proof
createClientinsrc/llm/providers/anthropic.ts(Cloudflare branch) now passesfetch: buildGuardedModelFetch(model)tonew Anthropic({...}), so Anthropic calls routed through the Cloudflare AI Gateway inherit OpenClaw guarded-fetch policy.fetch, and the guard rejects169.254.169.254before any network call.CLOUDFLARE_AI_GATEWAY_*account or gateway secrets). Maintainer-hosted smoke validated the constructor branch against a real Anthropic endpoint.Diff scope
anthropic.tsSecurity & Privacy
fetchoption; no monkey-patching.Compatibility
Related
AI disclosure
AI-assisted (Claude); reviewed by human author before submission.