Skip to content

Commit 41c1f24

Browse files
Bill Leoutsakoscursoragent
authored andcommitted
fix(e2e): stabilize sandbox dependency resolution
Declare bundle polyfills explicitly and verify the app-resolved packages so clean CI installs cannot drift with workspace hoisting. Avoid misleading final invariant errors before scenario seeding begins. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent ee20cbc commit 41c1f24

7 files changed

Lines changed: 51 additions & 12 deletions

File tree

apps/sim/e2e/scripts/run.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ async function main(): Promise<void> {
117117
let canaryCoverageComplete = true
118118
let diagnosticsRetained = true
119119
let failed = false
120+
let seedAttempted = false
120121

121122
const persistFakeRequestLogs = (): void => {
122123
const failures: unknown[] = []
@@ -373,6 +374,7 @@ async function main(): Promise<void> {
373374
)
374375
assertNoForbiddenProviderInitialization([app.logPath, realtime.logPath])
375376

377+
seedAttempted = true
376378
await seedE2eWorld({
377379
...commandOptions,
378380
env: {
@@ -435,7 +437,7 @@ async function main(): Promise<void> {
435437
process.off('SIGINT', handleSigint)
436438
process.off('SIGTERM', handleSigterm)
437439

438-
if (runDatabase) {
440+
if (runDatabase && seedAttempted) {
439441
try {
440442
assertSeededScenarioManifestExists(manifestPath)
441443
await Promise.all([

apps/sim/e2e/support/sandbox-bundles.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { createHash } from 'node:crypto'
22
import { readFileSync } from 'node:fs'
33
import path from 'node:path'
4-
import { REPO_ROOT } from './paths'
4+
import { readAppResolvedPackageVersion } from '@/lib/execution/sandbox/bundles/dependency-resolution'
5+
import { REPO_ROOT, SIM_APP_DIR } from './paths'
56

67
const INTEGRITY_PATH = 'apps/sim/lib/execution/sandbox/bundles/integrity.json'
78

@@ -36,12 +37,10 @@ export function verifySandboxBundleIntegrity(options?: { runningBunVersion?: str
3637
verifyHashes('source', integrity.sources)
3738
verifyHashes('output', integrity.outputs)
3839
for (const [packageName, expectedVersion] of Object.entries(integrity.dependencies)) {
39-
const packageJson = readJson<{ version?: string }>(
40-
path.join(REPO_ROOT, 'node_modules', packageName, 'package.json')
41-
)
42-
if (packageJson.version !== expectedVersion) {
40+
const resolvedVersion = readAppResolvedPackageVersion(packageName, SIM_APP_DIR)
41+
if (resolvedVersion !== expectedVersion) {
4342
throw new Error(
44-
`Sandbox bundle dependency ${packageName} changed: expected ${expectedVersion}, received ${packageJson.version ?? 'missing'}`
43+
`Sandbox bundle dependency ${packageName} changed: expected ${expectedVersion}, received ${resolvedVersion}`
4544
)
4645
}
4746
}

apps/sim/lib/execution/sandbox/bundles/build.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
1515
import { dirname, isAbsolute, join, resolve } from 'node:path'
1616
import { fileURLToPath } from 'node:url'
1717
import { createLogger } from '@sim/logger'
18+
import { readAppResolvedPackageVersion } from './dependency-resolution'
1819

1920
const logger = createLogger('SandboxBundleBuild')
2021

@@ -37,7 +38,11 @@ const HERE = dirname(fileURLToPath(import.meta.url))
3738
const APP_SIM_ROOT = join(HERE, '..', '..', '..', '..')
3839
const REPO_ROOT = join(APP_SIM_ROOT, '..', '..')
3940
const INTEGRITY_PATH = join(HERE, 'integrity.json')
40-
const INTEGRITY_SOURCES = [join(HERE, 'build.ts'), join(HERE, '_polyfills.ts')] as const
41+
const INTEGRITY_SOURCES = [
42+
join(HERE, 'build.ts'),
43+
join(HERE, '_polyfills.ts'),
44+
join(HERE, 'dependency-resolution.ts'),
45+
] as const
4146
const INTEGRITY_DEPENDENCIES = ['pdf-lib', 'docx', 'pptxgenjs', 'buffer', 'process'] as const
4247

4348
interface BundleSpec {
@@ -187,8 +192,7 @@ function writeIntegrityManifest(): void {
187192
dependencies: Object.fromEntries(
188193
INTEGRITY_DEPENDENCIES.map((packageName) => [
189194
packageName,
190-
readJson<{ version: string }>(join(REPO_ROOT, 'node_modules', packageName, 'package.json'))
191-
.version,
195+
readAppResolvedPackageVersion(packageName, APP_SIM_ROOT),
192196
])
193197
),
194198
outputs: Object.fromEntries(
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { existsSync, readFileSync } from 'node:fs'
2+
import { createRequire } from 'node:module'
3+
import { dirname, join, parse } from 'node:path'
4+
5+
const PACKAGE_ENTRYPOINTS: Readonly<Record<string, string>> = {
6+
buffer: 'buffer/',
7+
process: 'process/browser',
8+
}
9+
10+
export function readAppResolvedPackageVersion(packageName: string, appRoot: string): string {
11+
const requireFromApp = createRequire(join(appRoot, 'package.json'))
12+
const entrypoint = requireFromApp.resolve(PACKAGE_ENTRYPOINTS[packageName] ?? packageName)
13+
let directory = dirname(entrypoint)
14+
const filesystemRoot = parse(directory).root
15+
16+
while (directory !== filesystemRoot) {
17+
const packageJsonPath = join(directory, 'package.json')
18+
if (existsSync(packageJsonPath)) {
19+
const manifest = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as {
20+
name?: string
21+
version?: string
22+
}
23+
if (manifest.name === packageName && manifest.version) return manifest.version
24+
}
25+
directory = dirname(directory)
26+
}
27+
28+
throw new Error(`Could not locate the package manifest resolved for ${packageName}`)
29+
}

apps/sim/lib/execution/sandbox/bundles/integrity.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
"schemaVersion": 1,
33
"bunVersion": "1.3.13",
44
"sources": {
5-
"apps/sim/lib/execution/sandbox/bundles/build.ts": "5ac7773ab65451f908fe54ba609978469117fcaa61cff47be973d7ba528a9982",
6-
"apps/sim/lib/execution/sandbox/bundles/_polyfills.ts": "131dd6e7aec37bff3acf6507d6fe7bc95aeabae07fa2e97bbf2e32aa7251d491"
5+
"apps/sim/lib/execution/sandbox/bundles/build.ts": "c4036e734738b44b5169c46a008f595c95a691865777117980cc13c5684f7580",
6+
"apps/sim/lib/execution/sandbox/bundles/_polyfills.ts": "131dd6e7aec37bff3acf6507d6fe7bc95aeabae07fa2e97bbf2e32aa7251d491",
7+
"apps/sim/lib/execution/sandbox/bundles/dependency-resolution.ts": "dac56d7744c09f8d577b575ffdbb4dfd219fb16918fc529f84b017f0ec9d1f3f"
78
},
89
"dependencies": {
910
"pdf-lib": "1.17.1",

apps/sim/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135
"better-auth": "1.6.23",
136136
"binary-extensions": "3.1.0",
137137
"browser-image-compression": "^2.0.2",
138+
"buffer": "6.0.3",
138139
"busboy": "1.6.0",
139140
"cheerio": "1.1.2",
140141
"class-variance-authority": "^0.7.1",
@@ -196,6 +197,7 @@
196197
"posthog-node": "5.28.9",
197198
"pptxgenjs": "4.0.1",
198199
"prismjs": "^1.30.0",
200+
"process": "0.11.10",
199201
"react": "19.2.4",
200202
"react-dom": "19.2.4",
201203
"react-hook-form": "^7.54.2",

bun.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)