fix(relay): use safe process runner for inspection

This commit is contained in:
Brennan Benson
2026-08-27 18:25:36 -07:00
parent 344b1205c4
commit dadeeca765
2 changed files with 71 additions and 10 deletions
@@ -0,0 +1,60 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { inspectProcessChildren } from './pty-child-process-inspection'
import { runProcess } from '../shared/child-process/run-process'
vi.mock('../shared/child-process/run-process', () => ({ runProcess: vi.fn() }))
const result = (overrides: Partial<Awaited<ReturnType<typeof runProcess>>> = {}) => ({
code: 0,
signal: null,
stdout: '42\n',
stderr: '',
timedOut: false,
...overrides
})
describe('inspectProcessChildren', () => {
beforeEach(() => vi.mocked(runProcess).mockReset())
it('reports children only from successful pgrep output', async () => {
vi.mocked(runProcess).mockResolvedValue(result())
await expect(inspectProcessChildren(41)).resolves.toEqual({ hasChildProcesses: true })
expect(runProcess).toHaveBeenCalledWith({
program: 'pgrep',
args: ['-P', '41'],
timeoutMs: 3000
})
})
it('reports no children only from the pgrep no-match exit', async () => {
vi.mocked(runProcess).mockResolvedValue(result({ code: 1, stdout: '' }))
await expect(inspectProcessChildren(41)).resolves.toEqual({ hasChildProcesses: false })
})
it.each([
result({ code: 0, stdout: '' }),
result({ code: 2, stdout: '' }),
result({ code: null, signal: 'SIGTERM', stdout: '' }),
result({ code: 1, stdout: '', timedOut: true })
])('marks degraded process reads unavailable', async (processResult) => {
vi.mocked(runProcess).mockResolvedValue(processResult)
await expect(inspectProcessChildren(41)).resolves.toEqual({
hasChildProcesses: false,
unavailable: true
})
})
it('marks spawn failures unavailable', async () => {
vi.mocked(runProcess).mockImplementationOnce(() => {
throw new Error('pgrep missing')
})
await expect(inspectProcessChildren(41)).resolves.toEqual({
hasChildProcesses: false,
unavailable: true
})
})
})
+11 -10
View File
@@ -1,22 +1,23 @@
import { execFile as execFileCb } from 'node:child_process'
import { promisify } from 'node:util'
const execFile = promisify(execFileCb)
import { runProcess } from '../shared/child-process/run-process'
export async function inspectProcessChildren(pid: number): Promise<{
hasChildProcesses: boolean
unavailable?: true
}> {
try {
const { stdout } = await execFile('pgrep', ['-P', String(pid)], {
encoding: 'utf-8',
timeout: 3000
const result = await runProcess({
program: 'pgrep',
args: ['-P', String(pid)],
timeoutMs: 3000
})
return { hasChildProcesses: stdout.trim().length > 0 }
} catch (error) {
if ((error as { code?: string | number }).code === 1) {
if (result.code === 0 && result.stdout.trim().length > 0) {
return { hasChildProcesses: true }
}
if (result.code === 1 && !result.timedOut) {
return { hasChildProcesses: false }
}
return { hasChildProcesses: false, unavailable: true }
} catch {
return { hasChildProcesses: false, unavailable: true }
}
}