Severity
Medium — a hung child process can block frame extraction indefinitely.
Location
electron/frames/extractor.ts:345 and :395 — both execFileAsync(ffmpegPath, [...], { maxBuffer: … }) calls pass only maxBuffer, with no timeout option.
Mechanism
If ffmpeg stalls (corrupt input, codec edge case, stuck pipe), the promise never settles and the extraction step hangs. Other spawns in the app do bound their runtime; these legacy ffmpeg calls don't.
Impact
Post-processing for a session can wedge, blocking the describer/analysis pipeline for that session.
Suggested fix
Add a timeout (and killSignal) to both execFileAsync option objects; on timeout, kill the child, clean up partial outputs (see the related partial-output cleanup low finding), and surface a failure.
Regression test to add (npm test)
Extend electron/frames/extractor.test.ts with a fake/stub ffmpeg binary that never exits; assert the call rejects within the timeout and the child is killed. Deterministic; not covered by evals/.
Severity
Medium — a hung child process can block frame extraction indefinitely.
Location
electron/frames/extractor.ts:345and:395— bothexecFileAsync(ffmpegPath, [...], { maxBuffer: … })calls pass onlymaxBuffer, with notimeoutoption.Mechanism
If ffmpeg stalls (corrupt input, codec edge case, stuck pipe), the promise never settles and the extraction step hangs. Other spawns in the app do bound their runtime; these legacy ffmpeg calls don't.
Impact
Post-processing for a session can wedge, blocking the describer/analysis pipeline for that session.
Suggested fix
Add a
timeout(andkillSignal) to bothexecFileAsyncoption objects; on timeout, kill the child, clean up partial outputs (see the related partial-output cleanup low finding), and surface a failure.Regression test to add (
npm test)Extend
electron/frames/extractor.test.tswith a fake/stub ffmpeg binary that never exits; assert the call rejects within the timeout and the child is killed. Deterministic; not covered byevals/.