fix(code-runtime): separate model environment from native startup paths
This commit is contained in:
1 parent
a6f7eeadc6
commit
98d3af0683
12 files changed
+46
-14
No files matched your search
@@ -20,6 +20,9 @@ function processState(): ProgramProcess { return { env: { FIXTURE_SECRET: 'test'
|
||||
it('clears process environment, dispatches a binding reply and flushes the terminal frame', async () => {
|
||||
const { child, host } = endpoints()
|
||||
const state = processState()
|
||||
const nativeEnvironment = state.env
|
||||
nativeEnvironment.SystemRoot = 'C:\\Windows'
|
||||
nativeEnvironment.PATH = '/native/bin'
|
||||
const messages: Record<string, unknown>[] = []
|
||||
const peer = new JsonChannel(host, 4096, (raw) => {
|
||||
const message = raw as Record<string, unknown>
|
||||
@@ -30,6 +33,9 @@ it('clears process environment, dispatches a binding reply and flushes the termi
|
||||
onTestFinished(() => { peer.close() })
|
||||
await runNodeMain(child, 4096, state)
|
||||
expect(state.env).toEqual({})
|
||||
expect(state.env).not.toBe(nativeEnvironment)
|
||||
expect(Object.getPrototypeOf(state.env)).toBeNull()
|
||||
expect(nativeEnvironment).toEqual({ SystemRoot: 'C:\\Windows', PATH: '/native/bin' })
|
||||
expect(state.exitCode).toBeUndefined()
|
||||
expect(decodeCodeJsonWire(messages.find(message => message.type === 'done')?.value)).toBe(42)
|
||||
})
|
||||
|
||||
@@ -11,7 +11,7 @@ import { decodeCodeJsonWire, encodeCodeJsonWire } from '../src/json-wire.ts'
|
||||
it('boots an unbuilt source closure outside the workspace and exchanges tool replies', async () => {
|
||||
const directory = await mkdtemp(join(tmpdir(), 'dsh-node-source-'))
|
||||
onTestFinished(async () => { await rm(directory, { recursive: true, force: true }) })
|
||||
for (const file of ['process.ts', 'bootstrap.ts', 'channel.ts', 'json-wire.ts', 'output-json.ts', 'protocol.ts']) {
|
||||
for (const file of ['process.ts', 'bootstrap.ts', 'channel.ts', 'json-wire.ts', 'output-json.ts', 'protocol.ts', 'environment.ts']) {
|
||||
await copyFile(new URL(`../src/${file}`, import.meta.url), join(directory, file))
|
||||
}
|
||||
const source = `import {Socket} from 'node:net';import {runNodeMain} from ${JSON.stringify(pathToFileURL(join(directory, 'process.ts')).href)};await runNodeMain(new Socket({fd:7,readable:true,writable:true}),100000,process);`
|
||||
|
||||
@@ -33,6 +33,23 @@ describe('Node program process', () => {
|
||||
expect(result.sandbox).toEqual({ mode: 'danger-full-access', denied: false })
|
||||
})
|
||||
|
||||
it('keeps native startup paths available for nested Node creation with an empty model environment', async () => {
|
||||
const { run } = await setup()
|
||||
const result = await run({
|
||||
program: 'const {spawnSync}=await import("node:child_process"); const child=spawnSync(process.execPath,["-e","process.stdout.write(JSON.stringify(Object.keys(process.env)))"],{encoding:"utf8"}); return {env:Object.keys(process.env),status:child.status,error:child.error?.message ?? null,childKeys:JSON.parse(child.stdout || "[]")};',
|
||||
bindings: [],
|
||||
})
|
||||
expect(result.error).toBeUndefined()
|
||||
const value = result.value as { env: string[]; status: number | null; error: string | null; childKeys: string[] }
|
||||
expect(value.env).toEqual([])
|
||||
expect(value.status).toBe(0)
|
||||
expect(value.error).toBeNull()
|
||||
const nativeKeys = ['PATH', 'PATHEXT', 'SYSTEMROOT', 'WINDIR']
|
||||
// CoreFoundation initializes this entry independently when a macOS child starts.
|
||||
if (process.platform === 'darwin') nativeKeys.push('__CF_USER_TEXT_ENCODING')
|
||||
expect(value.childKeys.filter(key => !nativeKeys.includes(key.toUpperCase()))).toEqual([])
|
||||
})
|
||||
|
||||
it('returns binding values and preserves typed binding rejection', async () => {
|
||||
const { run } = await setup()
|
||||
const result = await run({
|
||||
@@ -180,7 +197,7 @@ describe('Node program process', () => {
|
||||
const confine = ctx.sandbox.confine.bind(ctx.sandbox)
|
||||
const policy = runtime.resolve({ program: '', bindings: [] }).sandboxPolicy
|
||||
if (policy === undefined || policy.mode === 'danger-full-access') throw new Error('expected confined policy')
|
||||
const wrapped = confine([process.execPath, '--version'], policy)
|
||||
const wrapped = confine([process.execPath, '--version'], { ...policy, mode: policy.mode })
|
||||
const original = wrapped.argv[0]
|
||||
if (original === undefined) throw new Error('expected sandbox launcher')
|
||||
const executable = await ctx.subprocess.resolveExecutable(original)
|
||||
|
||||
Reference in new issue
Block a user