Repository navigation
[PR] fix: stop leaking x-bili-plugin* host headers to the model endpoint (#3905) - #3915
ranxianglei wants to merge 2 commits into
Conversation
…3905) The main HTTP forward path copied every inbound header to the upstream except content-length/host, so all host-private x-bili-plugin* convention headers (agent marker, conversation id, window/model declarations, and the declared- tools channel from #3906/#3907) rode through to the model provider. Add stripBiliPluginHeaders (src/server/headers.ts) and apply it at both outbound model-endpoint derivations: the HTTP forward choke point (buildForwardTarget, which every retry/refetch reuses) and the WS lane final egress (finalizeResponsesWsUpstreamHeaders, non-Azure). The Azure WS branch keeps stripping every x-bili-* for the documented custom-header cap (#2359). The bili->bili protocol markers (x-bili-hop / x-bili-tunnel / x-bili-ws-lane) are deliberately left untouched: their consumer is a downstream bili's ingress decision (#300/#1086), so they must survive transit even though they leak harmlessly onto a terminal provider. A namespace-wide strip was tried first and broke x-bili-ws-lane transit (codex-responses-ws #3073), so the fix is scoped to the plugin family only. Regression-pinned both directions: host-private x-bili-plugin* no longer reach the model endpoint (proxy + plugin lanes, incl. the new exposed-tools channel); the chain markers still propagate; the WS lane presents the same surface. Fixes #3905
📦 Built Package ArtifactBranch: Option A — Install this exact build (recommended)npm install -g [email protected]This exact version is immutable and reproducible. The rolling Option B — Download artifact
tar xzf billion-context-pr3915.tgz
npm install -g packageInstall instructions are refreshed on each push. |
(ai: vllm/vllm-qwen/qwen3.8-27b) 查重: 不重复。 本 PR 是 #3905(x-bili-plugin* 泄漏到模型端点)的唯一修复实现;open 的 #3906/#3907 是同族但不同机制(exposed-tools 新通道本身),#3920 等无关。无并列的 egress-strip PR。 标签: 初审结论(进行中,最终八问随后):
稍后给完整八问。 |
#3915 intentionally stops forwarding x-bili-plugin* to model endpoints, but three pre-existing tests still pinned the old leak behavior and turned CI red: - responses-websocket.test.ts "egress headers": non-Azure egress asserted the x-bili-plugin* family arrives verbatim -> now asserts it is stripped (Azure's full x-bili-* strip #2359 unchanged); test name updated to match. - responses-websocket.test.ts "incremental tool continuation": the #2359 control line asserted x-bili-plugin reaches a non-Azure mock -> now asserts it does not. - plugin-bypass.test.ts "forwarded verbatim": asserted the bypass marker header reaches upstream; the marker is host-private convention metadata and is stripped at egress like the rest of the family (the body stays verbatim - tools/messages assertions unchanged). Targeted local: these files + issue3905 + hop-by-hop + chain suites green, typecheck clean; full-suite verdict = remote CI.
(ai: vllm/vllm-qwen/qwen3.8-27b) 审核结论:方向正确、实现完整、未发现回归;但 PR 漏更新了 3 个既有测试导致 CI 红——已按「小问题直接修」就地修复并推送追加 commit,等新轮 CI。 本轮做了什么原 head
修法 = 追加 commit 本地定向验证(全量交给 CI):上述 2 文件 + 八问
判定代码质量达标(命名达意、双向测试纪律齐全、diff 干净每行都服务于目的);三处 stale pin 已就地修复并推送( |
(ai: vllm/vllm-qwen/qwen3.8-27b) CI 结果:head 三处 stale pin 修复后全量回归通过,无其他旧测试钉住旧泄漏行为。PR 已就绪,等人工合并。 |
What & why
The main HTTP forward path (
buildForwardTarget) copied every inbound request header to the upstream exceptcontent-length/host, so all host-privatex-bili-plugin*convention headers leaked to the real model endpoint: the agent marker, conversation id, window/model declarations, and — once #3906/#3907 lands — the newx-bili-plugin-exposed-toolsdeclared-tools channel. The owner's constraint on that new header is "don't forward upstream"; this closes the pre-existing gap so the new header does not ship inside it.Reproduced locally before fixing: a mock upstream captured the full
x-bili-plugin*family arriving on both the proxy lane and the plugin lane (4/5 regression assertions failed pre-fix).Change
stripBiliPluginHeaders()insrc/server/headers.ts— drops everyx-bili-plugin*header.buildForwardTarget(src/server.ts) — the main send and every retry/refetch reuse these same headers.finalizeResponsesWsUpstreamHeaders(src/responses-ws.ts, non-Azure). The Azure WS branch keeps stripping everyx-bili-*for the documented custom-header cap (OpenCode V2 Azure Responses WebSocket bypasses native ACP interception; status can show stale compressed context #2359) — unchanged.Behavior change (old → new)
x-bili-plugin*(marker / conversation / window / model / exposed-tools)x-bili-hop/x-bili-tunnel/x-bili-ws-lanex-session-idWhy scoped to the plugin family (not all
x-bili-*)A namespace-wide strip was implemented first and broke
x-bili-ws-lanetransit (codex-responses-ws#3073: the shared probe/turn handshake lost the lane marker a chained bili keys off for chain-skip/self-loop detection). The plugin family is precisely the host-private convention metadata; the remainingx-bili-*are protocol/transit markers that must reach the next hop. Scoping tox-bili-plugin*closes the gap without touching chain/WS-lane detection.Tests
New
tests/issue3905-egress-bili-strip.test.tspins both directions:x-bili-plugin*reaches the model endpoint (incl. the new exposed-tools channel); client end-to-end headers unaffected.x-bili-hopstill propagates on egress while plugin metadata is stripped.Verified RED→GREEN around the fix. Targeted local suites green: this file +
hop-by-hop+issue1683-chain-egress-off+issue1086-chain-self-exemption+issue1542-chain-embedded-strip+codex-responses-ws+responses-ws-http-fallback; typecheck clean. Full-suite verdict is remote CI.Fixes #3905