Files
qwen-code/integration-tests/helpers/hosted-relay-headers.ts
T
Heyang Wangandwangheyang 8666ab091f fix(cli): reject malformed hosted shell Unicode before admission (#13678)
* fix(cli): reject malformed hosted shell Unicode before admission

Prevent lone UTF-16 surrogates from reaching Workspace acquisition
or execution while preserving valid Unicode and durable history.

- Refuse whole batches before Hooks and native tool admission
- Stop malformed sequential Hook rewrites and restore safe refusals
- Suppress post-tool callbacks for live and replayed Unicode refusals
- Cover local/O2 persistence, same-turn correction, and Session reuse
- Document the admission design and local acceptance evidence

* fix(cli): preserve durable hosted shell Unicode refusals

Keep malformed Shell input refusals bounded and recoverable after
Hook rewrites without losing policy denials or the original store error.

- Normalize optional arguments and validate reduced refusal evidence
- Fold nested permission rewrites and bound assembled Hook receipts
- Read recovery resources concurrently while preserving event order
- Cover MCP and background guards, sibling denials and failed writes
- Stabilize Hook admission waits and verify the second Session alone

* fix(cli): keep hosted Unicode refusals replayable and batch-wide

Keep durable Unicode refusals correctable across terminal Hook
recovery and bounded receipts, without admitting sibling tools.

- Accept proven-unstarted Hooks while rejecting blocked evidence
- Preserve a fixed Unicode reason in byte-bounded Hook refusals
- Retain each sibling's own argument validation error
- Pin MCP admission, Hook handoff and continuation regression cases

* fix(cli): recover cancelled size-refused hook plans

Treat cancelled Hook plans as terminal when their durable evidence
proves a result or no dispatch, so Unicode batch refusals can replay.

- Preserve failure-closed checks for unresolved or contradictory evidence
- Cover bounded permission refusals and independent recovery guard failures
- Assert Java capture lanes and single successful dispatch in both sessions

* test(sdk-java): scope Unicode publication checks per session

Shared publication rows made the local gate depend on invocation order.
A global positive count also hid a missing secondary-session capture.

- Filter publication counts by the current tenant and each session
- Preserve local zero and o2 positive checks for both sessions

* test(sdk-java): verify hosted Unicode capture completion

Make local publication checks run against an available service,
and distinguish completed o2 captures from reservation rows.

- Register publication fixtures for both capture modes
- Require referenced and complete results in each o2 session

* test(sdk-java): align Unicode gate with managed schema

Keep the hosted Unicode oracle runnable after schema consolidation.
Use canonical tables without changing the per-session completion
and single-dispatch assertions.

- Query captures from ma_output_capture
- Query dispatch evidence from ma_tool_execution

* test(managed-agent): align Unicode gate with main contracts

Keep the hosted Unicode gate compatible with the server's updated
Checkstyle rules and object-store contract after the module move.

- Add braces around the missing-object fixture refusal
- Add braces around the local-mode empty-capture assertion
- Align the fixture with the current object-store validation method

* test(managed-agent): register native macOS workspace fixtures

The Hosted tool-turn fixture registered guarded workspaces only on
Linux, leaving corrected Shell calls unavailable on supported macOS
hosts after malformed input had been refused.

- Match fixture registration to the native storage guard platforms
- Exercise the existing physical checks for both supported host systems

Native macOS local/O2 tests and the non-Unicode workspace control pass
with the original assertions, physical guards and execution deadlines.

---------

Co-authored-by: wangheyang <[email protected]>
2026-10-23 02:16:46 +00:00

59 lines
1.9 KiB
TypeScript

/**
* @license
* Copyright 2026 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import type { ServerResponse } from 'node:http';
// The Hosted drivers' Node proxies buffer the body fetch decoded and send it
// on, so only headers that still describe that body may follow it. Hop-by-hop
// fields (RFC 9110 §7.6.1, the proxy-auth pair, and every name the upstream
// `Connection` lists) describe Spring's connection: relaying its
// `Keep-Alive: timeout=60` let the daemon's fetch pool reuse a socket the
// proxy had just closed at its own 5 s idle timeout ("other side closed").
// Framing and coding fields describe bytes the proxy no longer holds; Node
// frames the buffered body itself.
const NOT_RELAYED = [
'connection',
'keep-alive',
'proxy-authenticate',
'proxy-authorization',
'proxy-connection',
'te',
'transfer-encoding',
'upgrade',
'trailer',
'content-length',
'content-encoding',
];
export function relayedHeaders(headers: Headers): Record<string, string> {
const dropped = new Set([
...NOT_RELAYED,
...(headers.get('connection') ?? '')
.split(',')
.map((name) => name.trim().toLowerCase())
.filter(Boolean),
]);
return Object.fromEntries(
[...headers].filter(([name]) => !dropped.has(name)),
);
}
// The wholesale upstream relays — hosted-{latency,process-crash,
// shell-output,shell-unicode,store-failure,workspace-tool-turn,channel-fault}-driver.ts —
// pass through this one site, pinned by the caller list in
// hosted-relay-headers.test.ts. The drivers' other upstream replies write
// fixed header literals and must stay that way: a driver-local copy of the
// upstream header set would leak hop-by-hop spellings again, and nothing
// enforces it.
export function relayUpstream(
res: ServerResponse,
upstream: Response,
body: Buffer,
): void {
res.writeHead(upstream.status, relayedHeaders(upstream.headers));
res.end(body);
}