qwen-code/scripts/tests/sandbox-command.test.js
jinye 09411aa0a9
fix(cli): Harden settings failures and sandbox command streams (#13140)
* fix(cli): Harden settings failures and sandbox command streams

* ci: Quote the native stdin verification step

* test(cli): Verify native sandbox and settings boundaries

* test(cli): Check complete policy during Windows settings saves

* fix(cli): Diagnose invalid verification temp roots before probing

Check private stdin pipe ownership on Linux rather than requiring proc reopening to fail. Refs #12417.

* fix(cli): address settings and sandbox review feedback (#13140)

* fix(cli): recover read-only workspace settings across restarts (#13140)

* fix(cli): preserve readonly recovery and SDK sandbox arguments

* fix: protect settings recovery and sandbox streams

Refs #12417

* test(cli): fix Windows workspace recovery fixtures

Resolve the four recovery fixtures consistently and require the intended
preservation failure instead of accepting an earlier canonical-path error.

Refs #12417
2026-10-03 12:02:48 +00:00

90 lines
3 KiB
JavaScript

/**
* @license
* Copyright 2026 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import { execFileSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import path from 'node:path';
import { describe, expect, it } from 'vitest';
const scriptPath = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'..',
'sandbox_command.js',
);
/**
* Runs sandbox_command.js as a subprocess with the given QWEN_SANDBOX value.
* Returns { status, stdout, stderr }. Never throws on a non-zero exit so the
* caller can assert on the exit code.
*/
function runSandboxCommand(sandboxValue, inherited = '') {
try {
const stdout = execFileSync(process.execPath, [scriptPath, '-q'], {
encoding: 'utf8',
env: { ...process.env, QWEN_SANDBOX: sandboxValue, SANDBOX: inherited },
});
return { status: 0, stdout, stderr: '' };
} catch (err) {
return {
status: err.status ?? 1,
stdout: err.stdout?.toString() ?? '',
stderr: err.stderr?.toString() ?? '',
};
}
}
describe('sandbox_command.js QWEN_SANDBOX handling', () => {
// Each payload appends a command that would exit 0 if the shell ever split
// the value on the metacharacter. A vulnerable build runs e.g.
// `command -v doesnotexist; true`, which exits 0, so commandExists() returns
// true and the script echoes the payload and exits 0. The hardened build
// treats the whole string as a single command name, fails to find it, and
// exits non-zero — so a regression here flips these assertions.
const injectionPayloads = [
'doesnotexist; true',
'doesnotexist && true',
'doesnotexist | true',
'doesnotexist; echo pwned',
'$(true)',
'`true`',
];
for (const payload of injectionPayloads) {
it(`rejects the injection payload ${JSON.stringify(payload)} instead of executing it`, () => {
const { status, stdout } = runSandboxCommand(payload);
expect(status).not.toBe(0);
// The payload must never be accepted as a resolved sandbox command.
expect(stdout.trim()).toBe('');
});
}
it('reports the raw value as a single missing command (no shell splitting)', () => {
const payload = 'doesnotexist; echo pwned';
const { status, stderr } = runSandboxCommand(payload);
expect(status).not.toBe(0);
// The entire string is echoed back verbatim, proving it was treated as one
// opaque command name rather than parsed by a shell.
expect(stderr).toContain(`missing sandbox command '${payload}'`);
});
});
it.each(['bwrap', 'BWRAP', ' BWRAP '])(
'normalizes inherited bwrap marker %j',
(marker) => {
const { status, stderr } = runSandboxCommand('false', marker);
expect(status).not.toBe(0);
expect(stderr).toContain('Whole-CLI bwrap has been removed');
},
);
it.each(['bwrap', 'BWRAP', ' BWRAP '])(
'rejects the legacy QWEN_SANDBOX bwrap selection %j',
(marker) => {
const { status, stderr } = runSandboxCommand(marker);
expect(status).not.toBe(0);
expect(stderr).toContain('Whole-CLI bwrap has been removed');
},
);