Skip to content

Commit 7ab98e2

Browse files
committed
Fix subprocess env leak, unbounded preview spawning, and dead code
- pptx-vm: pass minimal env to worker subprocess so it cannot inherit DB URLs, API keys, or other secrets from the Next.js process on a vm.createContext escape - PptxPreview: add AbortController so in-flight preview fetch is cancelled when the effect re-runs (e.g. next SSE update), preventing unbounded concurrent subprocesses; add 500ms debounce on streaming renders to reduce subprocess churn during rapid AI generation - file-reader: remove dead code — the `if (!isReadableType)` guard on line 110 was always true (all readable types returned earlier at line 76), making the subsequent `return null` unreachable
1 parent 51b47f1 commit 7ab98e2

File tree

3 files changed

+22
-9
lines changed

3 files changed

+22
-9
lines changed

apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/file-viewer.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -544,8 +544,11 @@ function PptxPreview({
544544

545545
useEffect(() => {
546546
let cancelled = false
547+
const controller = new AbortController()
548+
let debounceTimer: ReturnType<typeof setTimeout> | null = null
547549

548550
async function render() {
551+
if (cancelled) return
549552
try {
550553
setRendering(true)
551554
setRenderError(null)
@@ -555,6 +558,7 @@ function PptxPreview({
555558
method: 'POST',
556559
headers: { 'Content-Type': 'application/json' },
557560
body: JSON.stringify({ code: streamingContent }),
561+
signal: controller.signal,
558562
})
559563
if (!response.ok) {
560564
const err = await response.json().catch(() => ({ error: 'Preview failed' }))
@@ -596,7 +600,7 @@ function PptxPreview({
596600
pptxCacheSet(cacheKey, images)
597601
}
598602
} catch (err) {
599-
if (!cancelled) {
603+
if (!cancelled && !(err instanceof DOMException && err.name === 'AbortError')) {
600604
const msg = err instanceof Error ? err.message : 'Failed to render presentation'
601605
logger.error('PPTX render failed', { error: msg })
602606
setRenderError(msg)
@@ -606,9 +610,18 @@ function PptxPreview({
606610
}
607611
}
608612

609-
render()
613+
// Debounce streaming renders so rapid SSE updates don't spawn a subprocess
614+
// per event. Non-streaming renders (file load / cache) run immediately.
615+
if (streamingContent !== undefined) {
616+
debounceTimer = setTimeout(render, 500)
617+
} else {
618+
render()
619+
}
620+
610621
return () => {
611622
cancelled = true
623+
if (debounceTimer) clearTimeout(debounceTimer)
624+
controller.abort()
612625
}
613626
}, [fileData, dataUpdatedAt, streamingContent, cacheKey, workspaceId])
614627

apps/sim/lib/copilot/vfs/file-reader.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,10 @@ export async function readFileRecord(record: WorkspaceFileRecord): Promise<FileR
107107
}
108108
}
109109

110-
if (!isReadableType(record.type)) {
111-
return {
112-
content: `[Binary file: ${record.name} (${record.type}, ${record.size} bytes). Cannot display as text.]`,
113-
totalLines: 1,
114-
}
110+
return {
111+
content: `[Binary file: ${record.name} (${record.type}, ${record.size} bytes). Cannot display as text.]`,
112+
totalLines: 1,
115113
}
116-
117-
return null
118114
} catch (err) {
119115
logger.warn('Failed to read workspace file', {
120116
fileName: record.name,

apps/sim/lib/execution/pptx-vm.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ export async function generatePptxFromCode(code: string, workspaceId: string): P
7474
proc = spawn('node', [WORKER_PATH], {
7575
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
7676
serialization: 'json',
77+
// Prevent the subprocess from inheriting secrets (DB URL, API keys, etc.)
78+
// from the parent Next.js process. pptxgenjs only needs PATH to resolve
79+
// its own require() calls.
80+
env: { PATH: process.env.PATH ?? '' } as unknown as NodeJS.ProcessEnv,
7781
})
7882
} catch (err) {
7983
done(err instanceof Error ? err : new Error(String(err)))

0 commit comments

Comments
 (0)