fix(serve): stop cdp-mcp-command reading process.env directly (#6562)

cdp-mcp-command.ts read process.env directly — via a `= process.env` default on resolveCdpMcpCommand and a direct read in isBrowserAutomationMcpAvailable — which trips the serve process.env guard test (process-env-guard.test.ts) and fails CI on main.

Thread env through both helpers instead: they now take env explicitly, supplied by the already-allowlisted boundary callers (acp-http, run-qwen-serve, serve-features). Behavior is unchanged.
This commit is contained in:
chinesepowered 2026-07-08 20:34:45 -07:00 committed by GitHub
parent 6e48077532
commit d8084c63bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 26 additions and 14 deletions

View file

@ -102,7 +102,7 @@ function buildChromeDevToolsMcpRuntimeConfig(
) {
return undefined;
}
const command = resolveCdpMcpCommand();
const command = resolveCdpMcpCommand(process.env);
if (!command) {
writeStderrLine(
`qwen serve: set ${QWEN_CDP_MCP_COMMAND_ENV} to enable browser automation MCP (no adapter is bundled)`,

View file

@ -8,20 +8,23 @@
export const QWEN_CDP_MCP_COMMAND_ENV = 'QWEN_CDP_MCP_COMMAND';
export function resolveCdpMcpCommand(
env: NodeJS.ProcessEnv = process.env,
env: NodeJS.ProcessEnv,
): string | undefined {
const command = env[QWEN_CDP_MCP_COMMAND_ENV]?.trim();
return command ? command : undefined;
}
export function isBrowserAutomationMcpAvailable(opts: {
cdpTunnelOverWs?: boolean;
token?: string;
}): boolean {
export function isBrowserAutomationMcpAvailable(
opts: {
cdpTunnelOverWs?: boolean;
token?: string;
},
env: NodeJS.ProcessEnv,
): boolean {
return (
opts.cdpTunnelOverWs === true &&
!opts.token &&
process.env['QWEN_SERVE_ACP_HTTP'] !== '0' &&
resolveCdpMcpCommand() !== undefined
env['QWEN_SERVE_ACP_HTTP'] !== '0' &&
resolveCdpMcpCommand(env) !== undefined
);
}

View file

@ -1516,10 +1516,13 @@ describe('runQwenServe runtime startup failures', () => {
it('does not enable browser automation MCP on bearer-protected endpoints', () => {
expect(
isBrowserAutomationMcpAvailable({
cdpTunnelOverWs: true,
token: 'secret-token',
}),
isBrowserAutomationMcpAvailable(
{
cdpTunnelOverWs: true,
token: 'secret-token',
},
{},
),
).toBe(false);
});

View file

@ -854,7 +854,10 @@ function currentServeFeaturesForRunQwenServe(
// so the bootstrap `/capabilities` window doesn't briefly under-report them.
clientMcpOverWsEnabled: opts.clientMcpOverWs === true,
cdpTunnelOverWsEnabled: opts.cdpTunnelOverWs === true,
browserAutomationMcpAvailable: isBrowserAutomationMcpAvailable(opts),
browserAutomationMcpAvailable: isBrowserAutomationMcpAvailable(
opts,
process.env,
),
});
}

View file

@ -95,7 +95,10 @@ export function createServeFeatures(
multiWorkspaceSessionsEnabled,
clientMcpOverWsEnabled: opts.clientMcpOverWs === true,
cdpTunnelOverWsEnabled: opts.cdpTunnelOverWs === true,
browserAutomationMcpAvailable: isBrowserAutomationMcpAvailable(opts),
browserAutomationMcpAvailable: isBrowserAutomationMcpAvailable(
opts,
process.env,
),
voiceTranscriptionAvailable: getCachedVoiceTranscriptionAvailable(),
// Advertised whenever the `/voice/stream` WS endpoint exists (ACP HTTP
// on). A configured token no longer suppresses it — the browser carries