fix(codex): verify reconstructed WSL homes

This commit is contained in:
Brennan Benson
2026-08-27 11:36:13 -07:00
parent 481777b2f0
commit 99a687d6bd
5 changed files with 46 additions and 6 deletions
+1 -1
View File
@@ -152,7 +152,7 @@ describe('agent hooks CLI handler', () => {
expect(callMock).toHaveBeenCalledExactlyOnceWith(
'agentHooks.prepareCodexForWslPane',
{ codexHome: home, orcaCodexHome: home, wslDistro: 'Ubuntu-24.04' },
{ timeoutMs: 40_000 }
{ timeoutMs: 50_000 }
)
expect(prepareManagedCodexHomeBeforeShellLaunchMock).not.toHaveBeenCalled()
})
+2 -2
View File
@@ -28,8 +28,8 @@ type AgentHookCommandResult = {
statuses: AgentHookInstallStatus[]
}
// Covers the 5s WSL identity probe, 30s trust grant, and bounded app-server reap.
const WSL_CODEX_PREPARE_TIMEOUT_MS = 40_000
// Covers managed-home verification, WSL identity, trust grant, and bounded app-server reap.
const WSL_CODEX_PREPARE_TIMEOUT_MS = 50_000
function getDataPath(): string {
const userDataPath = getDefaultUserDataPath()
@@ -2,6 +2,13 @@ import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it, vi } from 'vitest'
const { wslRealpathMock } = vi.hoisted(() => ({
wslRealpathMock: vi.fn(async (path: string) => path)
}))
vi.mock('node:fs/promises', () => ({ realpath: wslRealpathMock }))
import {
prepareManagedCodexHomeBeforeShellLaunch,
resolveManagedCodexShellPreflightHome
@@ -24,6 +31,7 @@ function makeRoot(): string {
}
afterEach(() => {
wslRealpathMock.mockClear()
managedWslHomeRegistryInternals.clearRecordedManagedWslCodexHomes()
for (const root of roots.splice(0)) {
rmSync(root, { recursive: true, force: true })
@@ -1,9 +1,12 @@
import { realpath } from 'node:fs/promises'
import type { AgentHookInstallStatus } from '../../shared/agent-hook-types'
import { withTimeout } from '../../shared/promise-timeout-fallback'
import type { CodexWslRuntimeHookTarget } from './codex-wsl-hook-install-plan'
import { codexHookService } from './hook-service'
import {
isAbsolutePosixPathWithoutDotSegments,
resolveManagedWslCodexHome
resolveManagedWslCodexHome,
wslRuntimeHomePathsEqual
} from './managed-wsl-codex-home-registry'
type WslShellPreflightEnvironment = {
@@ -12,6 +15,8 @@ type WslShellPreflightEnvironment = {
WSL_DISTRO_NAME?: string
}
const WSL_MANAGED_HOME_REALPATH_TIMEOUT_MS = 5_000
export type ManagedWslCodexShellPreflightTarget = {
runtimeHomePath: string
wslDistro: string
@@ -51,6 +56,14 @@ export async function prepareManagedWslCodexHomeBeforeShellLaunch(args: {
if (!target) {
return null
}
const realHome = await withTimeout(
realpath(target.runtimeHomePath),
WSL_MANAGED_HOME_REALPATH_TIMEOUT_MS,
null
)
if (!realHome || !wslRuntimeHomePathsEqual(realHome, target.runtimeHomePath)) {
return null
}
const install =
args.install ??
((home: string, hookTarget: CodexWslRuntimeHookTarget) =>
@@ -2,13 +2,15 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { OrcaRuntimeService } from '../../orca-runtime'
import { isStreamingMethod, type RpcContext } from '../core'
const { installForRuntimeHomeSerializedMock } = vi.hoisted(() => ({
installForRuntimeHomeSerializedMock: vi.fn()
const { installForRuntimeHomeSerializedMock, realpathMock } = vi.hoisted(() => ({
installForRuntimeHomeSerializedMock: vi.fn(),
realpathMock: vi.fn()
}))
vi.mock('../../../codex/hook-service', () => ({
codexHookService: { installForRuntimeHomeSerialized: installForRuntimeHomeSerializedMock }
}))
vi.mock('node:fs/promises', () => ({ realpath: realpathMock }))
import { AGENT_HOOK_METHODS } from './agent-hooks'
import {
@@ -42,6 +44,8 @@ function runtimeWithSettings(enabled = true, disabledTuiAgents: string[] = []):
describe('agent hook RPC methods', () => {
beforeEach(() => {
installForRuntimeHomeSerializedMock.mockReset()
realpathMock.mockReset()
realpathMock.mockImplementation(async (path: string) => path)
managedWslHomeRegistryInternals.clearRecordedManagedWslCodexHomes()
recordManagedWslCodexHome('Ubuntu-24.04', RUNTIME_HOME)
})
@@ -112,6 +116,21 @@ describe('agent hook RPC methods', () => {
expect(installForRuntimeHomeSerializedMock).toHaveBeenCalledOnce()
})
it('rejects a managed-looking home that resolves through a symlink', async () => {
realpathMock.mockResolvedValue(
'\\\\wsl.localhost\\Ubuntu-24.04\\home\\jin\\outside-managed-home'
)
const method = prepareMethod()
const params = method.params!.parse({
codexHome: LINUX_HOME,
orcaCodexHome: LINUX_HOME,
wslDistro: 'Ubuntu-24.04'
})
await expect(method.handler(params, { runtime: runtimeWithSettings() })).resolves.toBeNull()
expect(installForRuntimeHomeSerializedMock).not.toHaveBeenCalled()
})
it('rejects malformed distro names at the RPC schema', () => {
const method = prepareMethod()