Skip to content

Commit 4cce577

Browse files
committed
fix(files): fence render names and separate compiler caches
1 parent 8d7dd70 commit 4cce577

4 files changed

Lines changed: 71 additions & 19 deletions

File tree

‎apps/sim/lib/projects/files/__integration__/content-rendered.integration.ts‎

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ import { searchProjectFileContent } from '@/lib/projects/files/application/searc
4646
import { revertProjectFileVersion } from '@/lib/projects/files/application/versions'
4747
import * as storageCleanup from '@/lib/uploads/contexts/workspace/file-storage-cleanup-outbox'
4848
import * as storage from '@/lib/uploads/core/storage-service'
49-
import { storeCompiledDoc } from '@/lib/uploads/documents/compiled-store'
49+
import { compileFileDocument } from '@/lib/uploads/documents/compile'
5050
import * as heic from '@/lib/uploads/server/heic'
5151
import { observeWorkspaceFileDelivery } from '@/lib/workspace-files/application/file-delivery-observer'
5252
import * as searchDelivery from '@/lib/workspace-files/search/delivery'
@@ -705,6 +705,33 @@ describe('Project rendered artifacts against PostgreSQL and private storage', ()
705705
}
706706
)
707707

708+
check('a source renamed during rendering is refused', async () => {
709+
const { readProjectFileArtifact } = await import('@/lib/projects/files/application/artifacts')
710+
const { renameProjectFile } = await import('@/lib/projects/files/application/lifecycle')
711+
const f = await fixture()
712+
const source = await createProjectFile.execute({
713+
principal: f.principal,
714+
input: {
715+
...createInput(f.projectId, 'const title = "test"'),
716+
name: 'before.pptx',
717+
contentType: 'text/x-pptxgenjs',
718+
},
719+
})
720+
vi.spyOn(sandboxTask, 'runSandboxTask').mockImplementation(async () => {
721+
await renameProjectFile.execute({
722+
principal: f.principal,
723+
input: { projectId: f.projectId, fileId: source.file.id, name: 'after.docx' },
724+
})
725+
return Buffer.from('PK\u0003\u0004document')
726+
})
727+
await expect(
728+
readProjectFileArtifact.execute({
729+
principal: f.principal,
730+
input: { projectId: f.projectId, fileId: source.file.id, maxBytes: 1_000_000 },
731+
})
732+
).rejects.toMatchObject({ code: 'conflict' })
733+
})
734+
708735
check(
709736
'an asset changed during render cannot be delivered with stale provenance or source identity',
710737
async () => {
@@ -780,13 +807,15 @@ describe('Project rendered artifacts against PostgreSQL and private storage', ()
780807
},
781808
})
782809
const artifact = Buffer.from(`PK\u0003\u0004${marker}`)
783-
await storeCompiledDoc(
784-
{ entityType: 'project', entityId: f.projectId },
810+
vi.spyOn(sandboxTask, 'runSandboxTask').mockResolvedValue(artifact)
811+
await compileFileDocument({
812+
owner: { entityType: 'project', entityId: f.projectId },
785813
source,
786-
'pptx',
787-
mime,
788-
artifact
789-
)
814+
sourceMime: 'text/x-pptxgenjs',
815+
fileName: 'architecture.pptx',
816+
inputs: [],
817+
maxBytes: 1_000_000,
818+
})
790819
prepared.push({ f, created, artifact })
791820
}
792821
for (const { f, created, artifact } of prepared) {

‎apps/sim/lib/projects/files/application/artifacts.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ function requireSameRevision(current: WorkspaceFileRow | undefined, expected: Wo
8585
if (
8686
!current ||
8787
current.key !== expected.key ||
88+
current.originalName !== expected.originalName ||
89+
current.contentType !== expected.contentType ||
8890
current.contentUpdatedAt.getTime() !== expected.contentUpdatedAt.getTime()
8991
) {
9092
throw new OrchestrationError('conflict', 'A document source or input changed during rendering')

‎apps/sim/lib/uploads/documents/compile.test.ts‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,3 +421,25 @@ describe('compileFileDocument source engine', () => {
421421
expect(executeInSandboxMock).not.toHaveBeenCalled()
422422
})
423423
})
424+
425+
it('separates cached PDF artifacts by effective source dialect', async () => {
426+
setEnvFlags({ isDocSandboxEnabled: true })
427+
const identities: string[] = []
428+
loadCompiledDocMock.mockImplementation(async (_owner, _source, _ext, identity) => {
429+
identities.push(identity)
430+
return Buffer.from(identity.includes('javascript') ? '%PDF-JS' : '%PDF-Python')
431+
})
432+
const input = {
433+
owner: { entityType: 'project' as const, entityId: ID },
434+
source: 'shared source',
435+
fileName: 'report.pdf',
436+
inputs: [],
437+
maxBytes: 1024,
438+
}
439+
const js = await compileFileDocument({ ...input, sourceMime: 'text/x-pdflibjs' })
440+
const python = await compileFileDocument({ ...input, sourceMime: 'text/x-python' })
441+
expect(js.buffer.toString()).toBe('%PDF-JS')
442+
expect(python.buffer.toString()).toBe('%PDF-Python')
443+
expect(js.artifactKey).not.toBe(python.artifactKey)
444+
expect(identities[0]).not.toBe(identities[1])
445+
})

‎apps/sim/lib/uploads/documents/compile.ts‎

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -640,19 +640,25 @@ export async function compileFileDocument(args: {
640640
) {
641641
throw new DocCompileUserError('Document inputs exceed the rendering limit')
642642
}
643-
const cached = await loadCompiledDoc(args.owner, args.source, fmt.ext, args.inputIdentity, {
643+
const useDocumentSandbox = isDocSandboxEnabled && args.sourceMime !== 'text/x-pdflibjs'
644+
const cacheIdentity = JSON.stringify({
645+
sourceLanguage: getDocumentSourceLanguage(args.source, fmt, args.sourceMime),
646+
renderer: useDocumentSandbox ? 'document-sandbox' : 'native',
647+
inputs: args.inputIdentity ?? null,
648+
})
649+
const cached = await loadCompiledDoc(args.owner, args.source, fmt.ext, cacheIdentity, {
644650
maxBytes: args.maxBytes,
645651
signal: args.signal,
646652
})
647653
if (cached)
648654
return {
649655
buffer: cached,
650-
artifactKey: compiledArtifactKey(args.owner, args.source, fmt.ext, args.inputIdentity),
656+
artifactKey: compiledArtifactKey(args.owner, args.source, fmt.ext, cacheIdentity),
651657
contentType: fmt.contentType,
652658
dependsOnReferencedFiles: args.inputs.length > 0,
653659
}
654660
let buffer: Buffer
655-
if (isDocSandboxEnabled && args.sourceMime !== 'text/x-pdflibjs') {
661+
if (useDocumentSandbox) {
656662
buffer = await renderPreparedDocument(
657663
args.source,
658664
fmt,
@@ -684,17 +690,10 @@ export async function compileFileDocument(args: {
684690
)
685691
}
686692
assertKnownSizeWithinLimit(buffer.length, args.maxBytes, 'compiled document')
687-
await storeCompiledDoc(
688-
args.owner,
689-
args.source,
690-
fmt.ext,
691-
fmt.contentType,
692-
buffer,
693-
args.inputIdentity
694-
)
693+
await storeCompiledDoc(args.owner, args.source, fmt.ext, fmt.contentType, buffer, cacheIdentity)
695694
return {
696695
buffer,
697-
artifactKey: compiledArtifactKey(args.owner, args.source, fmt.ext, args.inputIdentity),
696+
artifactKey: compiledArtifactKey(args.owner, args.source, fmt.ext, cacheIdentity),
698697
contentType: fmt.contentType,
699698
dependsOnReferencedFiles: args.inputs.length > 0,
700699
}

0 commit comments

Comments
 (0)