Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 8 additions & 2 deletions apps/editor/scripts/native/install-inputs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,14 @@ export async function prepareInstall(plan,root=process.cwd(),fetchImpl=fetch) {
const alias='@mdbase-dev/sdk-staging@'+stagingPath;
// pnpm's file alias must name the actual archive package, including UI peers.
// Keep the application import name @mdbase-dev/sdk, not the production identity.
const staged=lock.replaceAll(basename(plan.sdkTrust.production.path),'sdk-staging.tgz')
.replaceAll(plan.sdkTrust.production.sri,archive.sri)
// Other workspace packages may resolve the byte-identical registry SDK with the same
// integrity, so change only the vendored entry's own resolution, never the SRI globally.
const productionFile='file:apps/editor/vendor/'+basename(plan.sdkTrust.production.path);
const resolution=(sri,file)=>`\n '@mdbase-dev/sdk@${file}':\n resolution: {integrity: ${sri}, tarball: ${file}}\n`;
const vendored=resolution(plan.sdkTrust.production.sri,productionFile);
if(lock.split(vendored).length!==2)throw Error('Vendored SDK lock entry not found exactly once');
const staged=lock.replace(vendored,()=>resolution(archive.sri,productionFile))
.replaceAll(basename(plan.sdkTrust.production.path),'sdk-staging.tgz')
.replaceAll('@mdbase-dev/sdk@'+stagingPath,alias)
.replaceAll('version: '+stagingPath,"version: '"+alias+"'")
.replaceAll("'@mdbase-dev/sdk': "+stagingPath,"'@mdbase-dev/sdk': '"+alias+"'");
Expand Down
40 changes: 39 additions & 1 deletion apps/editor/scripts/native/publisher.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,11 @@ it('derives the staging frozen install without changing any other dependency',as
const pkg=JSON.parse(await readFile(join(f.app,'package.json'),'utf8'));
assert.equal(pkg.dependencies['@mdbase-dev/sdk'],'file:vendor/sdk-staging.tgz');
const lock=await readFile(join(f.root,'pnpm-lock.yaml'),'utf8');
assert.ok(lock.includes('sha512-staging'));assert.ok(!lock.includes(plan.sdkTrust.production.sri));
assert.ok(lock.includes('sha512-staging'));
const parsed=parse(lock),vendored=parsed.packages['@mdbase-dev/sdk-staging@file:apps/editor/vendor/sdk-staging.tgz'];
assert.equal(vendored.resolution.integrity,'sha512-staging');
for(const [key,entry] of Object.entries(parsed.packages))if(key!=='@mdbase-dev/sdk-staging@file:apps/editor/vendor/sdk-staging.tgz')
assert.notEqual(entry.resolution.integrity,'sha512-staging',key);
const stagingPath='file:apps/editor/vendor/sdk-staging.tgz',alias='@mdbase-dev/sdk-staging@'+stagingPath;
assert.equal(parse(lock).importers['apps/editor'].dependencies['@mdbase-dev/sdk'].version,alias);
const restored=lock.replaceAll("version: '"+alias+"'",'version: '+stagingPath)
Expand All @@ -137,6 +141,40 @@ it('derives the staging frozen install without changing any other dependency',as
assert.deepEqual(pkg,originalPackage);
}finally{await rm(f.root,{recursive:true,force:true});}
});
it('rewrites only the vendored SDK entry when a registry SDK shares its integrity',async()=>{
const root=await mkdtemp(join(tmpdir(),'editor-shared-sri-'));
try {
const productionSri='sha512-shared',file='file:apps/editor/vendor/sdk-production.tgz';
await mkdir(join(root,'apps/editor/vendor'),{recursive:true});
await writeFile(join(root,'apps/editor/package.json'),JSON.stringify({dependencies:{'@mdbase-dev/sdk':'file:vendor/sdk-production.tgz'}}));
const lock=["lockfileVersion: '9.0'",'','importers:','',' apps/editor:',' dependencies:'," '@mdbase-dev/sdk':",
' specifier: file:vendor/sdk-production.tgz',' version: '+file,'',' packages/app-ui:',' dependencies:',
" '@mdbase-dev/sdk':",' specifier: 0.1.0-beta.188',' version: 0.1.0-beta.188','','packages:','',
" '@mdbase-dev/sdk@0.1.0-beta.188':",` resolution: {integrity: ${productionSri}}`,'',
` '@mdbase-dev/sdk@${file}':`,` resolution: {integrity: ${productionSri}, tarball: ${file}}`,' version: 0.1.0-beta.188','',
'snapshots:',''," '@mdbase-dev/sdk@0.1.0-beta.188': {}",'',` '@mdbase-dev/sdk@${file}': {}`,''].join('\n');
await writeFile(join(root,'pnpm-lock.yaml'),lock);
const bytes=Buffer.from('authenticated staging archive');
const plan={target:'staging',sdkTrust:{lockSha256:sha(lock),production:{path:'apps/editor/vendor/sdk-production.tgz',sri:productionSri},
archives:{sdk:{path:'https://example.invalid/sdk-staging.tgz',sha256:sha(bytes),sri:'sha512-staging'}}}};
await prepareInstall(plan,root,async()=>new Response(bytes));
const staged=parse(await readFile(join(root,'pnpm-lock.yaml'),'utf8'));
const alias='@mdbase-dev/sdk-staging@file:apps/editor/vendor/sdk-staging.tgz';
assert.deepEqual(staged.packages,{
'@mdbase-dev/sdk@0.1.0-beta.188':{resolution:{integrity:productionSri}},
[alias]:{resolution:{integrity:'sha512-staging',tarball:'file:apps/editor/vendor/sdk-staging.tgz'},version:'0.1.0-beta.188'}});
assert.equal(staged.importers['packages/app-ui'].dependencies['@mdbase-dev/sdk'].version,'0.1.0-beta.188');
assert.equal(staged.importers['apps/editor'].dependencies['@mdbase-dev/sdk'].version,alias);
for(const broken of [lock.replace(`integrity: ${productionSri}, tarball`,'integrity: sha512-other, tarball'),
lock+`\n '@mdbase-dev/sdk@${file}':\n resolution: {integrity: ${productionSri}, tarball: ${file}}\n`]) {
await writeFile(join(root,'pnpm-lock.yaml'),broken);
await writeFile(join(root,'apps/editor/package.json'),JSON.stringify({dependencies:{'@mdbase-dev/sdk':'file:vendor/sdk-production.tgz'}}));
await assert.rejects(prepareInstall({...plan,sdkTrust:{...plan.sdkTrust,lockSha256:sha(broken)}},root,async()=>new Response(bytes)),
/Vendored SDK lock entry not found exactly once/);
assert.equal(await readFile(join(root,'pnpm-lock.yaml'),'utf8'),broken);
}
}finally{await rm(root,{recursive:true,force:true});}
});
it('uses authenticated assets for staging installation and installed-byte comparison',async context=>{
const fixture=await originalsFixture(),previous=process.env.GITHUB_TOKEN;
process.env.GITHUB_TOKEN='test-job-token';
Expand Down
Loading