From 1e6705ed39b18161cf874bffec5e0d3bd88710c9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 13 Aug 2026 09:02:56 +0900 Subject: [PATCH 01/13] test(release): expose checkout-backed root consumer evidence --- src/packedRootConsumerIsolation.test.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/packedRootConsumerIsolation.test.ts diff --git a/src/packedRootConsumerIsolation.test.ts b/src/packedRootConsumerIsolation.test.ts new file mode 100644 index 00000000..735317cd --- /dev/null +++ b/src/packedRootConsumerIsolation.test.ts @@ -0,0 +1,18 @@ +import { readFileSync } from 'node:fs'; + +import { describe, expect, it } from 'vitest'; + +const verifierSource = readFileSync( + new URL('../tests/package/verify-package.mjs', import.meta.url), + 'utf8', +); + +describe('packed root consumer release evidence', () => { + it('uses one real tarball and an isolated consumer package tree', () => { + expect(verifierSource).not.toContain("'--dry-run'"); + expect(verifierSource).toContain("'--pack-destination'"); + expect(verifierSource).toContain("'node_modules'"); + expect(verifierSource).toContain("join(extractionDirectory, 'package')"); + expect(verifierSource).toContain('cwd: consumerDirectory'); + }); +}); From 065346eb01a7ee4740ce4086c6cc15e8d91a7114 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 13 Aug 2026 09:06:10 +0900 Subject: [PATCH 02/13] test(release): reach packed-consumer isolation assertion --- src/packedRootConsumerIsolation.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/packedRootConsumerIsolation.test.ts b/src/packedRootConsumerIsolation.test.ts index 735317cd..f788b31d 100644 --- a/src/packedRootConsumerIsolation.test.ts +++ b/src/packedRootConsumerIsolation.test.ts @@ -1,9 +1,10 @@ import { readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; import { describe, expect, it } from 'vitest'; const verifierSource = readFileSync( - new URL('../tests/package/verify-package.mjs', import.meta.url), + resolve(process.cwd(), 'tests/package/verify-package.mjs'), 'utf8', ); From e9cf52a92ec14acd1f9330de04503fbd3d4f9dd3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 13 Aug 2026 09:22:04 +0900 Subject: [PATCH 03/13] fix(release): verify root consumers from packed tarball --- src/packedRootConsumerIsolation.test.ts | 7 ++- tests/package/verify-package.mjs | 72 +++++++++++++++++++------ 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/src/packedRootConsumerIsolation.test.ts b/src/packedRootConsumerIsolation.test.ts index f788b31d..6083c5d7 100644 --- a/src/packedRootConsumerIsolation.test.ts +++ b/src/packedRootConsumerIsolation.test.ts @@ -13,7 +13,12 @@ describe('packed root consumer release evidence', () => { expect(verifierSource).not.toContain("'--dry-run'"); expect(verifierSource).toContain("'--pack-destination'"); expect(verifierSource).toContain("'node_modules'"); - expect(verifierSource).toContain("join(extractionDirectory, 'package')"); expect(verifierSource).toContain('cwd: consumerDirectory'); + expect(verifierSource).toContain( + 'ESM root package must resolve from isolated consumer node_modules', + ); + expect(verifierSource).toContain( + 'CommonJS root package must resolve from isolated consumer node_modules', + ); }); }); diff --git a/tests/package/verify-package.mjs b/tests/package/verify-package.mjs index 82a03e31..b9ea20fb 100644 --- a/tests/package/verify-package.mjs +++ b/tests/package/verify-package.mjs @@ -2,12 +2,13 @@ import assert from 'node:assert/strict'; import { execFileSync } from 'node:child_process'; import { existsSync, + mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from 'node:fs'; -import { dirname, join, resolve } from 'node:path'; +import { basename, dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; const repositoryRoot = resolve( @@ -22,6 +23,12 @@ const packageName = packageJson.name; const verificationDirectory = mkdtempSync( join(repositoryRoot, '.package-verification-'), ); +const consumerDirectory = join(verificationDirectory, 'consumer'); +const packedPackageDirectory = join( + consumerDirectory, + 'node_modules', + ...packageName.split('/'), +); /** Execute a command from the repository root with inherited diagnostics. */ function run(command, argumentsList, options = {}) { @@ -128,14 +135,14 @@ function verifyPackedFiles(filePaths) { /** Write and execute an ESM or CommonJS package-consumer smoke test. */ function runConsumerSmokeTest(fileName, source) { - const smokeTestPath = join(verificationDirectory, fileName); + const smokeTestPath = join(consumerDirectory, fileName); writeFileSync(smokeTestPath, source, 'utf8'); - run(process.execPath, [smokeTestPath]); + run(process.execPath, [smokeTestPath], { cwd: consumerDirectory }); } /** Compile a strict TypeScript consumer against the packed public declarations. */ function verifyConsumerTypes() { - const consumerTypePath = join(verificationDirectory, 'consumer-types.ts'); + const consumerTypePath = join(consumerDirectory, 'consumer-types.ts'); writeFileSync( consumerTypePath, `import { @@ -311,16 +318,40 @@ void [ try { const packOutput = run('npm', [ 'pack', - '--dry-run', '--json', '--ignore-scripts', + '--pack-destination', + verificationDirectory, ]); - const packResult = JSON.parse(packOutput)[0]; + const packResults = JSON.parse(packOutput); + assert.equal(packResults.length, 1, 'npm pack must produce exactly one package'); + const [packResult] = packResults; assert.equal(packResult.name, packageName); assert.equal(packResult.version, packageJson.version); + assert.equal( + packResult.filename, + basename(packResult.filename), + 'npm pack filename must not contain path components', + ); + const packageArchivePath = join(verificationDirectory, packResult.filename); + assert.ok(existsSync(packageArchivePath), 'npm pack archive was not created'); const packedFiles = new Set(packResult.files.map(({ path }) => path)); verifyPackedFiles(packedFiles); + mkdirSync(packedPackageDirectory, { recursive: true }); + run('tar', [ + '-xzf', + packageArchivePath, + '--strip-components=1', + '-C', + packedPackageDirectory, + ]); + const extractedPackageJson = JSON.parse( + readFileSync(join(packedPackageDirectory, 'package.json'), 'utf8'), + ); + assert.equal(extractedPackageJson.name, packageName); + assert.equal(extractedPackageJson.version, packageJson.version); + runConsumerSmokeTest( 'consumer-esm.mjs', `import assert from 'node:assert/strict'; @@ -329,6 +360,12 @@ import * as autosave from '${packageName}/autosave'; import * as collaboration from '${packageName}/collaboration'; import * as converter from '${packageName}/converter'; +const packagePathFragment = '/node_modules/@contextualwisdomlab/cwl-editor/'; +const rootEntrypoint = import.meta.resolve('${packageName}'); +assert.ok( + rootEntrypoint.includes(packagePathFragment), + 'ESM root package must resolve from isolated consumer node_modules', +); assert.equal(typeof editor.markdownToHtml, 'function'); assert.equal(editor.validateSafeLinkHref('/documents/current'), '/documents/current'); assert.equal(typeof editor.restoreDocumentEnvelopeIfMatch, 'function'); @@ -343,6 +380,10 @@ assert.equal(typeof converter.bytesToDataUri, 'function'); for (const subpath of ['styles.css', 'fonts.css', 'fonts-latin.css']) { const resolved = import.meta.resolve('${packageName}/' + subpath); assert.ok(resolved.startsWith('file:')); + assert.ok( + resolved.includes(packagePathFragment), + 'ESM subpath must resolve from isolated consumer node_modules', + ); } `, ); @@ -355,6 +396,12 @@ const autosave = require('${packageName}/autosave'); const collaboration = require('${packageName}/collaboration'); const converter = require('${packageName}/converter'); +const packagePathFragment = '/node_modules/@contextualwisdomlab/cwl-editor/'; +const rootEntrypoint = require.resolve('${packageName}').replaceAll('\\\\', '/'); +assert.ok( + rootEntrypoint.includes(packagePathFragment), + 'CommonJS root package must resolve from isolated consumer node_modules', +); assert.equal(typeof editor.markdownToHtml, 'function'); assert.equal(editor.validateSafeLinkHref('/documents/current'), '/documents/current'); assert.equal(typeof editor.restoreDocumentEnvelopeIfMatch, 'function'); @@ -367,23 +414,16 @@ assert.equal(typeof collaboration.assertCollaborationConfiguration, 'function'); assert.ok(collaboration.CollaborativeCwlEditor); assert.equal(typeof converter.bytesToDataUri, 'function'); for (const subpath of ['styles.css', 'fonts.css', 'fonts-latin.css']) { - const resolved = require.resolve('${packageName}/' + subpath); - assert.ok(resolved.length > 0); + const resolved = require.resolve('${packageName}/' + subpath).replaceAll('\\\\', '/'); + assert.ok(resolved.includes(packagePathFragment)); } `, ); verifyConsumerTypes(); - for (const subpath of ['styles.css', 'fonts.css', 'fonts-latin.css']) { - const resolvedPath = fileURLToPath( - import.meta.resolve(`${packageName}/${subpath}`), - ); - assert.ok(existsSync(resolvedPath), `Export does not exist: ${subpath}`); - } - console.log( - `Verified ${packageName}@${packageJson.version}: npm contents, ESM, CommonJS, SSR-safe imports, subpath exports, and TypeScript declarations.`, + `Verified ${packageName}@${packageJson.version}: exact npm tarball contents, isolated ESM, CommonJS, SSR-safe imports, subpath exports, and TypeScript declarations.`, ); } finally { rmSync(verificationDirectory, { recursive: true, force: true }); From b907db8f546e0de9f90f86a20d142d2a4c4c1a41 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 13 Aug 2026 09:39:52 +0900 Subject: [PATCH 04/13] fix(release): isolate packed root package resolution --- tests/package/verify-package.mjs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/package/verify-package.mjs b/tests/package/verify-package.mjs index b9ea20fb..bbaf89fa 100644 --- a/tests/package/verify-package.mjs +++ b/tests/package/verify-package.mjs @@ -352,6 +352,20 @@ try { assert.equal(extractedPackageJson.name, packageName); assert.equal(extractedPackageJson.version, packageJson.version); + writeFileSync( + join(consumerDirectory, 'package.json'), + `${JSON.stringify( + { + name: 'inkspan-package-verification-consumer', + private: true, + type: 'module', + }, + null, + 2, + )}\n`, + 'utf8', + ); + runConsumerSmokeTest( 'consumer-esm.mjs', `import assert from 'node:assert/strict'; From e0da9e3fa6a3f8dca13fa929532ba4dd6afa1ffa Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 13 Aug 2026 09:40:47 +0900 Subject: [PATCH 05/13] test(release): preserve isolated consumer package scope --- src/packedRootConsumerIsolation.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/packedRootConsumerIsolation.test.ts b/src/packedRootConsumerIsolation.test.ts index 6083c5d7..3c0ee273 100644 --- a/src/packedRootConsumerIsolation.test.ts +++ b/src/packedRootConsumerIsolation.test.ts @@ -14,6 +14,12 @@ describe('packed root consumer release evidence', () => { expect(verifierSource).toContain("'--pack-destination'"); expect(verifierSource).toContain("'node_modules'"); expect(verifierSource).toContain('cwd: consumerDirectory'); + expect(verifierSource).toContain( + "join(consumerDirectory, 'package.json')", + ); + expect(verifierSource).toContain( + "name: 'inkspan-package-verification-consumer'", + ); expect(verifierSource).toContain( 'ESM root package must resolve from isolated consumer node_modules', ); From 4a90c2c311c6e0183265d81290dcaa5be6854533 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 06:45:08 +0900 Subject: [PATCH 06/13] test(release): isolate packed consumer from checkout dependencies --- src/packedRootConsumerIsolation.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/packedRootConsumerIsolation.test.ts b/src/packedRootConsumerIsolation.test.ts index 3c0ee273..b9025e3c 100644 --- a/src/packedRootConsumerIsolation.test.ts +++ b/src/packedRootConsumerIsolation.test.ts @@ -27,4 +27,12 @@ describe('packed root consumer release evidence', () => { 'CommonJS root package must resolve from isolated consumer node_modules', ); }); + + it('keeps the consumer outside the checkout dependency-resolution ancestry', () => { + expect(verifierSource).toContain("from 'node:os'"); + expect(verifierSource).toContain('tmpdir()'); + expect(verifierSource).not.toContain( + "join(repositoryRoot, '.package-verification-')", + ); + }); }); From ca9f3b2adb3fbc3204dc0589c793bc6a194dfe15 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 18:00:23 +0900 Subject: [PATCH 07/13] fix(release): isolate packed consumers outside checkout --- tests/package/verify-package.mjs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/package/verify-package.mjs b/tests/package/verify-package.mjs index bbaf89fa..b63b46e6 100644 --- a/tests/package/verify-package.mjs +++ b/tests/package/verify-package.mjs @@ -8,6 +8,7 @@ import { rmSync, writeFileSync, } from 'node:fs'; +import { tmpdir } from 'node:os'; import { basename, dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -21,7 +22,7 @@ const packageJson = JSON.parse( ); const packageName = packageJson.name; const verificationDirectory = mkdtempSync( - join(repositoryRoot, '.package-verification-'), + join(tmpdir(), 'inkspan-package-verification-'), ); const consumerDirectory = join(verificationDirectory, 'consumer'); const packedPackageDirectory = join( @@ -441,4 +442,4 @@ for (const subpath of ['styles.css', 'fonts.css', 'fonts-latin.css']) { ); } finally { rmSync(verificationDirectory, { recursive: true, force: true }); -} +} \ No newline at end of file From 53ffd2ede7c4af0e970b48f591c14ec6f6e0d9f1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 18:04:44 +0900 Subject: [PATCH 08/13] test(release): require external frozen dependency substrate --- src/packedRootConsumerIsolation.test.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/packedRootConsumerIsolation.test.ts b/src/packedRootConsumerIsolation.test.ts index b9025e3c..ec3e3ba3 100644 --- a/src/packedRootConsumerIsolation.test.ts +++ b/src/packedRootConsumerIsolation.test.ts @@ -35,4 +35,14 @@ describe('packed root consumer release evidence', () => { "join(repositoryRoot, '.package-verification-')", ); }); + + it('reuses only the frozen dependency substrate outside the packed package tree', () => { + expect(verifierSource).toContain('symlinkSync('); + expect(verifierSource).toContain( + "join(repositoryRoot, 'node_modules')", + ); + expect(verifierSource).toContain( + "join(verificationDirectory, 'node_modules')", + ); + }); }); From f8e40269e76827b2fcfdee8178f4d8bd0fe2f631 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 18:09:15 +0900 Subject: [PATCH 09/13] fix(release): provide frozen deps to isolated consumers --- tests/package/verify-package.mjs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/package/verify-package.mjs b/tests/package/verify-package.mjs index b63b46e6..57c1cacb 100644 --- a/tests/package/verify-package.mjs +++ b/tests/package/verify-package.mjs @@ -6,6 +6,7 @@ import { mkdtempSync, readFileSync, rmSync, + symlinkSync, writeFileSync, } from 'node:fs'; import { tmpdir } from 'node:os'; @@ -317,6 +318,12 @@ void [ } try { + symlinkSync( + join(repositoryRoot, 'node_modules'), + join(verificationDirectory, 'node_modules'), + 'dir', + ); + const packOutput = run('npm', [ 'pack', '--json', @@ -442,4 +449,4 @@ for (const subpath of ['styles.css', 'fonts.css', 'fonts-latin.css']) { ); } finally { rmSync(verificationDirectory, { recursive: true, force: true }); -} \ No newline at end of file +} From 4bb758959df4d7d2f56e693a1053c3a58b2cc728 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 19:30:44 +0900 Subject: [PATCH 10/13] test(package): require canonical tarball containment --- src/packedRootConsumerIsolation.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/packedRootConsumerIsolation.test.ts b/src/packedRootConsumerIsolation.test.ts index ec3e3ba3..80ffe59f 100644 --- a/src/packedRootConsumerIsolation.test.ts +++ b/src/packedRootConsumerIsolation.test.ts @@ -45,4 +45,12 @@ describe('packed root consumer release evidence', () => { "join(verificationDirectory, 'node_modules')", ); }); + + it('proves resolved entrypoints are canonically contained by the extracted package', () => { + expect(verifierSource).toContain('realpathSync'); + expect(verifierSource).toContain('relative('); + expect(verifierSource).toContain('isAbsolute('); + expect(verifierSource).toContain('assertResolvedInsidePackedPackage'); + expect(verifierSource).not.toContain('includes(packagePathFragment)'); + }); }); From a8ccf965027431ed1e7a7b4064ec7ec4b9e6db1e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 19:36:27 +0900 Subject: [PATCH 11/13] fix(package): prove canonical tarball containment --- tests/package/verify-package.mjs | 56 +++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/tests/package/verify-package.mjs b/tests/package/verify-package.mjs index 57c1cacb..01b3649d 100644 --- a/tests/package/verify-package.mjs +++ b/tests/package/verify-package.mjs @@ -377,15 +377,31 @@ try { runConsumerSmokeTest( 'consumer-esm.mjs', `import assert from 'node:assert/strict'; +import { realpathSync } from 'node:fs'; +import { isAbsolute, join, relative, sep } from 'node:path'; +import { fileURLToPath } from 'node:url'; import * as editor from '${packageName}'; import * as autosave from '${packageName}/autosave'; import * as collaboration from '${packageName}/collaboration'; import * as converter from '${packageName}/converter'; -const packagePathFragment = '/node_modules/@contextualwisdomlab/cwl-editor/'; +const packedPackageRoot = realpathSync( + join(process.cwd(), 'node_modules', ...'${packageName}'.split('/')), +); +function assertResolvedInsidePackedPackage(resolved, message) { + const resolvedPath = realpathSync(fileURLToPath(resolved)); + const relativePath = relative(packedPackageRoot, resolvedPath); + assert.ok( + relativePath !== '' && + relativePath !== '..' && + !relativePath.startsWith('..' + sep) && + !isAbsolute(relativePath), + message, + ); +} const rootEntrypoint = import.meta.resolve('${packageName}'); -assert.ok( - rootEntrypoint.includes(packagePathFragment), +assertResolvedInsidePackedPackage( + rootEntrypoint, 'ESM root package must resolve from isolated consumer node_modules', ); assert.equal(typeof editor.markdownToHtml, 'function'); @@ -402,8 +418,8 @@ assert.equal(typeof converter.bytesToDataUri, 'function'); for (const subpath of ['styles.css', 'fonts.css', 'fonts-latin.css']) { const resolved = import.meta.resolve('${packageName}/' + subpath); assert.ok(resolved.startsWith('file:')); - assert.ok( - resolved.includes(packagePathFragment), + assertResolvedInsidePackedPackage( + resolved, 'ESM subpath must resolve from isolated consumer node_modules', ); } @@ -413,15 +429,30 @@ for (const subpath of ['styles.css', 'fonts.css', 'fonts-latin.css']) { runConsumerSmokeTest( 'consumer-commonjs.cjs', `const assert = require('node:assert/strict'); +const { realpathSync } = require('node:fs'); +const { isAbsolute, join, relative, sep } = require('node:path'); const editor = require('${packageName}'); const autosave = require('${packageName}/autosave'); const collaboration = require('${packageName}/collaboration'); const converter = require('${packageName}/converter'); -const packagePathFragment = '/node_modules/@contextualwisdomlab/cwl-editor/'; -const rootEntrypoint = require.resolve('${packageName}').replaceAll('\\\\', '/'); -assert.ok( - rootEntrypoint.includes(packagePathFragment), +const packedPackageRoot = realpathSync( + join(process.cwd(), 'node_modules', ...'${packageName}'.split('/')), +); +function assertResolvedInsidePackedPackage(resolved, message) { + const resolvedPath = realpathSync(resolved); + const relativePath = relative(packedPackageRoot, resolvedPath); + assert.ok( + relativePath !== '' && + relativePath !== '..' && + !relativePath.startsWith('..' + sep) && + !isAbsolute(relativePath), + message, + ); +} +const rootEntrypoint = require.resolve('${packageName}'); +assertResolvedInsidePackedPackage( + rootEntrypoint, 'CommonJS root package must resolve from isolated consumer node_modules', ); assert.equal(typeof editor.markdownToHtml, 'function'); @@ -436,8 +467,11 @@ assert.equal(typeof collaboration.assertCollaborationConfiguration, 'function'); assert.ok(collaboration.CollaborativeCwlEditor); assert.equal(typeof converter.bytesToDataUri, 'function'); for (const subpath of ['styles.css', 'fonts.css', 'fonts-latin.css']) { - const resolved = require.resolve('${packageName}/' + subpath).replaceAll('\\\\', '/'); - assert.ok(resolved.includes(packagePathFragment)); + const resolved = require.resolve('${packageName}/' + subpath); + assertResolvedInsidePackedPackage( + resolved, + 'CommonJS subpath must resolve from isolated consumer node_modules', + ); } `, ); From 1f331e62a444c32abf74a77781cfec16241764d5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 21:00:49 -0700 Subject: [PATCH 12/13] test(release): pin validated packed module loading --- src/packedRootConsumerIsolation.test.ts | 56 +++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/packedRootConsumerIsolation.test.ts b/src/packedRootConsumerIsolation.test.ts index 80ffe59f..af7baa29 100644 --- a/src/packedRootConsumerIsolation.test.ts +++ b/src/packedRootConsumerIsolation.test.ts @@ -53,4 +53,60 @@ describe('packed root consumer release evidence', () => { expect(verifierSource).toContain('assertResolvedInsidePackedPackage'); expect(verifierSource).not.toContain('includes(packagePathFragment)'); }); + + it('executes only the exact canonical module entries that passed containment validation', () => { + expect(verifierSource).toContain( + "import { fileURLToPath, pathToFileURL } from 'node:url';", + ); + expect(verifierSource).not.toContain( + "import * as editor from '${packageName}';", + ); + expect(verifierSource).not.toContain( + "import * as autosave from '${packageName}/autosave';", + ); + expect(verifierSource).not.toContain( + "import * as collaboration from '${packageName}/collaboration';", + ); + expect(verifierSource).not.toContain( + "import * as converter from '${packageName}/converter';", + ); + expect(verifierSource).toContain( + "const rootEntrypoint = assertResolvedInsidePackedPackage(\n import.meta.resolve('${packageName}')", + ); + expect(verifierSource).toContain( + 'const editor = await import(pathToFileURL(rootEntrypoint).href);', + ); + expect(verifierSource).toContain( + 'const autosave = await import(pathToFileURL(autosaveEntrypoint).href);', + ); + expect(verifierSource).toContain( + 'const collaboration = await import(\n pathToFileURL(collaborationEntrypoint).href\n);', + ); + expect(verifierSource).toContain( + 'const converter = await import(pathToFileURL(converterEntrypoint).href);', + ); + + expect(verifierSource).not.toContain( + "const editor = require('${packageName}');", + ); + expect(verifierSource).not.toContain( + "const autosave = require('${packageName}/autosave');", + ); + expect(verifierSource).not.toContain( + "const collaboration = require('${packageName}/collaboration');", + ); + expect(verifierSource).not.toContain( + "const converter = require('${packageName}/converter');", + ); + expect(verifierSource).toContain('const editor = require(rootEntrypoint);'); + expect(verifierSource).toContain( + 'const autosave = require(autosaveEntrypoint);', + ); + expect(verifierSource).toContain( + 'const collaboration = require(collaborationEntrypoint);', + ); + expect(verifierSource).toContain( + 'const converter = require(converterEntrypoint);', + ); + }); }); From 147f317ca07d8fccf6b69ff220aba0bf971837ce Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 21:03:29 -0700 Subject: [PATCH 13/13] fix(release): execute only validated packed entries --- tests/package/verify-package.mjs | 56 +++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/tests/package/verify-package.mjs b/tests/package/verify-package.mjs index 01b3649d..eb641c15 100644 --- a/tests/package/verify-package.mjs +++ b/tests/package/verify-package.mjs @@ -379,11 +379,7 @@ try { `import assert from 'node:assert/strict'; import { realpathSync } from 'node:fs'; import { isAbsolute, join, relative, sep } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import * as editor from '${packageName}'; -import * as autosave from '${packageName}/autosave'; -import * as collaboration from '${packageName}/collaboration'; -import * as converter from '${packageName}/converter'; +import { fileURLToPath, pathToFileURL } from 'node:url'; const packedPackageRoot = realpathSync( join(process.cwd(), 'node_modules', ...'${packageName}'.split('/')), @@ -398,12 +394,30 @@ function assertResolvedInsidePackedPackage(resolved, message) { !isAbsolute(relativePath), message, ); + return resolvedPath; } -const rootEntrypoint = import.meta.resolve('${packageName}'); -assertResolvedInsidePackedPackage( - rootEntrypoint, +const rootEntrypoint = assertResolvedInsidePackedPackage( + import.meta.resolve('${packageName}'), 'ESM root package must resolve from isolated consumer node_modules', ); +const autosaveEntrypoint = assertResolvedInsidePackedPackage( + import.meta.resolve('${packageName}/autosave'), + 'ESM autosave package must resolve from isolated consumer node_modules', +); +const collaborationEntrypoint = assertResolvedInsidePackedPackage( + import.meta.resolve('${packageName}/collaboration'), + 'ESM collaboration package must resolve from isolated consumer node_modules', +); +const converterEntrypoint = assertResolvedInsidePackedPackage( + import.meta.resolve('${packageName}/converter'), + 'ESM converter package must resolve from isolated consumer node_modules', +); +const editor = await import(pathToFileURL(rootEntrypoint).href); +const autosave = await import(pathToFileURL(autosaveEntrypoint).href); +const collaboration = await import( + pathToFileURL(collaborationEntrypoint).href +); +const converter = await import(pathToFileURL(converterEntrypoint).href); assert.equal(typeof editor.markdownToHtml, 'function'); assert.equal(editor.validateSafeLinkHref('/documents/current'), '/documents/current'); assert.equal(typeof editor.restoreDocumentEnvelopeIfMatch, 'function'); @@ -431,10 +445,6 @@ for (const subpath of ['styles.css', 'fonts.css', 'fonts-latin.css']) { `const assert = require('node:assert/strict'); const { realpathSync } = require('node:fs'); const { isAbsolute, join, relative, sep } = require('node:path'); -const editor = require('${packageName}'); -const autosave = require('${packageName}/autosave'); -const collaboration = require('${packageName}/collaboration'); -const converter = require('${packageName}/converter'); const packedPackageRoot = realpathSync( join(process.cwd(), 'node_modules', ...'${packageName}'.split('/')), @@ -449,12 +459,28 @@ function assertResolvedInsidePackedPackage(resolved, message) { !isAbsolute(relativePath), message, ); + return resolvedPath; } -const rootEntrypoint = require.resolve('${packageName}'); -assertResolvedInsidePackedPackage( - rootEntrypoint, +const rootEntrypoint = assertResolvedInsidePackedPackage( + require.resolve('${packageName}'), 'CommonJS root package must resolve from isolated consumer node_modules', ); +const autosaveEntrypoint = assertResolvedInsidePackedPackage( + require.resolve('${packageName}/autosave'), + 'CommonJS autosave package must resolve from isolated consumer node_modules', +); +const collaborationEntrypoint = assertResolvedInsidePackedPackage( + require.resolve('${packageName}/collaboration'), + 'CommonJS collaboration package must resolve from isolated consumer node_modules', +); +const converterEntrypoint = assertResolvedInsidePackedPackage( + require.resolve('${packageName}/converter'), + 'CommonJS converter package must resolve from isolated consumer node_modules', +); +const editor = require(rootEntrypoint); +const autosave = require(autosaveEntrypoint); +const collaboration = require(collaborationEntrypoint); +const converter = require(converterEntrypoint); assert.equal(typeof editor.markdownToHtml, 'function'); assert.equal(editor.validateSafeLinkHref('/documents/current'), '/documents/current'); assert.equal(typeof editor.restoreDocumentEnvelopeIfMatch, 'function');