Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
1e6705e
test(release): expose checkout-backed root consumer evidence
seonghobae Aug 13, 2026
065346e
test(release): reach packed-consumer isolation assertion
seonghobae Aug 13, 2026
e9cf52a
fix(release): verify root consumers from packed tarball
seonghobae Aug 13, 2026
b907db8
fix(release): isolate packed root package resolution
seonghobae Aug 13, 2026
e0da9e3
test(release): preserve isolated consumer package scope
seonghobae Aug 13, 2026
4a90c2c
test(release): isolate packed consumer from checkout dependencies
seonghobae Aug 13, 2026
ca9f3b2
fix(release): isolate packed consumers outside checkout
seonghobae Aug 15, 2026
53ffd2e
test(release): require external frozen dependency substrate
seonghobae Aug 15, 2026
f8e4026
fix(release): provide frozen deps to isolated consumers
seonghobae Aug 15, 2026
4bb7589
test(package): require canonical tarball containment
seonghobae Aug 15, 2026
a8ccf96
fix(package): prove canonical tarball containment
seonghobae Aug 15, 2026
bfdd218
chore: synchronize packed-package verification with protected main
seonghobae Aug 17, 2026
1f331e6
test(release): pin validated packed module loading
seonghobae Aug 21, 2026
147f317
fix(release): execute only validated packed entries
seonghobae Aug 21, 2026
012c7f0
merge: synchronize packed root consumer verifier with protected main
seonghobae Aug 25, 2026
49aec2a
Merge commit 'a40b9489665bed7d95af619a6079b9c51cab299a' into HEAD
seonghobae Sep 4, 2026
3f9e77f
test(ci): cover event-specific Python matrix
seonghobae Sep 4, 2026
fab480b
test(ci): bind Python matrix to event
seonghobae Sep 4, 2026
4512a2f
revert(ci): restore Office contract owner
seonghobae Sep 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions src/packedRootConsumerIsolation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';

import { describe, expect, it } from 'vitest';

const verifierSource = readFileSync(
resolve(process.cwd(), 'tests/package/verify-package.mjs'),
'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('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',
);
expect(verifierSource).toContain(
'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-')",
);
});

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')",
);
});

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)');
});

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);',
);
});
});
170 changes: 146 additions & 24 deletions tests/package/verify-package.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ import assert from 'node:assert/strict';
import { execFileSync } from 'node:child_process';
import {
existsSync,
mkdirSync,
mkdtempSync,
readFileSync,
rmSync,
symlinkSync,
writeFileSync,
} from 'node:fs';
import { dirname, join, resolve } from 'node:path';
import { tmpdir } from 'node:os';
import { basename, dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const repositoryRoot = resolve(
Expand All @@ -20,7 +23,13 @@ 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(
consumerDirectory,
'node_modules',
...packageName.split('/'),
);

/** Execute a command from the repository root with inherited diagnostics. */
Expand Down Expand Up @@ -128,14 +137,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 {
Expand Down Expand Up @@ -309,26 +318,106 @@ void [
}

try {
symlinkSync(
join(repositoryRoot, 'node_modules'),
join(verificationDirectory, 'node_modules'),
'dir',
);

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);

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';
import * as editor from '${packageName}';
import * as autosave from '${packageName}/autosave';
import * as collaboration from '${packageName}/collaboration';
import * as converter from '${packageName}/converter';
import { realpathSync } from 'node:fs';
import { isAbsolute, join, relative, sep } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';

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,
);
return resolvedPath;
}
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');
Expand All @@ -343,18 +432,55 @@ 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:'));
assertResolvedInsidePackedPackage(
resolved,
'ESM subpath must resolve from isolated consumer node_modules',
);
}
`,
);

runConsumerSmokeTest(
'consumer-commonjs.cjs',
`const assert = require('node:assert/strict');
const editor = require('${packageName}');
const autosave = require('${packageName}/autosave');
const collaboration = require('${packageName}/collaboration');
const converter = require('${packageName}/converter');
const { realpathSync } = require('node:fs');
const { isAbsolute, join, relative, sep } = require('node:path');

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,
);
return resolvedPath;
}
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');
Expand All @@ -368,22 +494,18 @@ 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);
assertResolvedInsidePackedPackage(
resolved,
'CommonJS subpath must resolve from isolated consumer node_modules',
);
}
`,
);

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 });
Expand Down
Loading