fix(orchestrator): gateway mode leaked raw provider key to opencode sub-agents via OPENCODE_CONFIG_CONTENT - #11850
Conversation
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
…ub-agents via OPENCODE_CONFIG_CONTENT gateway mode (86bc107, #11651) promised a child env dump contains no raw provider key, but an opencode spawn broke the invariant twice over: buildOpencodeSpawnConfig embedded the raw cerebras/opencode/cloud key as provider options.apiKey inside the JSON assigned to env.OPENCODE_CONFIG_CONTENT, and applyModelGatewayEnv — which runs after and deletes only the seven named env keys — never touched it. the child env carried the raw key AND the opencode child pointed its baseURL straight at api.cerebras.ai / eliza cloud, bypassing the gateway. - buildOpencodeSpawnConfig checks resolveModelGatewayConfig() first, before any credential read (env, runtime settings, or config-env — setting() falls back to all three, so env-key deletion alone could never fix this). in gateway mode it returns a gateway-pointed openai-compatible provider config: nothing raw to leak, and the child routes through the gateway instead of bypassing it. - applyModelGatewayEnv enforces the stated invariant literally: raw values captured from the named keys are swept out of every remaining env value, so a composite carrier (a JSON blob like OPENCODE_CONFIG_CONTENT) that still embeds a raw key is dropped whole. fail-closed backstop for future merge steps. off-mode behavior is byte-identical; a new off-mode test pins the legacy direct-cerebras wiring. model-gateway-env.test.ts now exercises agentType opencode — the untested gap that hid this.
3f6f49a to
b49fb99
Compare
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Gateway mode leaked the raw provider key to opencode sub-agents (and opencode bypassed the gateway)
Defect
86bc107 (#11651, gateway mode for #11536 E2) states the invariant: with
ELIZA_MODEL_GATEWAY_URL+ELIZA_MODEL_GATEWAY_TOKENset, a child env dump contains no raw provider key. AnagentType: "opencode"spawn broke that invariant twice over:AcpService.buildEnv's opencode block callsbuildOpencodeAcpEnv→buildOpencodeSpawnConfig(opencode-config.ts), which embeds the rawCEREBRAS_API_KEY/ELIZA_OPENCODE_API_KEY/ Eliza Cloud key asprovider.*.options.apiKeyinside the JSON assigned toenv.OPENCODE_CONFIG_CONTENT.applyModelGatewayEnv(model-gateway.ts) runs after it and deletes only the seven named env keys — it never touchesOPENCODE_CONFIG_CONTENT— so the raw key rides into the child env inside the JSON blob.baseURLstraight atapi.cerebras.ai/ Eliza Cloud, so its model traffic skips the gateway entirely.Deleting the key env vars earlier would not have fixed this:
opencode-config'ssetting()falls back to runtime settings and config-env, so the key gets embedded regardless of env deletion order (multi-account pool rotation also injectsCEREBRAS_API_KEYfor opencode through this same read).model-gateway-env.test.tsonly exercisedagentType: "claude" | "codex", which is why the gap was invisible.Fix (structural)
buildOpencodeSpawnConfigchecksresolveModelGatewayConfig()FIRST — before any credential read from any source. In gateway mode it returns a gateway-pointed@ai-sdk/openai-compatibleprovider config (baseURL= gateway URL,apiKey= gateway token): there is nothing raw to leak, and the opencode child's traffic goes through the gateway — the same transport contractOPENAI_BASE_URL/ANTHROPIC_BASE_URLgives the codex/claude children. Provider auto-detection and custom base URLs are deliberately ignored in gateway mode (gateway centralizes egress); model names pass through unchanged, defaulting to the same chain the direct cerebras-api path uses.applyModelGatewayEnvnow enforces the stated invariant literally: raw values captured from the named keys are swept out of every remaining env value, so any composite carrier (a JSON blob likeOPENCODE_CONFIG_CONTENT) that still embeds a raw key is dropped whole. Fail-closed backstop for future merge steps; the opencode path never trips it now that the config is gateway-built.Off-mode behavior is byte-identical: the gateway branch is dead code when either var is unset, and a new off-mode spawn test pins the legacy direct-cerebras wiring (raw key embedded, no gateway URLs) exactly as before.
Evidence
Defect re-confirmed — new tests against the previous code (7 fail):
After the fix (same two files):
Full plugin suite + typecheck + lint:
New coverage:
model-gateway-env.test.tsnow spawnsagentType: "opencode"in gateway ON (gateway-routedOPENCODE_CONFIG_CONTENT, no raw key anywhere in the env dump including composite values) and OFF (legacy wiring pinned byte-identical) modes, plus the composite-value sweep;opencode-spawn-config-auto-detect.test.tscovers the gateway branch directly (raw env key, runtime-settings key, custom-base-URL bypass attempt, keyless host, model pass-through, single-var-off) and is now hermetic against host gateway vars.