Files
exact/scripts/deploy.test.mjs
Charlie CheeverandClaude Opus 5.5 f96e400f13 Deploy starts an Android stream from the production APK's receipt
LLP 1030.007 D4, D5. Deploy published to an Android stream that already
had a head but started none, and told the developer to run push instead.
The launcher now passes the app's production Android receipts to the
captured process, and `streams` starts a stream from one with no head, as
it does for push: the row's cohort is the APK's, and a note names the
receipt that anchors it.

Android's binary rows say "new APK needed" with the command that builds
one: no stream and no receipt, `deploy.store.android` "0", or native
evidence that differs from the APK's. When the data crate the binary runs
has changed (`dataCrate` moved), deploy withholds the bundle from that
stream, since the plan's first frame was baked by the new crate.

Verified: bun test scripts/deploy.test.mjs scripts/push.test.mjs; on an
Android 37.2 emulator, deploy --yes published an edit to the stream push
had started, and on a fresh origin deploy alone started the stream from
the receipt; both arrived. A data-crate edit showed a binary row and no
bundle.

Part of #588

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-15 02:25:58 -08:00

1309 lines
96 KiB
JavaScript

// The publisher and its origin, driven: stream heads, admission and sequence
// allocation, classification tables, signing keys, source snapshots, stream
// commits and origin handles (`scripts/deploy.mjs`, `scripts/origin.mjs`).
// `bun test ./scripts/deploy.test.mjs`.
import { expect, test } from 'bun:test';
// These cases run cargo (the filesystem tool, bakes, locks). A shell whose PATH
// omits rustup's bin directory still finds it there; without cargo, say so.
const cargoBin = `${process.env.CARGO_HOME ?? `${process.env.HOME}/.cargo`}/bin`;
if (!(process.env.PATH ?? '').split(':').includes(cargoBin)) process.env.PATH = `${process.env.PATH ?? ''}:${cargoBin}`;
if (!Bun.which('cargo', { PATH: process.env.PATH })) throw new Error(`these tests need cargo: put it on PATH or in ${cargoBin}`);
// The fixtures name their apps; a caller's EXACT_APP_DIR would redirect every one.
delete process.env.EXACT_APP_DIR;
import { spawn, spawnSync } from 'node:child_process';
import { createHash, createPrivateKey, createPublicKey, generateKeyPairSync, sign as cryptoSign } from 'node:crypto';
import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readlinkSync, realpathSync, renameSync, writeFileSync, rmSync, symlinkSync, utimesSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { isAbsolute, join, dirname, relative, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { captureAssets, assetCards, copyStaticTreeIfPresent, webEnvelope, publicFileCards, listAssets, readStaticFile, readDevGeneration, retainDevGeneration } from '../host/web/serve.mjs';
import { resolveApp, webGpuArtifacts, withAppFixture } from './app.mjs';
import { streamBundle } from './texture-families.mjs';
import { bake, sealEnvelope, canonicalBytes, classify, classifyArtifacts, cohortReceipt, deployRun, holdBundles, inspectHead, disposeSnapshot, materializeSnapshot, readAssetIndex, portableAssetNames, publishRoot, renderTable, snapshotOf as capturedSnapshotOf } from './deploy.mjs';
import { defaultRelease, publishStream, streamHead, streamIndex } from './publisher.mjs';
import { blobPath, DirectoryOrigin, HttpsOrigin, OriginUnavailable, sha256, webReleasePath, webRootPath } from './origin.mjs';
// Minimal compiler receipts for origin protocol fixtures below; capability
// behavior is tested independently with declared requirements.
const fixtureBuild = (id, bundle) => ({version:1,compat:{id,inputs:{store:{L:'A'},executors:[]},target:'fixture'},
graph:{version:1,sources:{},artifacts:[{name:'app.plan',requires:{},sha256:bundle.plan.sha256,bytes:bundle.plan.bytes?.length??0}]},binary:{sha256:'0'.repeat(64)}});
const DEPLOY = join(dirname(fileURLToPath(import.meta.url)), 'deploy.mjs');
test('deployment ships the web GPU product with an inherited gpu-dev proof profile', async () => {
const root = resolve(import.meta.dir, '..'), app = resolveApp('beacons');
const run = deployRun(app.target, 'profile');
const previous = process.env.EXACT_GAME_PROOF_PROFILE;
try {
process.env.EXACT_GAME_PROOF_PROFILE = 'gpu-dev';
const web = bake(app, run, root, root);
const receipt = JSON.parse(readFileSync(join(web, 'bake.json')));
expect(receipt.trust).toBe('production');
const products = receipt.products.map(p => p.path);
expect(products).toContain(join(app.target, 'wasm32-unknown-unknown/web/beacons_gpu.wasm'));
expect(products).not.toContain(join(app.target, 'wasm32-unknown-unknown/gpu-dev/beacons_gpu.wasm'));
const expected = join(run, 'shipping');
mkdirSync(expected);
webGpuArtifacts(app, expected, { profile: 'web' });
const origin = new DirectoryOrigin(join(run, 'origin'));
await publishRoot({ origin, row: {}, web });
const pointer = JSON.parse(await origin.get(webRootPath));
const shipped = await origin.get(`${webReleasePath(pointer.id)}/gpu_bg.wasm`);
expect(shipped).toEqual(readFileSync(join(expected, 'gpu_bg.wasm')));
expect(process.env.EXACT_GAME_PROOF_PROFILE).toBe('gpu-dev');
} finally {
if (previous === undefined) delete process.env.EXACT_GAME_PROOF_PROFILE;
else process.env.EXACT_GAME_PROOF_PROFILE = previous;
rmSync(run, { recursive: true, force: true });
}
}, 600000);
// Each case is checked while the file loads and reported as a bun:test test.
function result(name, ok, detail = '') {
test(name, () => { if (!ok) throw new Error(detail || `${name}: failed`); });
}
async function rejects(action, matches) {
try { await action(); return false; } catch (error) { return matches(error); }
}
{
const id = 'com.exact.names';
const bytes = Buffer.alloc(36 + Buffer.byteLength(id));
bytes.write('EXPL'); bytes.writeUInt32LE(4, 4); bytes.writeBigUInt64LE(1n, 16);
bytes.writeUInt32LE(Buffer.byteLength(id), 32); bytes.write(id, 36);
const app = { name: 'internal-slug', id, displayName: 'Cross-platform Display', manifest: { name: 'Web Install Name' } };
const web = webEnvelope(app, bytes, []);
const mismatchedPlanRefused = await rejects(() => webEnvelope({ ...app, id: 'com.exact.another' }, bytes, []), error => error.message.includes(`plan is for ${id}`));
const stream = streamHead({ app, bundle: { plan: { bytes, sha256: web.plan.sha256, formatVersion: 4, kernelSchema: '0000000000000001' }, assets: [] },
stream: { channel: 'prod', compatibilityId: 'a'.repeat(32) }, seq: 1, release: 'test' });
result('web and stream envelopes use the cross-platform display name', app.name !== app.manifest.name
&& app.manifest.name !== app.displayName && web.app.name === app.displayName
&& stream.app.name === web.app.name && mismatchedPlanRefused);
}
// "Current" means the production client admits the complete authenticated
// head. An unusable head contributes no rollback floor: repair advances from
// the largest immutable record whose embedded envelope verifies, or refuses
// when no such history exists. Raw JSON spellings rejected by Rust are also
// rejected before JavaScript can normalize them. The locked publisher repeats
// the same admission in case the head changed after the table was printed.
{
const dir = mkdtempSync(join(tmpdir(), 'exact-head-admission-'));
const compatibilityId = 'a'.repeat(32);
const stream = { channel: 'prod', compatibilityId };
const { privateKey, publicKey } = generateKeyPairSync('ed25519');
const publicRaw = publicKey.export({ type: 'spki', format: 'der' }).subarray(-32).toString('base64');
const app = { id: 'com.exact.admission', displayName: 'Admission', dir,
manifest: { deploy: { signing: { key: 'test', keys: { test: publicRaw } } } } };
const planBytes = Buffer.from('same plan');
const assetBytes = Buffer.from('same asset');
const bundle = {
plan: { bytes: planBytes, sha256: createHash('sha256').update(planBytes).digest('hex'), formatVersion: 4, kernelSchema: '0'.repeat(16) },
assets: [{ name: 'assets/icon.png', bytes: assetBytes, sha256: createHash('sha256').update(assetBytes).digest('hex') }],
};
const signer = { keyId: 'test', sign: (head) => ({ keyId: 'test', ed25519: cryptoSign(null, canonicalBytes(head), privateKey).toString('base64') }) };
const signed = (edit = () => {}) => {
const head = streamHead({ app, bundle, stream, seq: 7, release: 'old' });
head.cohort = cohortReceipt(fixtureBuild(compatibilityId,bundle));
edit(head);
head.signature = signer.sign(head);
return head;
};
const found = (head) => {
const bytes = Buffer.from(JSON.stringify(head) + '\n');
return { json: head, bytes, sha256: createHash('sha256').update(bytes).digest('hex') };
};
const rawFound = (text) => {
const bytes = Buffer.from(text + '\n');
return { json: JSON.parse(text), bytes, sha256: createHash('sha256').update(bytes).digest('hex') };
};
const valid = signed();
// The head's asset index, a blob the origin must also serve.
const index = streamIndex(bundle), indexPath = blobPath(index.card.sha256);
// A host display-name change repairs metadata without losing signed capabilities.
const renameDir=mkdtempSync(join(tmpdir(),'exact-renamed-cohort-')), renameOrigin=new DirectoryOrigin(renameDir);
await renameOrigin.put(indexPath,index.bytes,{immutable:true});
await renameOrigin.putHead(stream,found(valid).bytes,{previousDigest:null});
await renameOrigin.put(`.exact/${stream.channel}/${compatibilityId}/releases/old.json`,Buffer.from(JSON.stringify({platform:'linux',envelope:valid})),{immutable:true});
const renamed={...app,displayName:'Renamed'}, build=fixtureBuild(compatibilityId,bundle);
const renameArgs={app:renamed,opts:{platform:['linux']},origin:renameOrigin,channel:stream.channel,snapshot:{commit:'rename',dirty:false,changes:[],repo:dir},release:'rename',bundle,compat:{linux:build.compat},builds:{linux:build},platforms:['linux'],wantOrigin:false};
const renameTable=await classify(renameArgs), renameRow=renameTable.rows.find(r=>r.kind==='stream');
const renamePublished=await publishStream({origin:renameOrigin,row:renameRow,bundle,compat:build.compat,app:renamed,signer,release:'rename',snapshot:renameArgs.snapshot,opts:{},log:()=>{},build});
const changed=structuredClone(build);changed.graph.artifacts[0].requires.sources={camera:{params:[],result:'String'}};
const afterRename=await classify({...renameArgs,release:'unsupported',builds:{linux:changed}});
const renamedHead=await renameOrigin.head(stream);
result('display-name repair preserves the authenticated cohort and still refuses new capabilities',renameRow.action==='bundle'&&renamePublished.seq===8
&&renamedHead.json.app.name==='Renamed'&&renamedHead.json.stream.seq===8&&inspectHead(renamedHead,renamed,stream).authenticated
&&afterRename.rows.find(r=>r.kind==='stream').reason.includes('sources.camera'));
const foreign='deadbeefdeadbeefdeadbeefdeadbeef', forged=structuredClone(renamedHead.json);forged.stream.compatibilityId=foreign;
await renameOrigin.putHead({...stream,compatibilityId:foreign},Buffer.from(JSON.stringify(forged)),{previousDigest:null});
const independent=await classify({...renameArgs,release:'unrelated'});
result('an unauthenticated unrelated stream cannot block a healthy cohort',independent.rows.some(r=>r.compatibilityId===compatibilityId&&r.action==='current')
&&independent.rows.some(r=>r.compatibilityId===foreign&&r.action==='binary')&&independent.notes.some(n=>n.includes(foreign)&&n.includes('does not verify')));
rmSync(renameDir,{recursive:true,force:true});
const history = Buffer.from(JSON.stringify({ envelope: valid }) + '\n');
const tableFor = (candidate, withHistory = true, withIndex = true) => classify({ app, opts: { platform: [] },
origin: {
kind: 'directory', describe: () => dir,
get: async (name) => withHistory && name.endsWith('/releases/old.json') ? history : withIndex && name === indexPath ? index.bytes : null,
head: async () => candidate === null ? null : candidate?.bytes ? candidate : found(candidate),
list: async (name) => withHistory && name.endsWith('/releases') ? ['old.json'] : [],
},
channel: stream.channel, snapshot: { commit: '0'.repeat(40), dirty: false, changes: [], repo: dir },
release: 'next', web: dir, bundle, builds:{linux:fixtureBuild(compatibilityId,bundle)}, compat: { linux: { id: compatibilityId, inputs: { store: { L: 'A' }, executors: [] } } },
platforms: ['linux'], wantOrigin: false });
const missingSignature = signed(); delete missingSignature.signature;
const badSignature = signed(); badSignature.signature.ed25519 = Buffer.alloc(64).toString('base64');
const forgedLow = signed((head) => { head.stream.seq = 2; }); forgedLow.signature.ed25519 = Buffer.alloc(64).toString('base64');
const forgedHuge = signed((head) => { head.stream.seq = Number.MAX_SAFE_INTEGER; }); forgedHuge.signature.ed25519 = Buffer.alloc(64).toString('base64');
const noSeq = signed((head) => { head.stream.seq = 'seven'; });
const decimal = rawFound(JSON.stringify(valid).replace('"seq":7', '"seq":7.0'));
const exponent = rawFound(JSON.stringify(valid).replace('"seq":7', '"seq":7e0'));
const zeroHead = signed((head) => { head.unknownNumber = 0; });
const negativeZero = rawFound(JSON.stringify(zeroHead).replace('"unknownNumber":0', '"unknownNumber":-0'));
const scalarHead = { ...valid, unknownText: String.fromCharCode(0xd800) };
const loneSurrogate = rawFound(JSON.stringify(scalarHead));
const variants = [
missingSignature,
badSignature,
forgedLow,
forgedHuge,
noSeq,
decimal,
exponent,
negativeZero,
loneSurrogate,
signed((head) => { head.stream.channel = 'beta'; }),
signed((head) => { head.exact = 2; }),
signed((head) => { delete head.plan.bytes; }),
];
const validTable = await tableFor(valid);
// A signed head whose asset index the origin lacks is repaired, not current.
const missingIndexTable = await tableFor(valid, true, false);
const reordered = { cohort: valid.cohort, signature: valid.signature, stream: valid.stream, release: valid.release,
plan: valid.plan, exact: valid.exact, assets: valid.assets, app: valid.app };
const prettyBytes = Buffer.from(JSON.stringify(reordered, null, 2) + '\n');
const pretty = { json: reordered, bytes: prettyBytes, sha256: createHash('sha256').update(prettyBytes).digest('hex') };
const numberedKeys = signed((head) => { head.unknownKeys = { 2: 'two', 10: 'ten' }; });
const numberedCanonical = canonicalBytes(numberedKeys).toString('utf8');
const surrogateValueRefused = await rejects(() => canonicalBytes({ value: String.fromCharCode(0xd800) }), error => error.message.includes('not a Unicode scalar value'));
const surrogateKeyRefused = await rejects(() => canonicalBytes({ [String.fromCharCode(0xdc00)]: 'value' }), error => error.message.includes('not a Unicode scalar value'));
const repaired = await Promise.all(variants.map((candidate) => tableFor(candidate)));
const missingHeadTable = await tableFor(null);
const emptyHeadTable = await tableFor(null, false);
const unlistableTable = await classify({ app, opts: { platform: [] },
origin: {
kind: 'https', describe: () => 'https://origin.example', get: async () => null,
head: async () => null, list: async () => null,
},
channel: stream.channel, snapshot: { commit: '0'.repeat(40), dirty: false, changes: [], repo: dir },
release: 'next', web: dir, bundle, builds:{linux:fixtureBuild(compatibilityId,bundle)}, compat: { linux: { id: compatibilityId, inputs: { store: { L: 'A' }, executors: [] } } },
platforms: ['linux'], wantOrigin: false });
const noHistoryRefused = await rejects(async () => await tableFor(badSignature, false), error => error.message.includes('release history has no authenticated sequence floor'));
let unknownHistoryRefused = false;
let unknownHistoryWrote = false;
const unknownOrigin = {
kind: 'object', describe: () => 'unknown-object-origin', get: async () => null,
head: async () => null, list: async () => null,
withLock: async (_stream, body) => body(),
put: async () => { unknownHistoryWrote = true; },
putHead: async () => { unknownHistoryWrote = true; },
};
try {
await publishStream({ origin: unknownOrigin,
row: { kind: 'stream', platform: 'linux', channel: stream.channel, compatibilityId, action: 'bundle', changes: [] },
bundle, compat: { id: compatibilityId, inputs: {} }, app, signer, release: 'unknown-history',
snapshot: { commit: '0'.repeat(40), dirty: false, changes: [] }, opts: {}, log: () => {} });
} catch (error) { unknownHistoryRefused = error.message.includes('cannot enumerate its authenticated release history'); }
const badHistoryOrigin = (bytes) => ({
kind: 'directory', describe: () => 'bad-history-origin',
get: async (name) => name.endsWith('/releases/broken.json') ? bytes : null,
head: async () => null, list: async () => ['broken.json'],
});
const foreignHistory = Buffer.from(JSON.stringify({ envelope: signed((head) => { head.app.id = 'com.exact.foreign'; }) }) + '\n');
const badHistories = [Buffer.from('{not json'), Buffer.from(JSON.stringify({ envelope: missingSignature }) + '\n'), foreignHistory];
const badHistoryClassifyRefused = [];
for (const bytes of badHistories) {
try {
await classify({ app, opts: { platform: [] }, origin: badHistoryOrigin(bytes),
channel: stream.channel, snapshot: { commit: '0'.repeat(40), dirty: false, changes: [], repo: dir },
release: 'next', web: dir, bundle, builds:{linux:fixtureBuild(compatibilityId,bundle)}, compat: { linux: { id: compatibilityId, inputs: { store: { L: 'A' }, executors: [] } } },
platforms: ['linux'], wantOrigin: false });
badHistoryClassifyRefused.push(false);
} catch (error) { badHistoryClassifyRefused.push(error.message.includes('nonempty release history has no authenticated sequence floor')); }
}
let corruptHistoryPublishRefused = false;
let corruptHistoryWrote = false;
try {
await publishStream({ origin: {
...badHistoryOrigin(Buffer.from('{not json')), withLock: async (_stream, body) => body(),
put: async () => { corruptHistoryWrote = true; }, putHead: async () => { corruptHistoryWrote = true; },
}, row: { kind: 'stream', platform: 'linux', channel: stream.channel, compatibilityId, action: 'bundle', changes: [] },
bundle, compat: { id: compatibilityId, inputs: {} }, app, signer, release: 'corrupt-history',
snapshot: { commit: '0'.repeat(40), dirty: false, changes: [] }, opts: {}, log: () => {} });
} catch (error) { corruptHistoryPublishRefused = error.message.includes('nonempty release history has no authenticated sequence floor'); }
const vanishedTable = await classify({ app, opts: { platform: [] }, origin: badHistoryOrigin(null),
channel: stream.channel, snapshot: { commit: '0'.repeat(40), dirty: false, changes: [], repo: dir },
release: 'next', web: dir, bundle, builds:{linux:fixtureBuild(compatibilityId,bundle)}, compat: { linux: { id: compatibilityId, inputs: { store: { L: 'A' }, executors: [] } } },
platforms: ['linux'], wantOrigin: false });
const vanishedHistoryUnavailable = vanishedTable.rows[0].action === 'unavailable'
&& vanishedTable.rows[0].reason.includes('disappeared while establishing');
const origin = new DirectoryOrigin(dir);
mkdirSync(join(dir, '.exact', stream.channel, compatibilityId), { recursive: true });
writeFileSync(join(dir, '.exact', stream.channel, compatibilityId, 'exact.json'), found(forgedHuge).bytes);
await origin.put(`.exact/${stream.channel}/${compatibilityId}/releases/old.json`, history, { immutable: true });
const locked = await publishStream({ origin,
row: { kind: 'stream', platform: 'linux', channel: stream.channel, compatibilityId, action: 'current', changes: [] },
bundle, compat: { id: compatibilityId, inputs: {} }, app, signer, release: 'locked-repair',
snapshot: { commit: '0'.repeat(40), dirty: false, changes: [] }, opts: {}, log: () => {} });
const repairedHead = await origin.head(stream);
const missingDir = mkdtempSync(join(tmpdir(), 'exact-missing-head-'));
const missingOrigin = new DirectoryOrigin(missingDir);
await missingOrigin.put(`.exact/${stream.channel}/${compatibilityId}/releases/old.json`, history, { immutable: true });
const missingPublished = await publishStream({ origin: missingOrigin,
row: { kind: 'stream', platform: 'linux', channel: stream.channel, compatibilityId, action: 'bundle', changes: [] },
bundle, compat: { id: compatibilityId, inputs: {} }, app, signer, release: 'after-missing',
snapshot: { commit: '0'.repeat(40), dirty: false, changes: [] }, opts: {}, log: () => {} });
const hiddenDir = mkdtempSync(join(tmpdir(), 'exact-hidden-history-'));
const hiddenOrigin = new DirectoryOrigin(hiddenDir);
await hiddenOrigin.put(`.exact/${stream.channel}/${compatibilityId}/releases/.old.json`, history, { immutable: true });
const hiddenTable = await classify({ app, opts: { platform: [] }, origin: hiddenOrigin,
channel: stream.channel, snapshot: { commit: '0'.repeat(40), dirty: false, changes: [], repo: dir },
release: 'after-hidden', web: dir, bundle, builds:{linux:fixtureBuild(compatibilityId,bundle)}, compat: { linux: { id: compatibilityId, inputs: { store: { L: 'A' }, executors: [] } } },
platforms: ['linux'], wantOrigin: false });
const hiddenPublished = await publishStream({ origin: hiddenOrigin,
row: { kind: 'stream', platform: 'linux', channel: stream.channel, compatibilityId, action: 'bundle', changes: [] },
bundle, compat: { id: compatibilityId, inputs: {} }, app, signer, release: 'after-hidden',
snapshot: { commit: '0'.repeat(40), dirty: false, changes: [] }, opts: {}, log: () => {} });
const hiddenReleaseCli = spawnSync(process.execPath,
[DEPLOY, 'caltrain', '--release', '.hidden', '--json'],
{ cwd: join(dirname(DEPLOY), '..'), encoding: 'utf8' });
result('deploy calls only an admitted authenticated head current', validTable.rows[0].action === 'current'
&& validTable.rows[0].seq === 7 && inspectHead(found(valid), app, stream).usable && inspectHead(pretty, app, stream).usable
&& inspectHead(found(numberedKeys), app, stream).usable
&& numberedCanonical.includes('"unknownKeys":{"10":"ten","2":"two"}')
&& surrogateValueRefused && surrogateKeyRefused
&& missingHeadTable.rows[0].action === 'bundle' && missingHeadTable.rows[0].seq === 8
&& emptyHeadTable.rows[0].action === 'bundle' && emptyHeadTable.rows[0].seq === 1
&& unlistableTable.rows[0].action === 'unavailable'
&& unlistableTable.rows[0].reason.includes('cannot enumerate its authenticated release history')
&& [...repaired, missingIndexTable].every((table) => table.rows[0].action === 'bundle' && table.rows[0].seq === 8
&& table.rows[0].changes[0].name === 'exact.json' && table.rows[0].changes[0].change === 'repair')
&& noHistoryRefused && unknownHistoryRefused && !unknownHistoryWrote
&& badHistoryClassifyRefused.every(Boolean) && corruptHistoryPublishRefused && !corruptHistoryWrote
&& vanishedHistoryUnavailable
&& locked.action === 'published' && locked.seq === 8
&& missingPublished.action === 'published' && missingPublished.seq === 8
&& hiddenTable.rows[0].seq === 8 && hiddenPublished.seq === 8
&& hiddenReleaseCli.status === 1 && hiddenReleaseCli.stderr.includes('start with a letter or digit')
&& locked.changes[0].change === 'repair' && inspectHead(repairedHead, app, stream).usable,
JSON.stringify({ missingHead: missingHeadTable.rows[0], emptyHead: emptyHeadTable.rows[0], unlistable: unlistableTable.rows[0],
noHistoryRefused, unknownHistoryRefused, unknownHistoryWrote, badHistoryClassifyRefused, corruptHistoryPublishRefused, corruptHistoryWrote,
vanishedHistoryUnavailable, hiddenTable: hiddenTable.rows[0], hiddenPublished: { action: hiddenPublished.action, seq: hiddenPublished.seq },
hiddenReleaseCli: { status: hiddenReleaseCli.status, stderr: hiddenReleaseCli.stderr },
locked: { action: locked.action, seq: locked.seq }, missingPublished: { action: missingPublished.action, seq: missingPublished.seq } }));
rmSync(hiddenDir, { recursive: true, force: true });
rmSync(missingDir, { recursive: true, force: true });
rmSync(dir, { recursive: true, force: true });
}
{
const dir = mkdtempSync(join(tmpdir(), 'exact-list-outage-'));
const cohort = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
const origin = {
kind: 'directory', describe: () => dir, get: async () => null, head: async () => null,
list: async (name) => { if (name.endsWith('/releases')) return null; throw new OriginUnavailable('EACCES'); },
};
const table = await classify({ app: { id: 'com.exact.test', displayName: 'Test', dir, manifest: {} }, opts: { platform: [] },
origin, channel: 'prod', snapshot: { commit: '0'.repeat(40), dirty: false, changes: [], repo: dir },
release: 'test', web: dir, bundle: { plan: { sha256: '0'.repeat(64) }, assets: [] },
builds:{linux:fixtureBuild(cohort,{plan:{sha256:'0'.repeat(64)}})}, compat: { linux: { id: cohort, inputs: { store: { L: 'A' }, executors: [] } } }, platforms: ['linux'], wantOrigin: false });
result('stream discovery outage retains the classified cohort row', table.rows.filter(r=>r.kind==='stream').length === 1
&& table.rows[0].action === 'bundle' && table.notes.some((note) => note.includes('stream discovery unavailable')),
JSON.stringify(table));
rmSync(dir, { recursive: true, force: true });
}
// Android's binary is the APK, which its own verb builds (LLP 1030.006 D6, LLP 1030.007 D5): with no stream and no
// production APK receipt, the table names the APK's command.
{
const dir = mkdtempSync(join(tmpdir(), 'exact-android-binary-'));
const origin = { kind: 'directory', describe: () => dir, get: async () => null, head: async () => null, list: async () => [] };
const table = async (store) => classify({ app: { id: 'com.exact.test', displayName: 'Test', dir, manifest: { deploy: { store: { android: store } } } },
opts: { platform: [] }, origin, channel: 'prod', snapshot: { commit: '0'.repeat(40), dirty: false, changes: [], repo: dir },
release: 'test', web: dir, bundle: { plan: { sha256: '0'.repeat(64) }, assets: [] }, builds: {}, compat: {}, platforms: ['android'], wantOrigin: false });
const updating = await table('A'), fixed = await table('0');
const rendered = renderTable(updating);
result('an Android deploy with no stream names the production APK command', updating.rows.length === 1
&& updating.rows[0].kind === 'binary' && updating.rows[0].reason.includes('EXACT_UPDATE_TRUST=production bun exact.mjs android --release')
&& updating.rows[0].reason.includes('EXACT_UPDATE_GENESIS=1') && fixed.rows[0].reason.startsWith('deploy.store.android is "0"')
&& rendered.includes('new APK needed: android — EXACT_UPDATE_TRUST=production bun exact.mjs android --release'), rendered);
rmSync(dir, { recursive: true, force: true });
}
// A production APK receipt with no head starts its stream: the row's cohort is that APK's, and a note names the
// receipt (LLP 1030.007 D4).
{
const dir = mkdtempSync(join(tmpdir(), 'exact-android-start-'));
const origin = { kind: 'directory', describe: () => dir, get: async () => null, head: async () => null, list: async () => [] };
const id = 'a'.repeat(32), bundle = { plan: { sha256: '1'.repeat(64) }, assets: [] };
const apk = fixtureBuild(id, bundle);
apk.compat.inputs.platform = 'android';
const cohort = cohortReceipt(apk), stream = { channel: 'prod', compatibilityId: id };
const table = await classify({ app: { id: 'com.exact.test', displayName: 'Test', dir, manifest: { deploy: { store: { android: 'A' } } } },
opts: { platform: [] }, origin, channel: 'prod', snapshot: { commit: '0'.repeat(40), dirty: false, changes: [], repo: dir },
release: 'test', web: dir, bundle, builds: {}, compat: {}, platforms: ['android'], wantOrigin: false,
knownStreams: [{ stream, head: null, cohort, platform: 'android', build: apk }],
candidates: new Map([[id, { build: apk, bundle }]]), anchors: new Map([[id, '/receipts/android-aarch64-linux-android.build.json']]) });
const [row] = table.rows;
result('a production APK receipt starts its Android stream with that APK as the cohort', table.rows.length === 1
&& row.kind === 'stream' && row.platform === 'android' && row.action === 'bundle' && row.receipt === cohort && row.head === null
&& table.notes.some((note) => note === `android stream ${id.slice(0, 8)} starts from the production build receipt /receipts/android-aarch64-linux-android.build.json: binary ${'0'.repeat(12)}`),
JSON.stringify(table));
rmSync(dir, { recursive: true, force: true });
}
// A dry-run renders network availability per row, including declared retired
// streams. A corrupt response remains a hard refusal rather than masquerading
// as a transient network problem.
{
const dir = mkdtempSync(join(tmpdir(), 'exact-origin-table-'));
writeFileSync(join(dir, 'index.html'), 'web');
const app = { id: 'com.exact.test', displayName: 'Test', dir,
manifest: { deploy: { streams: [{ channel: 'prod', compatibilityId: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' }] } } };
const compat = {
web: { id: 'wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww', inputs: {} },
linux: { id: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', inputs: { store: { L: 'A' }, executors: [] } },
};
const table = await classify({ app, opts: { platform: [] },
origin: new HttpsOrigin('https://127.0.0.1:1'), channel: 'prod',
snapshot: { commit: '0'.repeat(40), dirty: false, changes: [], repo: dir }, release: 'test', web: dir,
bundle: { plan: { sha256: '0'.repeat(64) }, assets: [] }, compat, platforms: ['linux'], wantOrigin: true });
const unavailable = table.rows.filter((row) => row.action === 'unavailable');
result('deploy tables preserve every row when HTTPS is unavailable', unavailable.length === 3
&& unavailable.some((row) => row.kind === 'origin')
&& unavailable.some((row) => row.platform === 'linux')
&& unavailable.some((row) => row.compatibilityId.startsWith('bbbb')),
JSON.stringify(table.rows));
rmSync(dir, { recursive: true, force: true });
}
{
const dir = mkdtempSync(join(tmpdir(), 'exact-bad-head-'));
const cohort = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
mkdirSync(join(dir, '.exact', 'prod', cohort), { recursive: true });
writeFileSync(join(dir, '.exact', 'prod', cohort, 'exact.json'), '{not json');
let message = '';
try {
await classify({ app: { id: 'com.exact.test', displayName: 'Test', dir, manifest: {} }, opts: { platform: [] },
origin: new DirectoryOrigin(dir), channel: 'prod', snapshot: { commit: '0'.repeat(40), dirty: false, changes: [], repo: dir },
release: 'test', web: dir, bundle: { plan: { sha256: '0'.repeat(64) }, assets: [] },
compat: { linux: { id: cohort, inputs: { store: { L: 'A' }, executors: [] } } }, platforms: ['linux'], wantOrigin: false });
} catch (error) { message = error.message; }
result('deploy does not hide a malformed head as unavailable', message.includes('is not JSON'), message);
rmSync(dir, { recursive: true, force: true });
}
// One comparison drives dev and deploy; neither id equality nor a binary
// edit is a proxy for a bundle dependency.
{
const candidate=fixtureBuild('a'.repeat(32),{plan:{sha256:'0'.repeat(64)}});
candidate.compat.inputs={app:'test',store:{L:'A'},executors:['native'],grantCeiling:'net.fetch https://x/',gpuSurfaces:[{name:'map',interface:'v1'}],dataCrate:{tree:'old'}};
candidate.graph.sources={station:{params:['String'],result:'String'}};
candidate.graph.artifacts[0].requires={sources:candidate.graph.sources,executors:['native'],grantCeiling:'net.fetch https://x/'};
const installed=cohortReceipt(candidate);
const host=structuredClone(candidate);host.binary.sha256='1'.repeat(64);
const same=classifyArtifacts(host,installed);
const moved=structuredClone(host);moved.compat.id='b'.repeat(32);moved.compat.inputs.dataCrate.tree='new';
const old=classifyArtifacts(moved,installed);
const needs=structuredClone(moved);needs.graph.artifacts[0].requires.sources={camera:{params:[],result:'String'}};
const absent=classifyArtifacts(needs,installed);
const shader=structuredClone(moved);shader.graph.artifacts.push({name:'shaders/map.wgsl',requires:{gpuSurfaces:[{name:'map',interface:'v2'}]}});
const unsupported=classifyArtifacts(shader,installed);
const grants=structuredClone(moved);grants.graph.artifacts[0].requires.grantCeiling='net.fetch https://new/';
const refused=classifyArtifacts(grants,installed);
// A TypeScript bundle on a newer prelude (LLP 1108 D6 R2: `exactBodyFrom`, then
// `redirect`) is no bundle for a cohort whose prelude predates it, and is for one
// as new or newer: runtime 1 would follow a redirect a runtime-2 bundle refused.
const runtime=structuredClone(moved);runtime.graph.artifacts[0].requires.typescriptRuntime=2;
const prelude=n=>({...installed,compat:{...installed.compat,inputs:{...installed.compat.inputs,typescriptRuntime:n}}});
const olderPrelude=classifyArtifacts(runtime,installed), runtimeOne=classifyArtifacts(runtime,prelude(1));
const samePrelude=classifyArtifacts(runtime,prelude(2)), newerPrelude=classifyArtifacts(runtime,prelude(3));
result('a bundle needing a newer TypeScript runtime is refused by an older cohort only',
!olderPrelude.bundle&&olderPrelude.missing[0].includes('typescriptRuntime')&&!runtimeOne.bundle&&runtimeOne.missing[0].includes('runtime 2 or later; this cohort\'s is 1')
&&samePrelude.bundle&&newerPrelude.bundle, JSON.stringify({olderPrelude,runtimeOne,samePrelude,newerPrelude}));
// The TypeScript module pair runs only where the binary's TypeScript grants are exactly its own (js/src/paired.rs).
const pair=(grants)=>{const c=structuredClone(moved);c.graph.artifacts.push({name:'typescript/app.hbc',requires:{javascriptGrants:grants}});return c;};
const holding=g=>({...installed,compat:{...installed.compat,inputs:{...installed.compat.inputs,javascriptGrants:g}}});
const narrower=classifyArtifacts(pair('net.fetch https://x/\nnet.fetch https://y/'),holding('net.fetch https://x/'));
const wider=classifyArtifacts(pair('net.fetch https://x/'),holding('net.fetch https://x/\nnet.fetch https://y/'));
const exact=classifyArtifacts(pair('net.fetch https://x/'),holding('net.fetch https://x/'));
result('a TypeScript pair goes only to a binary holding exactly its grants',
!narrower.bundle&&narrower.missing[0].includes('typescript/app.hbc: javascriptGrants')&&!wider.bundle&&exact.bundle,
JSON.stringify({narrower,wider,exact}));
// An Android cohort takes a generation that needs no more than its APK was composed from, and only its own Hermes
// bytecode version (LLP 1030.006 D4, D4a).
const apk=({...installed,compat:{...installed.compat,inputs:{...installed.compat.inputs,hermesBytecode:96,
androidLinked:{uses:['fetch','dates'],permissions:['android.permission.READ_CALENDAR'],extensions:['swatch']}}}});
const android=(plan,module)=>{const c=structuredClone(moved);Object.assign(c.graph.artifacts[0].requires,plan);c.graph.artifacts.push({name:'typescript/app.hbc',requires:module});return c;};
const less=classifyArtifacts(android({androidUses:['fetch'],androidExtensions:[]},{hermesBytecode:96,androidPermissions:[]}),apk);
const capability=classifyArtifacts(android({androidUses:['fetch','camera'],androidExtensions:[]},{hermesBytecode:96,androidPermissions:[]}),apk);
const extension=classifyArtifacts(android({androidUses:[],androidExtensions:['pedometer']},{hermesBytecode:96,androidPermissions:[]}),apk);
const permission=classifyArtifacts(android({androidUses:[],androidExtensions:[]},{hermesBytecode:96,androidPermissions:['android.permission.WRITE_CALENDAR']}),apk);
const engine=classifyArtifacts(android({androidUses:[],androidExtensions:[]},{hermesBytecode:97,androidPermissions:[]}),apk);
result('an Android cohort refuses a generation beyond what its APK linked or of another bytecode version, and takes one that needs less',
less.bundle&&!capability.bundle&&capability.missing[0].includes('androidUses.camera')&&!extension.bundle&&extension.missing[0].includes('androidExtensions.pedometer')
&&!permission.bundle&&permission.missing[0].includes('WRITE_CALENDAR')&&!engine.bundle&&engine.missing[0].includes('Hermes bytecode 97'),
JSON.stringify({less,capability,extension,permission,engine}));
result('artifact graph separates binary changes, compatible older cohorts, and named missing dependencies',
same.binary&&same.bundle&&old.binary&&old.bundle&&old.warnings[0].includes('will run the old code')
&&!absent.bundle&&absent.missing[0].includes('sources.camera')&&!unsupported.bundle&&unsupported.missing[0].includes('gpuSurfaces.map')
&&!refused.bundle&&refused.missing[0].includes('https://new/')&&!classifyArtifacts(moved,null).bundle,
JSON.stringify({same,old,absent,unsupported,refused}));
}
// Signing-key creation is one exclusive filesystem operation. Two publishers
// racing for an id cannot both report a public half and silently replace the
// private half behind the first one's result.
{
const dir = mkdtempSync(join(tmpdir(), 'exact-keygen-'));
const run = () => new Promise((done) => {
const child = spawn(process.execPath, [DEPLOY, 'keygen', 'race', '--keys', dir, '--json']);
let stdout = '', stderr = '';
child.stdout.on('data', (bytes) => { stdout += bytes; });
child.stderr.on('data', (bytes) => { stderr += bytes; });
child.on('close', (code) => done({ code, stdout, stderr }));
});
const attempts = await Promise.all([run(), run()]);
const winners = attempts.filter((attempt) => attempt.code === 0);
const losers = attempts.filter((attempt) => attempt.code !== 0);
let matches = false;
try {
const reported = Buffer.from(JSON.parse(winners[0]?.stdout ?? '{}').publicKey ?? '', 'base64');
const actual = createPublicKey(createPrivateKey(readFileSync(join(dir, 'race.pem'))))
.export({ type: 'spki', format: 'der' }).subarray(-32);
matches = reported.equals(actual);
} catch { /* the result below names the failed invariant */ }
result('concurrent keygen has one truthful winner', winners.length === 1 && losers.length === 1
&& losers[0].stderr.includes('a signing key is never overwritten') && matches,
attempts.map((attempt) => `exit ${attempt.code}: ${attempt.stdout}${attempt.stderr}`).join('\n'));
rmSync(dir, { recursive: true, force: true });
}
{ // Edit diagnostics own and remove large captured Git trees, including on callback failure.
const app = resolveApp('caltrain'), previous = process.env.CARGO_TARGET_DIR;
const traceDir = mkdtempSync(join(tmpdir(), 'exact-diagnostic-git-')), trace = join(traceDir, 'trace.json');
const previousTrace = process.env.GIT_TRACE2_EVENT;
writeFileSync(trace, '');
process.env.GIT_TRACE2_EVENT = trace;
let gitStarts;
let source, run, isolated = false, installed = false, caught = false, why = '';
try {
await withAppFixture(app, async f => {
source = f.sourceRoot; run = f.run;
isolated = f.app.dir !== app.dir && f.env.EXACT_APP_DIR === f.app.dir
&& f.env.CARGO_TARGET_DIR.startsWith(run + '/') && f.env.EXACT_WEB_DIST.startsWith(source + '/')
&& spawnSync('git', ['rev-parse', '--show-toplevel'], { cwd: f.app.dir, env: f.env, encoding: 'utf8' }).stdout.trim() === source;
// The capture carries the pinned node_modules (a TypeScript bake runs
// Rolldown from it), installed as an output, not committed as source.
installed = existsSync(join(f.exactRoot, 'node_modules/.bin/rolldown'))
&& spawnSync('git', ['ls-files', 'node_modules'], { cwd: f.exactRoot, env: f.env, encoding: 'utf8' }).stdout === '';
f.git(['commit', '--allow-empty', '-qm', 'Diagnostic follow-up']);
writeFileSync(join(f.app.dir, 'diagnostic-private.txt'), 'captured only');
for (let i = 0; i < 5000; i++) writeFileSync(join(source, `cleanup-${i}`), 'private');
throw new Error('expected diagnostic callback failure');
});
} catch (error) { caught = error.message === 'expected diagnostic callback failure'; why = caught ? '' : error.message; }
finally {
if (previousTrace === undefined) delete process.env.GIT_TRACE2_EVENT;
else process.env.GIT_TRACE2_EVENT = previousTrace;
try { gitStarts = readFileSync(trace, 'utf8').trim().split('\n').filter(Boolean).map(line => JSON.parse(line)).filter(event => event.event === 'start'); }
finally { rmSync(traceDir, { recursive: true, force: true }); }
}
// Check invocation, not whether a detached collector happens to beat cleanup.
result('diagnostic Git commits do not start automatic maintenance',
gitStarts.filter(event => event.argv.includes('commit')).length === 2
&& !gitStarts.some(event => event.argv.includes('maintenance') || event.argv.includes('gc')),
gitStarts.map(event => event.argv.join(' ')).join('\n'));
// A fixture that could not start (a cold Cargo cache offline: run `cargo fetch`) says so.
result('diagnostic source and outputs are isolated and cleaned on failure', isolated && installed && caught
&& !existsSync(source ?? '/missing') && !existsSync(run ?? '/missing')
&& !existsSync(join(app.dir, 'diagnostic-private.txt')) && process.env.CARGO_TARGET_DIR === previous, why);
}
// A release remains recognizable to a person without being the bake's lock
// or directory identity. Even an explicitly reused correlation id gets a
// separate stage, and generated ids in the same clock tick do not collide.
{
const fixture = mkdtempSync(join(tmpdir(), 'exact-source-snapshot-'));
const compiler = join(fixture, 'contract-stub');
writeFileSync(compiler, '#!/usr/bin/env bun\nconsole.log(JSON.stringify({packages:[],sources:[{origin:"app",path:process.argv.at(-1)}],consulted:[],errors:[]}));\n');
chmodSync(compiler, 0o755);
const snapshots = [];
const snapshotOf = (app, opts, exactRoot) => { const snapshot = capturedSnapshotOf(app, { ...opts, compiler }, exactRoot); snapshots.push(snapshot); return snapshot; };
const init = (repo, files) => {
mkdirSync(repo, { recursive: true });
spawnSync('git', ['init', '-q'], { cwd: repo });
for (const [name, bytes] of Object.entries(files)) {
mkdirSync(dirname(join(repo, name)), { recursive: true });
writeFileSync(join(repo, name), bytes);
}
spawnSync('git', ['add', '-A'], { cwd: repo });
return spawnSync('git', ['-c', 'user.name=Exact Test', '-c', '[email protected]', 'commit', '-qm', 'fixture'], { cwd: repo }).status === 0;
};
const internal = join(fixture, 'internal');
const external = join(fixture, 'external');
const exact = join(fixture, 'exact2');
const cargoDep = join(fixture, 'cargo-dep');
const linked = join(fixture, 'linked');
const filtered = join(fixture, 'filtered');
const outsideLink = join(fixture, 'outside-link.rs');
const outsideTarget = join(fixture, 'outside-main.rs');
let initialized = init(internal, { '.gitignore': '/apps/test/assets/ignored.txt\n/generated/\n/target/\n',
'apps/test/app.contract': 'app Test\n', 'apps/test/assets/dist/published.txt': 'nested old\n',
'host/runtime.rs': 'old\n', 'removed.txt': 'remove me\n' })
&& init(cargoDep, { '.gitignore': '/crates/fixture-dep/ignored.rs\n/generated/\n/target/\n',
'Cargo.toml': '[workspace]\nmembers=["crates/fixture-dep"]\nresolver="2"\n[workspace.package]\nversion="0.1.0"\nedition="2021"\n',
'shared.txt': '1\n',
'generated/value.txt': 'ignored repository input\n',
'crates/fixture-dep/Cargo.toml': '[package]\nname="fixture-dep"\nversion.workspace=true\nedition.workspace=true\n',
'crates/fixture-dep/src/lib.rs': 'pub fn value() -> &\'static str { include_str!("../../../shared.txt").trim() }\n' })
&& init(external, { 'app.contract': 'app External\n',
'Cargo.toml': '[package]\nname="external"\nversion="0.1.0"\nedition="2021"\n[dependencies]\nfixture-dep={path="../cargo-dep/crates/fixture-dep"}\n',
'src/lib.rs': 'pub fn value() -> &\'static str { fixture_dep::value() }\n',
'src/main.rs': 'fn main() { println!("{}:{}", fixture_dep::value(), option_env!("RACE_VALUE").unwrap_or("sealed")); }\n' })
&& init(exact, { 'host/runtime.rs': 'old\n' })
&& init(linked, { 'app.contract': 'app Linked\n', 'src/main.rs': 'local\n' })
&& init(filtered, { 'app.contract': 'app Filtered\n', 'source.txt': 'WORKING SOURCE BYTES\n',
'target-one.txt': 'ONE\n', 'target-two.txt': 'TWO\n' });
if (initialized) {
writeFileSync(outsideLink, 'external mutable bytes\n');
writeFileSync(outsideTarget, 'fn main() { println!("live"); }\n');
rmSync(join(linked, 'src/main.rs'));
symlinkSync(outsideLink, join(linked, 'src/main.rs'));
spawnSync('git', ['add', 'src/main.rs'], { cwd: linked });
initialized = spawnSync('git', ['-c', 'user.name=Exact Test', '-c', '[email protected]',
'commit', '-qm', 'link'], { cwd: linked }).status === 0;
}
if (initialized) {
spawnSync('git', ['config', 'filter.worktree.clean', 'sed s/WORKING/STORED/g'], { cwd: filtered });
spawnSync('git', ['config', 'filter.worktree.smudge', 'sed s/STORED/WORKING/g'], { cwd: filtered });
spawnSync('git', ['config', 'filter.worktree.required', 'true'], { cwd: filtered });
writeFileSync(join(filtered, '.gitattributes'), 'source.txt filter=worktree\n');
spawnSync('git', ['add', '--renormalize', '.'], { cwd: filtered });
spawnSync('git', ['add', '.gitattributes'], { cwd: filtered });
initialized = spawnSync('git', ['-c', 'user.name=Exact Test', '-c', '[email protected]',
'commit', '-qm', 'filter'], { cwd: filtered }).status === 0;
}
if (initialized) {
symlinkSync('target-one.txt', join(filtered, 'alias.txt'));
symlinkSync(join(realpathSync(filtered), 'alias.txt'), join(filtered, 'inside.txt'));
spawnSync('git', ['add', 'alias.txt', 'inside.txt'], { cwd: filtered });
initialized = spawnSync('git', ['-c', 'user.name=Exact Test', '-c', '[email protected]',
'commit', '-qm', 'internal absolute link'], { cwd: filtered }).status === 0;
}
if (initialized) {
initialized = spawnSync('cargo', ['generate-lockfile'], { cwd: external, stdio: 'ignore' }).status === 0;
spawnSync('git', ['add', 'Cargo.lock'], { cwd: external });
initialized = initialized && spawnSync('git', ['-c', 'user.name=Exact Test', '-c', '[email protected]',
'commit', '-qm', 'lock'], { cwd: external }).status === 0;
}
const fixtureApp = (name, dir, workspace) => ({ name, dir, workspace, target: join(workspace, 'target'),
crate: (kind) => `${name}-${kind}`, manifest: { app: { id: `com.exact.${name}`, name }, host: {}, deploy: {} },
id: `com.exact.${name}`, displayName: name, origin: null, declared: false });
const internalApp = fixtureApp('test', join(internal, 'apps/test'), internal);
const externalApp = fixtureApp('external', external, external);
const linkedApp = fixtureApp('linked', linked, linked);
const filteredApp = fixtureApp('filtered', filtered, filtered);
const escapingSymlinkRefused = await rejects(() => snapshotOf(linkedApp, {}, linked), error => error.message.includes('symlink src/main.rs') && error.message.includes('absolute'));
const linkRaceBin = join(fixture, 'link-race-bin');
const linkRaceDone = join(fixture, 'link-race-done');
mkdirSync(linkRaceBin);
const linkRaceGit = spawnSync('which', ['git'], { encoding: 'utf8' }).stdout.trim();
writeFileSync(join(linkRaceBin, 'git'), `#!/bin/sh\n"${linkRaceGit}" "$@"\ncode=$?\ncase " $* " in\n *" write-tree "*)\n if [ ! -e "$EXACT_LINK_RACE_DONE" ]; then\n ln -shf target-two.txt "$EXACT_LINK_RACE_ALIAS"\n : > "$EXACT_LINK_RACE_DONE"\n fi\n ;;\nesac\nexit "$code"\n`);
chmodSync(join(linkRaceBin, 'git'), 0o755);
const linkRacePath = process.env.PATH;
process.env.PATH = `${linkRaceBin}:${linkRacePath}`;
process.env.EXACT_LINK_RACE_DONE = linkRaceDone;
process.env.EXACT_LINK_RACE_ALIAS = join(filtered, 'alias.txt');
let filteredSnapshot;
try { filteredSnapshot = snapshotOf(filteredApp, {}, filtered); }
finally {
process.env.PATH = linkRacePath;
delete process.env.EXACT_LINK_RACE_DONE;
delete process.env.EXACT_LINK_RACE_ALIAS;
rmSync(join(filtered, 'alias.txt'));
symlinkSync('target-one.txt', join(filtered, 'alias.txt'));
}
const filteredMaterialized = materializeSnapshot(filteredSnapshot, deployRun(filteredApp.target, 'filtered'), filteredApp);
const checkoutFilterPreserved = filteredSnapshot.id === filteredSnapshot.commit
&& readFileSync(join(filteredMaterialized.app.dir, 'source.txt'), 'utf8') === 'WORKING SOURCE BYTES\n'
&& !isAbsolute(readlinkSync(join(filteredMaterialized.app.dir, 'inside.txt')))
&& readFileSync(join(filteredMaterialized.app.dir, 'inside.txt'), 'utf8') === 'ONE\n';
const linkedTarget = join(fixture, 'shared-target');
mkdirSync(linkedTarget);
symlinkSync(linkedTarget, join(internal, 'target'));
const projectTmp = join(internal, 'project-tmp');
mkdirSync(projectTmp);
const priorTmp = process.env.TMPDIR;
process.env.TMPDIR = projectTmp;
// Staged additions deleted from disk are absent from the captured worktree;
// they must neither resurrect index bytes nor make git add fail.
writeFileSync(join(internal, 'staged-missing.txt'), 'never captured');
spawnSync('git', ['add', 'staged-missing.txt'], { cwd: internal });
rmSync(join(internal, 'staged-missing.txt'));
const realIndex = spawnSync('git', ['ls-files', '--stage', '-z'], { cwd: internal }).stdout;
let internalSnapshot;
try { internalSnapshot = snapshotOf(internalApp, {}, internal); }
finally {
if (priorTmp === undefined) delete process.env.TMPDIR;
else process.env.TMPDIR = priorTmp;
}
rmSync(join(internal, 'target'));
rmSync(projectTmp, { recursive: true });
// This is the race a before/after fingerprint cannot see: a transient edit
// exists while the bake is being prepared, then the checkout is restored.
writeFileSync(join(internal, 'host/runtime.rs'), 'transient during bake\n');
const cleanRun = deployRun(internalApp.target, 'clean-race');
const cleanMaterialized = materializeSnapshot(internalSnapshot, cleanRun, internalApp);
const cleanRaceBytes = readFileSync(join(cleanMaterialized.exactRoot, 'host/runtime.rs'), 'utf8');
result('capture omits missing staged additions and preserves the real index', !existsSync(join(cleanMaterialized.exactRoot, 'staged-missing.txt'))
&& realIndex.equals(spawnSync('git', ['ls-files', '--stage', '-z'], { cwd: internal }).stdout));
spawnSync('git', ['reset', '--', 'staged-missing.txt'], { cwd: internal });
const projectTmpRejected = relative(internal, cleanMaterialized.sourceRoot).startsWith('..');
writeFileSync(join(internal, 'host/runtime.rs'), 'old\n');
// Restore the live file immediately after the capture freezes its tree. A
// later live status read must not relabel those already-captured bytes as a
// clean HEAD snapshot.
const raceBin = join(fixture, 'race-bin');
const raceDone = join(fixture, 'race-done');
mkdirSync(raceBin);
const realGit = spawnSync('which', ['git'], { encoding: 'utf8' }).stdout.trim();
writeFileSync(join(raceBin, 'git'), `#!/bin/sh\n"${realGit}" "$@"\ncode=$?\ncase " $* " in\n *" write-tree "*|*" --binary "*)\n if [ ! -e "$EXACT_CAPTURE_RACE_DONE" ]; then\n printf 'old\\n' > "$EXACT_CAPTURE_RACE_FILE"\n : > "$EXACT_CAPTURE_RACE_DONE"\n fi\n ;;\nesac\nexit "$code"\n`);
chmodSync(join(raceBin, 'git'), 0o755);
writeFileSync(join(internal, 'host/runtime.rs'), 'transient during capture\n');
const oldPath = process.env.PATH;
process.env.PATH = `${raceBin}:${oldPath}`;
process.env.EXACT_CAPTURE_RACE_FILE = join(internal, 'host/runtime.rs');
process.env.EXACT_CAPTURE_RACE_DONE = raceDone;
let racedSnapshot;
try { racedSnapshot = snapshotOf(internalApp, { dirty: true }, internal); }
finally {
process.env.PATH = oldPath;
delete process.env.EXACT_CAPTURE_RACE_FILE;
delete process.env.EXACT_CAPTURE_RACE_DONE;
}
const racedMaterialized = materializeSnapshot(racedSnapshot, deployRun(internalApp.target, 'atomic-race'), internalApp);
const atomicRaceCaptured = racedSnapshot.dirty && racedSnapshot.id !== racedSnapshot.commit
&& racedSnapshot.changes.some((change) => change.endsWith('host/runtime.rs'))
&& readFileSync(join(racedMaterialized.exactRoot, 'host/runtime.rs'), 'utf8') === 'transient during capture\n'
&& readFileSync(join(internal, 'host/runtime.rs'), 'utf8') === 'old\n';
writeFileSync(join(internal, 'host/runtime.rs'), 'edited\n');
writeFileSync(join(internal, 'apps/test/assets/dist/published.txt'), 'nested edited\n');
writeFileSync(join(internal, 'apps/test/assets/ignored.txt'), 'ignored captured\n');
rmSync(join(internal, 'removed.txt'));
mkdirSync(join(internal, 'target'), { recursive: true });
writeFileSync(join(internal, 'target/generated.bin'), 'not source\n');
mkdirSync(join(internal, 'generated'));
writeFileSync(join(internal, 'generated/output.bin'), 'ignored input root\n');
const siblingRefused = await rejects(() => snapshotOf(internalApp, {}, internal), error => error.message.includes('exact2') && error.message.includes('host/runtime.rs')
&& error.message.includes('assets/ignored.txt') && !error.message.includes('target/generated.bin'));
const dirtySnapshot = snapshotOf(internalApp, { dirty: true }, internal);
writeFileSync(join(internal, 'host/runtime.rs'), 'transient replacement\n');
writeFileSync(join(internal, 'apps/test/assets/dist/published.txt'), 'transient nested replacement\n');
writeFileSync(join(internal, 'apps/test/assets/ignored.txt'), 'transient ignored replacement\n');
const dirtyRun = deployRun(internalApp.target, 'dirty-race');
const dirtyMaterialized = materializeSnapshot(dirtySnapshot, dirtyRun, internalApp);
writeFileSync(join(internal, 'host/runtime.rs'), 'edited\n');
writeFileSync(join(internal, 'apps/test/assets/dist/published.txt'), 'nested edited\n');
writeFileSync(join(internal, 'apps/test/assets/ignored.txt'), 'ignored captured\n');
const capturedDirtyBytes = readFileSync(join(dirtyMaterialized.exactRoot, 'host/runtime.rs'), 'utf8') === 'edited\n'
&& readFileSync(join(dirtyMaterialized.app.dir, 'assets/dist/published.txt'), 'utf8') === 'nested edited\n'
&& readFileSync(join(dirtyMaterialized.app.dir, 'assets/ignored.txt'), 'utf8') === 'ignored captured\n'
&& !existsSync(join(dirtyMaterialized.exactRoot, 'removed.txt'))
&& readFileSync(join(dirtyMaterialized.exactRoot, 'generated/output.bin'), 'utf8') === 'ignored input root\n';
writeFileSync(join(internal, 'apps/test/assets/ignored.txt'), 'ignored changed\n');
const dirtyAgain = snapshotOf(internalApp, { dirty: true }, internal);
const changedSnapshotRefused = await rejects(() => snapshotOf(internalApp, { dirty: true, snapshot: dirtySnapshot.id }, internal), error => error.message.includes('same complete source set'));
const ignoredRootRefused = await rejects(() => snapshotOf(externalApp, {}, exact), error => error.message.includes('cargo') && error.message.includes('generated/value.txt'));
const externalSnapshot = snapshotOf(externalApp, { dirty: true }, exact);
const partialPinRefused = await rejects(() => snapshotOf(externalApp, { dirty: true, snapshot: externalSnapshot.commit }, exact), error => error.message.includes('complete source set'));
const pinned = snapshotOf(externalApp, { dirty: true, snapshot: externalSnapshot.id.slice(0, 12) }, exact);
const externalRun = deployRun(externalApp.target, 'external');
const externalMaterialized = materializeSnapshot(externalSnapshot, externalRun, externalApp);
const stagedGitProbe = spawnSync('git', ['rev-parse', '--show-toplevel'], {
cwd: externalMaterialized.exactRoot, encoding: 'utf8',
});
const stagedGitSealed = stagedGitProbe.status !== 0 && stagedGitProbe.stdout.trim() === '';
const ignoredRootCaptured = readFileSync(join(dirname(externalMaterialized.app.dir), 'cargo-dep/generated/value.txt'), 'utf8')
=== 'ignored repository input\n';
writeFileSync(join(cargoDep, 'shared.txt'), '2\n');
mkdirSync(join(external, '.cargo'));
writeFileSync(join(external, '.cargo/config.toml'), '[env]\nRACE_VALUE="live ancestor"\n');
const stagedRun = spawnSync('cargo', ['run', '--quiet', '--locked'], { cwd: externalMaterialized.app.workspace,
env: { ...process.env, CARGO_TARGET_DIR: join(fixture, 'cargo-target') }, encoding: 'utf8' });
const stagedDependencyStayedCaptured = stagedRun.status === 0 && stagedRun.stdout.trim() === '1:sealed';
rmSync(join(external, '.cargo'), { recursive: true });
writeFileSync(join(cargoDep, 'shared.txt'), '1\n');
// Cargo accepts absolute path dependencies, but an immutable deploy cannot:
// the staged manifest would otherwise reach back into the mutable checkout.
const relativeManifest = readFileSync(join(external, 'Cargo.toml'), 'utf8');
writeFileSync(join(external, 'Cargo.toml'), relativeManifest.replace('../cargo-dep/crates/fixture-dep', join(cargoDep, 'crates/fixture-dep')));
const absoluteSnapshot = snapshotOf(externalApp, { dirty: true }, exact);
writeFileSync(join(cargoDep, 'shared.txt'), '2\n');
const absoluteDependencyRefused = await rejects(() => materializeSnapshot(absoluteSnapshot, deployRun(externalApp.target, 'absolute-dependency'), externalApp), error => error.message.includes('resolves outside the captured source root'));
writeFileSync(join(cargoDep, 'shared.txt'), '1\n');
writeFileSync(join(external, 'Cargo.toml'), relativeManifest);
writeFileSync(join(external, 'Cargo.toml'), `${relativeManifest}\n[[bin]]\nname="outside"\npath=${JSON.stringify(outsideTarget)}\n`);
const absoluteTargetSnapshot = snapshotOf(externalApp, { dirty: true }, exact);
const absoluteTargetRefused = await rejects(() => materializeSnapshot(absoluteTargetSnapshot, deployRun(externalApp.target, 'absolute-target'), externalApp), error => error.message.includes('target outside') && error.message.includes('resolves outside'));
writeFileSync(join(external, 'Cargo.toml'), relativeManifest);
writeFileSync(join(cargoDep, 'crates/fixture-dep/ignored.rs'), 'pub const CAPTURED: bool = true;\n');
const ignoredDependencyRefused = await rejects(() => snapshotOf(externalApp, {}, exact), error => error.message.includes('cargo') && error.message.includes('crates/fixture-dep/ignored.rs'));
const dependencyDirty = snapshotOf(externalApp, { dirty: true }, exact);
const dependencyRun = deployRun(externalApp.target, 'external-dependency');
const dependencyMaterialized = materializeSnapshot(dependencyDirty, dependencyRun, externalApp);
const capturedDependency = readFileSync(join(dirname(dependencyMaterialized.app.dir), 'cargo-dep/crates/fixture-dep/ignored.rs'), 'utf8')
=== 'pub const CAPTURED: bool = true;\n';
rmSync(join(cargoDep, 'crates/fixture-dep/ignored.rs'));
const rendered = renderTable({ release: 'test', snapshot: externalSnapshot, channel: 'prod',
origin: { kind: 'directory', location: '/origin' }, notes: [], rows: [] });
writeFileSync(join(exact, 'host/runtime.rs'), 'edited\n');
const dependencyRefused = await rejects(() => snapshotOf(externalApp, {}, exact), error => error.message.includes('exact2') && error.message.includes('host/runtime.rs'));
result('deploy snapshots every source repository the bake reads', initialized
&& internalSnapshot.id === internalSnapshot.commit && internalSnapshot.sources.length === 1
&& internalSnapshot.sources[0].roles.join(',') === 'app,exact2'
&& cleanRaceBytes === 'old\n' && projectTmpRejected && checkoutFilterPreserved && atomicRaceCaptured
&& siblingRefused && dirtySnapshot.dirty && dirtySnapshot.id !== dirtyAgain.id
&& capturedDirtyBytes && changedSnapshotRefused
&& dirtySnapshot.changes.some((change) => change.endsWith('host/runtime.rs'))
&& dirtySnapshot.changes.some((change) => change.endsWith('apps/test/assets/dist/published.txt'))
&& dirtySnapshot.changes.some((change) => change.endsWith('apps/test/assets/ignored.txt'))
&& dirtySnapshot.changes.some((change) => change.endsWith('removed.txt'))
&& !dirtySnapshot.changes.some((change) => change.includes('target/generated.bin'))
&& dirtySnapshot.changes.some((change) => change.includes('generated/output.bin'))
&& /^[0-9a-f]{40}$/.test(externalSnapshot.id) && externalSnapshot.id !== externalSnapshot.commit
&& externalSnapshot.sources.length === 3 && partialPinRefused && pinned.id === externalSnapshot.id
&& relative(externalMaterialized.app.dir, externalMaterialized.exactRoot) === '../exact2'
&& stagedDependencyStayedCaptured && absoluteDependencyRefused && absoluteTargetRefused
&& stagedGitSealed && escapingSymlinkRefused
&& ignoredRootRefused && ignoredRootCaptured
&& ignoredDependencyRefused && capturedDependency
&& rendered.includes(`snapshot ${externalSnapshot.id.slice(0, 12)}`)
&& dependencyRefused,
JSON.stringify({ initialized, internalSnapshot, cleanRaceBytes, projectTmpRejected, checkoutFilterPreserved, atomicRaceCaptured,
siblingRefused, dirtySnapshot, dirtyAgain: dirtyAgain.id,
capturedDirtyBytes, changedSnapshotRefused, externalSnapshot, partialPinRefused, pinned: pinned.id,
externalLayout: relative(externalMaterialized.app.dir, externalMaterialized.exactRoot),
stagedDependencyStayedCaptured, absoluteDependencyRefused, absoluteTargetRefused,
stagedGitSealed, escapingSymlinkRefused,
ignoredRootRefused, ignoredRootCaptured,
ignoredDependencyRefused, capturedDependency, dependencyRefused }));
for (const snapshot of snapshots) disposeSnapshot(snapshot);
rmSync(fixture, { recursive: true, force: true });
}
{
const target = mkdtempSync(join(tmpdir(), 'exact-deploy-run-'));
const now = new Date('2026-09-04T12:34:56.789Z');
const ids = new Set(Array.from({ length: 32 }, () => defaultRelease('a'.repeat(40), now)));
const first = deployRun(target, 'same-release');
writeFileSync(join(first, 'still-here'), 'first');
const second = deployRun(target, 'same-release');
result('deploy ids and private stages do not collide in one clock tick', ids.size === 32
&& first !== second && readFileSync(join(first, 'still-here'), 'utf8') === 'first');
rmSync(target, { recursive: true, force: true });
}
// Stream heads point only at immutable blobs. Their immutable audit record is
// prepared before the conditional head swap; a failed record cannot expose a
// head, and a failed head leaves the preceding one and every named blob whole.
{
const dir = mkdtempSync(join(tmpdir(), 'exact-stream-commit-'));
const origin = new DirectoryOrigin(dir);
const compatibilityId = 'c'.repeat(32);
const row = { kind: 'stream', platform: 'linux', channel: 'prod', compatibilityId,
action: 'bundle', changes: [{ name: 'app.plan', change: 'new' }, { name: 'assets/icon.png', change: 'new' }] };
const plan = Buffer.from('plan bytes');
const asset = Buffer.from('asset bytes');
const bundle = { plan: { bytes: plan, sha256: createHash('sha256').update(plan).digest('hex'), formatVersion: 4, kernelSchema: '0'.repeat(16) },
assets: [{ name: 'assets/icon.png', bytes: asset, sha256: createHash('sha256').update(asset).digest('hex') }] };
const app = { id: 'com.exact.test', displayName: 'Test', manifest: { deploy: {} } };
const signer = { keyId: 'test', sign: () => ({ keyId: 'test', ed25519: Buffer.alloc(64).toString('base64') }) };
const racedPath = blobPath('d'.repeat(64));
const raced = await Promise.allSettled([
origin.put(racedPath, Buffer.from('first'), { immutable: true }),
origin.put(racedPath, Buffer.from('second'), { immutable: true }),
]);
const racedBytes = await origin.get(racedPath);
const immutableRaceHeld = raced.filter((attempt) => attempt.status === 'fulfilled').length === 1
&& raced.filter((attempt) => attempt.status === 'rejected').length === 1
&& (racedBytes.equals(Buffer.from('first')) || racedBytes.equals(Buffer.from('second')));
const order = [];
const put = origin.put.bind(origin);
origin.put = async (rel, bytes, options) => { const result = await put(rel, bytes, options); order.push(`put ${rel}`); return result; };
const putHead = origin.putHead.bind(origin);
origin.putHead = async (...args) => { order.push('put head'); return putHead(...args); };
const args = { origin, row, bundle, compat: { id: compatibilityId, inputs: {} }, app, signer,
release: 'one', snapshot: { commit: '0'.repeat(40), dirty: false, changes: [] }, opts: {}, log: () => {} };
await publishStream(args);
const stream = { channel: 'prod', compatibilityId };
const head = await origin.head(stream);
const base = `.exact/prod/${compatibilityId}`;
const recordPath = `${base}/releases/one.json`;
const record = JSON.parse((await origin.get(recordPath)).toString('utf8'));
let reusedRefused = false;
const beforeRetry = order.length;
try { await publishStream(args); }
catch (error) { reusedRefused = error.message.includes('already has an immutable record'); }
const names = await origin.list(base);
// The head names the plan and the asset index as blobs; the index names the asset beside them.
const blobCards = [head.json.plan, head.json.assets];
const listed = readAssetIndex(head.json.assets, await origin.get(blobPath(head.json.assets.sha256)));
// An index the origin cannot serve now is an unavailable row, not a classification that throws.
const outage = Object.create(origin);
outage.get = async (rel) => { if (rel === blobPath(head.json.assets.sha256)) throw new OriginUnavailable('index: HTTP 503'); return origin.get(rel); };
const outageTable = await classify({ app, opts: { platform: [] }, origin: outage, channel: 'prod',
snapshot: { commit: '0'.repeat(40), dirty: false, changes: [], repo: dir }, release: 'next', web: dir, bundle,
builds: { linux: fixtureBuild(compatibilityId, bundle) }, compat: { linux: { id: compatibilityId, inputs: { store: { L: 'A' }, executors: [] } } },
platforms: ['linux'], wantOrigin: false });
const indexOutageUnavailable = outageTable.rows[0]?.action === 'unavailable' && outageTable.rows[0].reason.includes('HTTP 503');
const recordBeforeHead = order.indexOf(`put ${recordPath}`) < order.indexOf('put head');
const interrupted = [];
// Writes: the plan, index and asset blobs, the record, then the head.
for (const moment of ['before', 'after']) for (let stop = 1; stop <= 5; stop++) {
const failedDir = mkdtempSync(join(tmpdir(), `exact-stream-failure-${moment}-${stop}-`));
const failed = new DirectoryOrigin(failedDir);
const oldPlan = Buffer.from('old plan');
const oldBundle = { plan: { ...bundle.plan, bytes: oldPlan, sha256: createHash('sha256').update(oldPlan).digest('hex') }, assets: [] };
await failed.put(blobPath(oldBundle.plan.sha256), oldPlan, { immutable: true });
const oldHead = streamHead({ app, bundle: oldBundle, stream, seq: 1, release: 'old' });
oldHead.signature = signer.sign(oldHead);
const oldBytes = Buffer.from(JSON.stringify(oldHead) + '\n');
await failed.withLock(stream, () => failed.putHead(stream, oldBytes));
const rawPut = failed.put.bind(failed);
let writes = 0;
failed.put = async (...putArgs) => {
writes++;
if (writes === stop && moment === 'before') throw new Error(`injected before write ${stop}`);
const result = await rawPut(...putArgs);
if (writes === stop && moment === 'after') throw new Error(`injected after write ${stop}`);
return result;
};
const rawHead = failed.putHead.bind(failed);
failed.putHead = async (...headArgs) => {
writes++;
if (writes === stop && moment === 'before') throw new Error(`injected before write ${stop}`);
const result = await rawHead(...headArgs);
if (writes === stop && moment === 'after') throw new Error(`injected after write ${stop}`);
return result;
};
let stopped = false;
let result = null;
try { result = await publishStream({ ...args, origin: failed, release: `failed-${moment}-${stop}` }); }
catch (error) { stopped = error.message.includes('injected'); }
const after = await failed.head(stream);
interrupted.push((stop < 5
? stopped && after.bytes.equals(oldBytes)
: moment === 'before'
? stopped && after.bytes.equals(oldBytes)
: result?.action === 'published' && after.json.release === `failed-${moment}-${stop}`)
&& (await failed.get(blobPath(oldBundle.plan.sha256))).equals(oldPlan));
rmSync(failedDir, { recursive: true, force: true });
}
result('stream publication commits immutable blobs and receipt before its head', recordBeforeHead
&& names.join(',') === 'exact.json,releases' && blobCards.every((card) => card.url === `../../blobs/${card.sha256}`)
&& blobCards.every((card) => existsSync(join(dir, '.exact', 'blobs', card.sha256)))
&& listed.length === 1 && listed[0].url === `./${listed[0].sha256}` && existsSync(join(dir, '.exact', 'blobs', listed[0].sha256))
&& canonicalBytes(record.assets).equals(await origin.get(blobPath(head.json.assets.sha256)))
&& record.head.entryDigest === createHash('sha256').update(canonicalBytes(head.json)).digest('hex')
&& record.envelope.signature.keyId === 'test' && immutableRaceHeld && reusedRefused && order.length === beforeRetry
&& interrupted.every(Boolean) && indexOutageUnavailable, JSON.stringify(outageTable.rows[0]));
rmSync(dir, { recursive: true, force: true });
}
// All origin verbs reject links at the root, intermediate, and leaf boundary.
// Locks are permanent OS ownership, independent of age or claimed host/PID.
{
const dir = mkdtempSync(join(tmpdir(), 'exact-origin-handles-'));
const originDir = join(dir, 'origin');
const outside = join(dir, 'outside');
mkdirSync(originDir); mkdirSync(outside);
writeFileSync(join(outside, 'secret'), 'private');
const origin = new DirectoryOrigin(originDir);
const stream = { channel: 'prod', compatibilityId: 'test' };
const refusals = [];
const refuse = async (fn) => { try { await fn(); return false; } catch { return true; } };
symlinkSync(outside, join(originDir, 'escape'));
symlinkSync(join(outside, 'secret'), join(originDir, 'linked'));
symlinkSync(join(outside, 'absent'), join(originDir, 'dangling'));
refusals.push(await refuse(() => origin.get('escape/secret')),
await refuse(() => origin.list('escape')), await refuse(() => origin.get('linked')),
await refuse(() => origin.list('linked')), await refuse(() => origin.put('linked', Buffer.from('public'))),
await refuse(() => origin.put('dangling', Buffer.from('public'))),
await refuse(() => origin.put('escape/new/deep/file', Buffer.from('public'))));
symlinkSync(outside, join(originDir, '.exact'));
refusals.push(await refuse(() => origin.putHead(stream, Buffer.from('{}'))),
await refuse(() => origin.withLock(stream, async () => false)));
rmSync(join(originDir, '.exact'));
await origin.withLock(stream, async () => true);
const lockPath = join(originDir, '.exact/prod/test/.lock');
rmSync(lockPath);
symlinkSync(join(outside, 'secret'), lockPath);
refusals.push(await refuse(() => origin.withLock(stream, async () => false)));
rmSync(lockPath);
const headPath = join(originDir, '.exact/prod/test/exact.json');
symlinkSync(join(outside, 'secret'), headPath);
refusals.push(await refuse(() => origin.putHead(stream, Buffer.from('{}'))));
rmSync(headPath);
refusals.push(await refuse(() => copyStaticTreeIfPresent(join(originDir, 'escape/missing'), join(dir, 'static-candidate'))));
const rootLink = join(dir, 'root-link'); symlinkSync(originDir, rootLink);
refusals.push(await refuse(() => new DirectoryOrigin(rootLink).get('linked')),
await refuse(() => new DirectoryOrigin(rootLink).put('new', Buffer.from('public'))));
let agedHeld = false, otherHostHeld = false, replacedRefused = false, successorHeld = false;
const priorHost = process.env.HOSTNAME;
try {
process.env.HOSTNAME = 'publisher-a';
await origin.withLock(stream, async () => {
utimesSync(lockPath, new Date(0), new Date(0));
agedHeld = await refuse(() => new DirectoryOrigin(originDir).withLock(stream, async () => false));
process.env.HOSTNAME = 'publisher-b';
otherHostHeld = await refuse(() => new DirectoryOrigin(originDir).withLock(stream, async () => false));
renameSync(lockPath, join(dir, 'retired-lock'));
let entered;
const ready = new Promise((resolve) => { entered = resolve; });
let release;
const pending = new Promise((resolve) => { release = resolve; });
const successor = new DirectoryOrigin(originDir);
// Keep the successor held until the old owner's finally has run.
const held = successor.withLock(stream, async () => { entered(); await pending; });
await ready;
replacedRefused = await refuse(() => origin.putHead(stream, Buffer.from('{}')));
origin.successor = { held, release };
});
successorHeld = await refuse(() => new DirectoryOrigin(originDir).withLock(stream, async () => false));
origin.successor.release(); await origin.successor.held;
} finally {
if (priorHost === undefined) delete process.env.HOSTNAME; else process.env.HOSTNAME = priorHost;
}
const reusable = await origin.withLock(stream, async () => true);
await origin.putHead(stream, Buffer.from('{"seq":1}'));
const conditional = await refuse(() => origin.putHead(stream, Buffer.from('{"seq":2}')));
result('origin handles reject every linked boundary and retain exclusive lock ownership',
refusals.every(Boolean) && agedHeld && otherHostHeld && replacedRefused && successorHeld && reusable && conditional
&& readFileSync(join(outside, 'secret'), 'utf8') === 'private' && !existsSync(join(outside, 'new')),
JSON.stringify({ refusals, agedHeld, otherHostHeld, replacedRefused, successorHeld, reusable, conditional }));
rmSync(dir, { recursive: true, force: true });
}
// Asset names must stage as distinct files on every client filesystem, APFS
// included: the publisher refuses what exact-update's check_asset_names
// refuses, before a head is signed or admitted.
{
const refusals = [
[['Logo.png', 'logo.png'], /differ only by case/],
[['a', 'a/b.png'], /is a file where/],
[['deck/B/x.html', 'deck/b'], /is a file where/],
[['caf\u00e9.png'], /not portable/],
[['cafe\u0301.png'], /not portable/],
[['two words.png'], /not portable/],
[['mark.png', 'mark.png'], /twice/],
];
const refused = refusals.map(([names, why]) => { try { portableAssetNames(names); return false; } catch (error) { return why.test(error.message); } });
let accepted = true;
for (const names of [['a/b.png', 'a/c.png', 'A-b_c.1.png'], ['deck/index.html', 'deck/index.html.map'], ['[email protected]', '[email protected]']]) {
try { portableAssetNames(names); } catch { accepted = false; }
}
// Every refused name in one answer, one per line.
try { portableAssetNames(['two words.png', 'Logo.png', 'logo.png', 'ok.png', 'caf\u00e9.png']); accepted = false; }
catch (error) { const lines = error.message.split('\n'); if (lines.length !== 3 || !/two words/.test(lines[0]) || !/differ only by case/.test(lines[1]) || !/caf\u00e9/.test(lines[2])) accepted = false; }
const app = { id: 'com.exact.names', displayName: 'Names', manifest: {} };
const stream = { channel: 'prod', compatibilityId: 'a'.repeat(32) };
const planBytes = Buffer.from('plan');
const card = (name) => ({ name, bytes: Buffer.from(name), sha256: sha256(Buffer.from(name)) });
const bundle = { plan: { bytes: planBytes, sha256: sha256(planBytes), formatVersion: 4, kernelSchema: '0'.repeat(16) }, assets: [card('Logo.png'), card('logo.png')] };
const signingRefused = await rejects(() => streamHead({ app, bundle, stream, seq: 1, release: 'names' }), (error) => /differ only by case/.test(error.message));
// An index another publisher wrote with names that fold together is refused as it is read.
const listed = JSON.parse(streamIndex({ ...bundle, assets: [card('Logo.png')] }).bytes).assets;
const raw = canonicalBytes({ assets: [...listed, { ...listed[0], name: 'logo.png' }] });
let indexProblem = null;
try { readAssetIndex({ url: './x', sha256: sha256(raw), bytes: raw.length, count: 2 }, raw); } catch (error) { indexProblem = error.message; }
// A web root's index is read at any size (a browser loads it); a client's is bounded.
const huge = canonicalBytes({ assets: Array.from({ length: 34000 }, (_, i) => ({ ...listed[0], name: `assets/n${i}` })) });
const hugeCard = { url: './x', sha256: sha256(huge), bytes: huge.length, count: 34000 };
const unbounded = readAssetIndex(hugeCard, huge, { bounded: false }).length === 34000;
const bounded = await rejects(() => readAssetIndex(hugeCard, huge), (error) => /for 34000 assets; the most is 4096\.0 KiB/.test(error.message));
result('a web root reads an index over the client bound; a client refuses it', unbounded && bounded);
// `plans` is optional, as exact-update reads it: an index with a plan asset and no map is read.
const planned = canonicalBytes({ assets: [{ ...listed[0], name: 'plans/card.plan' }] });
let plansOptional = true;
try { readAssetIndex({ url: './x', sha256: sha256(planned), bytes: planned.length, count: 1 }, planned); } catch { plansOptional = false; }
result('an asset index without a plans map is read', plansOptional);
result('the publisher refuses asset names a client filesystem folds together', refused.every(Boolean) && accepted
&& signingRefused && /differ only by case/.test(indexProblem ?? ''), JSON.stringify({ refused, accepted, signingRefused, indexProblem }));
}
// The next seq sits above everything the stream has authenticated: the head
// and every signed immutable release record. A head rolled back on the
// origin (a restored backup, a stale replica) must not hand out a seq
// clients already hold for another bundle.
{
const dir = mkdtempSync(join(tmpdir(), 'exact-seq-floor-'));
const compatibilityId = 'b'.repeat(32);
const stream = { channel: 'prod', compatibilityId };
const { privateKey, publicKey } = generateKeyPairSync('ed25519');
const publicRaw = publicKey.export({ type: 'spki', format: 'der' }).subarray(-32).toString('base64');
const app = { id: 'com.exact.seqfloor', displayName: 'Seq Floor', dir,
manifest: { deploy: { signing: { key: 'test', keys: { test: publicRaw } } } } };
const bundleOf = (text) => {
const plan = Buffer.from(text);
return { plan: { bytes: plan, sha256: sha256(plan), formatVersion: 4, kernelSchema: '0'.repeat(16) }, assets: [] };
};
const published = bundleOf('published plan'), next = bundleOf('next plan');
const signedAt = (seq) => {
const head = streamHead({ app, bundle: published, stream, seq, release: `r${seq}` });
head.cohort = cohortReceipt(fixtureBuild(compatibilityId, published));
head.signature = { keyId: 'test', ed25519: cryptoSign(null, canonicalBytes(head), privateKey).toString('base64') };
return head;
};
const head = signedAt(7);
const headBytes = Buffer.from(JSON.stringify(head) + '\n');
const records = { 'r7.json': signedAt(7), 'r9.json': signedAt(9) };
const tableWith = (names) => classify({ app, opts: { platform: [] },
origin: {
kind: 'directory', describe: () => dir,
get: async (name) => {
const leaf = name.split('/').at(-1);
return names.includes(leaf) ? Buffer.from(JSON.stringify({ envelope: records[leaf] })) : null;
},
head: async () => ({ json: head, bytes: headBytes, sha256: sha256(headBytes) }),
list: async (name) => name.endsWith('/releases') ? names : [],
},
channel: stream.channel, snapshot: { commit: '0'.repeat(40), dirty: false, changes: [], repo: dir },
release: 'next', web: dir, bundle: next, builds: { linux: fixtureBuild(compatibilityId, next) },
compat: { linux: { id: compatibilityId, inputs: { store: { L: 'A' }, executors: [] } } },
platforms: ['linux'], wantOrigin: false });
const rolledBack = await tableWith(['r7.json', 'r9.json']);
const inStep = await tableWith(['r7.json']);
rmSync(dir, { recursive: true, force: true });
result('a rolled-back head allocates above the authenticated release history',
rolledBack.rows[0].action === 'bundle' && rolledBack.rows[0].seq === 10 && inStep.rows[0].seq === 8,
JSON.stringify({ rolledBack: rolledBack.rows[0], inStep: inStep.rows[0] }));
}
{
// LLP 1069.008 D7: the dry run ends with what the app can reach.
const reach = [
{ grant: 'net.fetch https://api.example.com/', purpose: null, enforced: 'runtime (all hosts); CSP (served web)' },
{ grant: 'device.microphone purpose.microphone', purpose: 'Records your takes.', enforced: 'OS prompt (iOS, macOS); Permissions-Policy (served web; a static dist sends none); declared by app.ts' },
];
const table = (rows) => renderTable({ release: 'test', snapshot: { commit: '0'.repeat(40), dirty: false }, channel: 'prod',
origin: { kind: 'directory', location: '/origin' }, notes: [], rows: [], reach: rows }).split('\n');
const shown = table(reach), none = table(null);
result('the dry run prints what the app can reach, with who enforces each line',
shown[1] === 'what this app can reach:' && /^ {2}reach +purpose +enforced by$/.test(shown[2])
&& /^ {2}net\.fetch https:\/\/api\.example\.com\/ +— +runtime \(all hosts\); CSP \(served web\)$/.test(shown[3])
&& shown[4].includes('"Records your takes."') && shown[4].endsWith('declared by app.ts')
&& none.length === 1,
shown.join('\n'));
}
{
const card = { name: 'plans/trains.plan', sha256: 'a'.repeat(64), bytes: Buffer.from('snapshot') };
const app = { id: 'test.widgets', displayName: 'Widgets' };
const bundle = { plan: { bytes: Buffer.from('app'), sha256: 'b'.repeat(64), formatVersion: 5, kernelSchema: '0'.repeat(16) }, assets: [card] };
const head = streamHead({ app, bundle, stream: { channel: 'prod', compatibilityId: 'c'.repeat(32) }, seq: 1, release: 'widgets' });
const index = JSON.parse(streamIndex(bundle).bytes);
result('entry plans index the signed asset cards in the same stream\'s asset index',
JSON.stringify(index.plans.trains) === JSON.stringify(index.assets[0]) && head.assets.count === 1 && head.plans === undefined && head.plan.sha256 === bundle.plan.sha256);
}
test('snapshot plans are public files and authenticated dev generation assets', async () => {
const dir = mkdtempSync(join(tmpdir(), 'exact-public-plans-'));
try {
const body = Buffer.from('snapshot'), name = 'plans/card.plan';
mkdirSync(join(dir, 'plans'));
writeFileSync(join(dir, name), body);
const files = await publicFileCards(dir);
if (!files.some(file => file.name === name && file.bytes === body.length)) throw new Error('entry absent from public cards');
if (readStaticFile(dir, '/' + name)?.body.toString() !== 'snapshot') throw new Error('entry not served');
const epoch = 'b'.repeat(32), captured = captureAssets(dir), cache = join(dir, 'cache');
const id = 'test.widget', plan = Buffer.alloc(36 + id.length);
plan.write('EXPL'); plan.writeUInt32LE(4, 4); plan.writeBigUInt64LE(1n, 16);
plan.writeUInt32LE(id.length, 32); plan.write(id, 36);
const sealed = sealEnvelope({ ...webEnvelope({id,displayName:'Widget'}, plan, assetCards(captured)), dev: {epoch,seq:1} }, `/__dev/generation/${epoch}/1/assets.json`);
captured.set('assets.json', sealed.index); captured.set('exact.json', sealed.bytes);
retainDevGeneration(cache, epoch, 1, captured);
const envelope = JSON.parse(readDevGeneration(cache, `/__dev/generation/${epoch}/1/exact.json`).body);
const index = readDevGeneration(cache, envelope.assets.url).body, listed = readAssetIndex(envelope.assets, index), { plans } = JSON.parse(index);
if (plans.card.name !== name || plans.card.sha256 !== sha256(body) || plans.card.url !== listed[0].url) throw new Error('published index omitted the captured entry');
if (readDevGeneration(cache, `/__dev/generation/${epoch}/1/${name}`)?.body.toString() !== 'snapshot') throw new Error('entry absent from dev generation');
} finally { rmSync(dir, {recursive:true,force:true}); }
});
// The first build may compile the web modules when the machine cache is cold.
test('a production web root serves every authenticated asset card, including activity schemas and types', async () => {
const root = resolve(import.meta.dir, '..');
mkdirSync(join(root, 'target'), {recursive:true});
const dir = mkdtempSync(join(root, 'target/web-activity-root-'));
try {
const id = 'test.activity-root', app = {id, displayName:'Activity root'};
writeFileSync(join(dir, 'app.json'), JSON.stringify({name:app.displayName, app:{id, name:app.displayName}}));
writeFileSync(join(dir, 'app.contract'), 'component App\n view\n text "Activity root"\n');
const bake = join(dir, 'bake'), web = join(dir, 'web'), origin = new DirectoryOrigin(join(dir, 'origin'));
const build = (out, args = []) => {
const run = spawnSync(process.execPath, ['host/web-js/build.mjs', 'activity-root', '--out', out, '--render', 'none', ...args],
{cwd:root, env:{...process.env, EXACT_APP_DIR:dir}, encoding:'utf8'});
if (run.status !== 0) throw new Error(run.stdout + run.stderr);
};
build(bake);
for (const [name, body] of [['plans/card.plan', 'snapshot'], ['activities/card.schema.json', '{"type":"object"}'], ['activities/card.d.ts', 'export type State = {};']]) {
mkdirSync(dirname(join(bake, name)), {recursive:true});
writeFileSync(join(bake, name), body);
}
const sealed = sealEnvelope(webEnvelope(app, readFileSync(join(bake, 'app.plan')), assetCards(captureAssets(bake))));
writeFileSync(join(bake, 'assets.json'), sealed.index); writeFileSync(join(bake, 'exact.json'), sealed.bytes);
build(web, ['--production', '--plan', join(bake, 'app.plan')]);
const published = await publishRoot({origin, row:{}, web});
const envelope = JSON.parse(readStaticFile(origin.dir, `/${webReleasePath(published.root)}/exact.json`)?.body ?? 'null');
const listed = readAssetIndex(envelope.assets, readStaticFile(origin.dir, envelope.assets.url)?.body);
if (!listed.some(card => card.name === 'activities/card.schema.json')) throw new Error('activity schema absent from published index');
for (const card of [envelope.plan, ...listed.map(c => ({ ...c, url: new URL(c.url, 'http://o' + envelope.assets.url).pathname }))]) {
const body = readStaticFile(origin.dir, card.url)?.body;
if (!body || body.length !== card.bytes || sha256(body) !== card.sha256) throw new Error(`published card is not served: ${card.url}`);
}
rmSync(join(web, 'activities/card.schema.json'));
if (!await rejects(() => publishRoot({origin, row:{}, web}), error => error.message.includes('web envelope does not bind activities/card.schema.json'))) throw new Error('missing asset was published');
} finally { rmSync(dir, {recursive:true,force:true}); }
}, 300000);
// A TypeScript app with a Live Activity: the Apple bake's generation lists the module pair, which the web bundle
// carries as its own module, so the macOS stream's bundle adds the pair the bake made beside its receipt.
test('a native stream of a TypeScript app with a Live Activity publishes the module pair its bake made', () => {
const dir = mkdtempSync(join(tmpdir(), 'exact-hold-bundles-'));
try {
const card = (name, body) => ({ name, bytes: Buffer.from(body), sha256: sha256(Buffer.from(body)) });
const plan = card('app.plan', 'plan'), activity = card('plans/departure.plan', 'activity');
const pair = [card('typescript/app.hbc', 'bytecode'), card('typescript/app.module.json', '{}')];
const graph = (cards) => ({ artifacts: cards.map(({ name, bytes, sha256 }) => ({ name, sha256, bytes: bytes.length, kind: 'bundle', requires: {} })) });
const builds = {
web: { compat: { target: 'wasm32-unknown-unknown', inputs: { platform: 'web' } }, graph: graph([plan, activity]) },
macos: { compat: { target: 'aarch64-apple-darwin', inputs: { platform: 'macos' } }, graph: graph([plan, activity, ...pair]) },
};
const entries = join(dir, 'macos-aarch64-apple-darwin.entries');
mkdirSync(join(entries, 'typescript'), { recursive: true });
for (const { name, bytes } of pair) writeFileSync(join(entries, name), bytes);
const fresh = () => ({ plan: { sha256: plan.sha256, bytes: plan.bytes }, assets: [activity] });
const bundle = fresh();
holdBundles(bundle, builds, dir);
expect(bundle.assets.map((a) => a.name)).toEqual(['plans/departure.plan']);
expect(Object.keys(bundle.platforms)).toEqual(['macos']);
expect(bundle.platforms.macos.assets.map((a) => [a.name, a.bytes.toString()]))
.toEqual([['plans/departure.plan', 'activity'], ['typescript/app.hbc', 'bytecode'], ['typescript/app.module.json', '{}']]);
// The pair is held to the graph's digests, and any other difference still refuses.
writeFileSync(join(entries, 'typescript/app.hbc'), 'edited');
expect(() => holdBundles(fresh(), builds, dir)).toThrow('typescript/app.hbc');
writeFileSync(join(entries, 'typescript/app.hbc'), 'bytecode');
builds.macos.graph.artifacts.push({ name: 'plans/other.plan', sha256: sha256(Buffer.from('x')), bytes: 1, kind: 'bundle', requires: {} });
expect(() => holdBundles(fresh(), builds, dir)).toThrow('macos bake graph differs from the packaged bundle');
} finally { rmSync(dir, { recursive: true, force: true }); }
});
// A game's baked texture: the web root carries its three files, and each Apple stream the one family its
// bake's roster holds (scripts/texture-families.mjs).
test('a native stream publishes only the texture family its platform reads', () => {
const dir = mkdtempSync(join(tmpdir(), 'exact-hold-textures-'));
try {
const card = (name) => ({ name, bytes: Buffer.from(name), sha256: sha256(Buffer.from(name)) });
const plan = card('app.plan'), model = card('assets/fox.model');
const [rgba, bc, astc] = ['assets/fox/0.tex', 'assets/fox/0.bc.tex', 'assets/fox/0.astc.tex'].map(card);
const graph = (cards) => ({ artifacts: cards.map(({ name, bytes, sha256 }) => ({ name, sha256, bytes: bytes.length, kind: 'bundle', requires: {} })) });
const builds = {
web: { compat: { inputs: { platform: 'web' } }, graph: graph([plan, model, rgba, bc, astc]) },
macos: { compat: { inputs: { platform: 'macos', textureFamily: 'bc' } }, graph: graph([plan, model, bc]) },
ios: { compat: { inputs: { platform: 'ios', textureFamily: 'astc' } }, graph: graph([plan, model, astc]) },
};
const bundle = { plan: { sha256: plan.sha256, bytes: plan.bytes }, assets: [model, rgba, bc, astc] };
holdBundles(bundle, builds, dir);
expect(bundle.assets.length).toBe(4);
expect(Object.keys(bundle.platforms)).toEqual(['macos', 'ios']);
expect(bundle.platforms.macos.assets.map((a) => a.name)).toEqual(['assets/fox.model', 'assets/fox/0.bc.tex']);
expect(bundle.platforms.ios.assets.map((a) => a.name)).toEqual(['assets/fox.model', 'assets/fox/0.astc.tex']);
// A stream of an iOS cohort baked with ASTC alone is sent ASTC; one baked before thinning, every file.
expect(streamBundle(bundle, 'ios', { textureFamily: 'astc' }).assets.map((a) => a.name)).toEqual(['assets/fox.model', 'assets/fox/0.astc.tex']);
expect(streamBundle(bundle, 'ios', { platform: 'ios' }).assets.map((a) => a.name).sort()).toEqual(['assets/fox.model', 'assets/fox/0.astc.tex', 'assets/fox/0.bc.tex', 'assets/fox/0.tex']);
// A macOS bake that kept another family differs from the bundle its stream publishes.
builds.macos.graph = graph([plan, model, bc, astc]);
expect(() => holdBundles({ plan: bundle.plan, assets: [model, rgba, bc, astc] }, builds, dir)).toThrow('macos bake graph differs from the packaged bundle');
// A bake that thinned nothing names no family, and its stream publishes every file.
builds.macos = { compat: { inputs: { platform: 'macos' } }, graph: graph([plan, model, rgba, bc, astc]) };
const whole = { plan: bundle.plan, assets: [model, rgba, bc, astc] };
holdBundles(whole, builds, dir);
expect(Object.keys(whole.platforms)).toEqual(['ios']);
} finally { rmSync(dir, { recursive: true, force: true }); }
});
test('adding editing and removing only a sunset publishes a new signed sequence', async () => {
const { privateKey, publicKey } = generateKeyPairSync('ed25519');
const app = { id: 'com.exact.sunset', displayName: 'Sunset', manifest: { deploy: { signing: { key: 'test', keys: { test: publicKey.export({ type: 'spki', format: 'der' }).subarray(-32).toString('base64') } } } } };
const signer = { keyId: 'test', sign: head => ({ keyId: 'test', ed25519: cryptoSign(null, canonicalBytes(head), privateKey).toString('base64') }) };
const stream = { channel: 'prod', compatibilityId: 'a'.repeat(32) };
const bytes = Buffer.from('same plan');
const bundle = { plan: { bytes, sha256: sha256(bytes), formatVersion: 4, kernelSchema: '0'.repeat(16) }, assets: [] };
const initial = streamHead({ app, bundle, stream, seq: 7, release: 'first' });
initial.signature = signer.sign(initial);
const path = `.exact/prod/${stream.compatibilityId}/exact.json`;
const files = new Map([[path, Buffer.from(JSON.stringify(initial))]]);
let writes = 0;
const origin = {
describe: () => 'memory', get: async name => files.get(name) ?? null,
head: async () => { const bytes = files.get(path); return { bytes, sha256: sha256(bytes), json: JSON.parse(bytes) }; },
list: async prefix => [...files.keys()].filter(name => name.startsWith(`${prefix}/`)).map(name => name.slice(prefix.length + 1)).filter(name => !name.includes('/')),
withLock: async (_, fn) => fn(),
put: async (name, bytes) => { files.set(name, bytes); writes++; return 'written'; },
putHead: async (_, bytes, { previousDigest }) => { expect(sha256(files.get(path))).toBe(previousDigest); files.set(path, bytes); writes++; },
};
const row = { kind: 'stream', platform: 'linux', ...stream, action: 'bundle', changes: [] };
const compat = { id: stream.compatibilityId, inputs: {} };
let seq = 7;
for (const sunset of [{ message: 'Retiring' }, { message: 'Install the next binary', store: 'https://example.test' }, null]) {
app.manifest.deploy.sunset = { [`prod/${stream.compatibilityId}`]: sunset };
const published = await publishStream({ origin, row, bundle, compat, app, signer, release: `change-${seq}`, snapshot: { commit: '0'.repeat(40), dirty: false }, opts: {}, log() {} });
expect(published.seq).toBe(++seq);
const head = await origin.head();
expect(head.json.sunset ?? null).toEqual(sunset);
expect(inspectHead(head, app, stream).authenticated).toBe(true);
const before = writes;
const again = await publishStream({ origin, row, bundle, compat, app, signer, release: `same-${seq}`, snapshot: { commit: '0'.repeat(40), dirty: false }, opts: {}, log() {} });
expect(again.action).toBe('current');
expect(writes).toBe(before);
}
});
// The captured deploy with producer boundaries doubled: an existing iOS stream must reach classification on Linux.
test.each(['new', 'invalid', 'authenticated'])('deploy skips a native bake only for an authenticated cohort (%s)', async state => {
const root = mkdtempSync(resolve(import.meta.dir, '../target/deploy-bundle-'));
const sourceRoot = resolve(root, 'exact-source-capture-fixture/source'), exactRoot = resolve(sourceRoot, 'exact');
const app = { id: 'com.exact.bundle', name: 'bundle', displayName: 'Bundle', dir: exactRoot, workspace: exactRoot, target: root,
manifest: { host: { ios: {} }, deploy: { signing: { key: 'test', keys: { test: 'public' } } } } };
const bundle = { plan: { bytes: Buffer.from('plan'), sha256: sha256(Buffer.from('plan')), formatVersion: 4, kernelSchema: '0'.repeat(16) }, assets: [] };
const build = fixtureBuild('a'.repeat(32), bundle);
build.trust = 'production';
build.compat.inputs = { platform: 'ios', store: { L: 'A' }, keys: { test: 'public' }, executors: [] };
const cohort = cohortReceipt(build), stream = { channel: 'prod', compatibilityId: build.compat.id };
const calls = [], output = [];
const bindings = {
ROOT: exactRoot, canonicalPath: x => x, basename: path => path.split('/').at(-1), dirname, inside: (parent, child) => child.startsWith(parent + '/'),
process: { env: {}, stderr: { write() {} } }, console: { log: text => output.push(text) },
resolveApp: () => app, requireReleasePins() {}, channelOf: () => 'prod', validateChannel: x => x,
channelOrigin: () => root, openOrigin: () => ({ writable: true, describe: () => root }), nativePlatforms: () => ['ios'],
loadSigner: () => ({ keyId: 'test' }), namesNative: () => true,
bake: () => root, bakeJs: () => root, readBundle: () => bundle, readBuilds: () => [{ ...build, compat: { ...build.compat, inputs: { ...build.compat.inputs, platform: 'web' } } }],
buildFor: () => { calls.push('native bake'); return build; },
holdBundles() {}, rustPackage: () => false, resolve, sealedSourceEnv: (_, env) => env,
streams: async () => state === 'authenticated' ? [{ stream, head: {}, cohort, platform: 'ios' }] : state === 'new' ? [] : [{ stream, platform: 'ios', problem: 'unauthenticated' }],
streamCandidates: async () => [{ row: { kind: 'stream', platform: 'ios', ...stream }, compat: build.compat, build, bundle }],
classify: async () => ({ snapshot: {}, rows: [{ kind: 'stream', platform: 'ios', ...stream, receipt: cohort, action: 'bundle' }] }),
streamBundle, publishStream: async () => { calls.push('publish'); return { kind: 'stream', action: 'published', seq: 8, head: { sha256: 'b'.repeat(64) } }; },
refuse: message => { throw Error(message); },
};
const source = readFileSync(DEPLOY, 'utf8');
const fn = source.slice(source.indexOf('async function deployCaptured('), source.indexOf('/** An explicitly supplied'));
const deploy = new Function(...Object.keys(bindings), fn + ';return deployCaptured;')(...Object.values(bindings));
try {
expect(await deploy({ _: ['bundle'], platform: ['ios'], keys: root, yes: true, json: true }, {
version: 1, run: resolve(root, 'run'), sourceRoot, exactRoot, release: 'update', app,
snapshot: { id: 'snapshot', sources: [{ repo: resolve(root, 'live'), roles: ['exact'], commit: 'a'.repeat(40) }] }, receipts: [],
})).toBe(0);
expect(calls).toEqual(state === 'authenticated' ? ['publish'] : ['native bake', 'publish']);
expect(JSON.parse(output.at(-1)).published[0].seq).toBe(8);
} finally { rmSync(root, { recursive: true, force: true }); }
});