fix(daemon): align Codex launch permissions on Windows and WSL (#3037)

Use danger-full-access when WSL_DISTRO_NAME is set and pass
default_permissions=":workspace" so newer Codex builds can write
inside the project directory instead of staying read-only.
This commit is contained in:
吴杨帆 2026-05-28 12:12:26 +08:00 committed by GitHub
parent 62972f14a3
commit 72426b942a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 54 additions and 6 deletions

View file

@ -44,6 +44,16 @@ export function parseCodexDebugModels(stdout: string): RuntimeModelOption[] | nu
return out.length > 1 ? out : null;
}
export function codexNeedsDangerFullAccessSandbox(
platform: NodeJS.Platform = process.platform,
env: NodeJS.ProcessEnv = process.env,
): boolean {
if (platform === 'win32') return true;
// WSL reports `linux` but Codex still hits the Windows read-only
// workspace-write sandbox path when launched from there (#2834).
return Boolean(env.WSL_DISTRO_NAME?.trim());
}
export const codexAgentDef = {
id: 'codex',
name: 'Codex CLI',
@ -98,8 +108,8 @@ export const codexAgentDef = {
// back to a coarse policy that rejects any shell. macOS (Seatbelt)
// and Linux (Landlock+seccomp) keep workspace-write because their
// sandbox enforcement permits shell while restricting writes.
const isWindows = process.platform === 'win32';
const args = isWindows
const needsDangerFullAccess = codexNeedsDangerFullAccessSandbox();
const args = needsDangerFullAccess
? ['exec', '--json', '--skip-git-repo-check', '--sandbox', 'danger-full-access']
: [
'exec',
@ -110,6 +120,9 @@ export const codexAgentDef = {
'-c',
'sandbox_workspace_write.network_access=true',
];
// Newer Codex builds honor permissions config over legacy sandbox
// flags; without this, Windows/WSL launches can stay read-only (#2834).
args.push('-c', 'default_permissions=":workspace"');
if (process.env.OD_CODEX_DISABLE_PLUGINS === '1') {
args.push('--disable', 'plugins');
}

View file

@ -2,6 +2,7 @@ import { test } from 'vitest';
import {
AGENT_DEFS, assert, chmodSync, codex, cursorAgent, detectAgents, join, mkdtempSync, rmSync, tmpdir, withEnvSnapshot, withPlatform, writeFileSync,
} from './helpers/test-helpers.js';
import { codexNeedsDangerFullAccessSandbox } from '../../src/runtimes/defs/codex.js';
import { readLocalAgentProfileDefs } from '../../src/runtimes/registry.js';
test('AGENT_DEFS ids are unique', () => {
@ -107,7 +108,7 @@ test('codex args disable plugins when OD_CODEX_DISABLE_PLUGINS is 1', () => {
withPlatform('darwin', () => {
const args = codex.buildArgs('', [], [], {}, { cwd: '/tmp/od-project' });
assert.deepEqual(args.slice(0, 9), [
assert.deepEqual(args.slice(0, 11), [
'exec',
'--json',
'--skip-git-repo-check',
@ -115,6 +116,8 @@ test('codex args disable plugins when OD_CODEX_DISABLE_PLUGINS is 1', () => {
'workspace-write',
'-c',
'sandbox_workspace_write.network_access=true',
'-c',
'default_permissions=":workspace"',
'--disable',
'plugins',
]);
@ -126,17 +129,48 @@ test('codex args use workspace-write sandbox on macOS and Linux', () => {
for (const platform of ['darwin', 'linux'] as const) {
withPlatform(platform, () => {
withEnvSnapshot(['WSL_DISTRO_NAME'], () => {
delete process.env.WSL_DISTRO_NAME;
const args = codex.buildArgs('', [], [], {}, { cwd: '/tmp/od-project' });
assert.equal(args.includes('--full-auto'), false);
assert.deepEqual(args.slice(0, 5), [
'exec',
'--json',
'--skip-git-repo-check',
'--sandbox',
'workspace-write',
]);
assert.equal(
args.includes('-c'),
true,
);
assert.equal(
args.includes('default_permissions=":workspace"'),
true,
);
});
});
}
});
test('codex args use danger-full-access sandbox on WSL because workspace-write stays read-only', () => {
delete process.env.OD_CODEX_DISABLE_PLUGINS;
withPlatform('linux', () => {
withEnvSnapshot(['WSL_DISTRO_NAME'], () => {
process.env.WSL_DISTRO_NAME = 'Ubuntu';
assert.equal(codexNeedsDangerFullAccessSandbox('linux', process.env), true);
const args = codex.buildArgs('', [], [], {}, { cwd: '/tmp/od-project' });
assert.equal(args.includes('--full-auto'), false);
assert.deepEqual(args.slice(0, 5), [
'exec',
'--json',
'--skip-git-repo-check',
'--sandbox',
'workspace-write',
'danger-full-access',
]);
assert.equal(args.includes('default_permissions=":workspace"'), true);
});
}
});
});
test('codex args use danger-full-access sandbox on Windows because workspace-write blocks PowerShell', () => {
@ -165,6 +199,7 @@ test('codex args use danger-full-access sandbox on Windows because workspace-wri
args.includes('sandbox_workspace_write.network_access=true'),
false,
);
assert.equal(args.includes('default_permissions=":workspace"'), true);
});
});