fix(daemon): enforce stderr retention bound

This commit is contained in:
Brennan Benson
2026-08-27 15:24:16 -07:00
parent a9256f10db
commit 4c55629ef1
2 changed files with 39 additions and 1 deletions
@@ -46,6 +46,33 @@ describe('observeDaemonChildExit', () => {
)
})
it('retains only the configured bytes from an oversized stderr chunk', () => {
const child = createChild()
const onExit = vi.fn()
const observer = observeDaemonChildExit(child, onExit, 8)
observer.markReady()
child.stderr.write(Buffer.from(`${'x'.repeat(1024 * 1024)}FATAL`))
child.emit('exit', 134, null)
child.stderr.emit('end')
expect(onExit).toHaveBeenCalledWith(expect.objectContaining({ stderrTail: 'xxxFATAL' }))
})
it('reports once when stderr closes before the child exits', () => {
const child = createChild()
const onExit = vi.fn()
const observer = observeDaemonChildExit(child, onExit)
observer.markReady()
child.stderr.emit('close')
child.emit('exit', 134, null)
child.emit('exit', 134, null)
expect(onExit).toHaveBeenCalledOnce()
expect(onExit).toHaveBeenCalledWith(expect.objectContaining({ stderrTail: '' }))
})
it('swallows stderr errors after process exit while awaiting drain', () => {
const child = createChild()
const onExit = vi.fn()
+12 -1
View File
@@ -28,6 +28,17 @@ export type DaemonChildExitObserver = {
stop(options?: { destroyStderr?: boolean }): void
}
function appendStderrTail(current: Buffer, chunk: Buffer, maxBytes: number): Buffer {
if (maxBytes <= 0) {
return Buffer.alloc(0)
}
if (chunk.length >= maxBytes) {
return Buffer.from(chunk.subarray(-maxBytes))
}
const currentBytes = Math.min(current.length, maxBytes - chunk.length)
return Buffer.concat([current.subarray(-currentBytes), chunk], currentBytes + chunk.length)
}
export function observeDaemonChildExit(
child: ObservableDaemonChild,
recordExit: (observation: DaemonChildExitObservation) => void,
@@ -42,7 +53,7 @@ export function observeDaemonChildExit(
const onStderr = (chunk: Buffer | string): void => {
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)
stderrTail = Buffer.concat([stderrTail, bytes]).subarray(-maxStderrBytes)
stderrTail = appendStderrTail(stderrTail, bytes, maxStderrBytes)
}
const onStderrError = (): void => {}
const finalizeExit = (): void => {