Skip to content

Commit 26293c2

Browse files
fix: report package evidence sidecar paths (#672)
* fix: report package evidence sidecar paths * docs: record package evidence diagnostic fix * docs: name package evidence diagnostic
1 parent 9197015 commit 26293c2

4 files changed

Lines changed: 24 additions & 11 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"agent-bundle": patch
3+
---
4+
5+
Report `AB6039` package-only compile-evidence failures against `agent-bundle.package-compile-evidence.json` (#672).

‎packages/agent-bundle/src/build/compile-evidence.ts‎

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,8 @@ export const parseCompileEvidenceRecord = (bytes: string): CompileEvidenceRecord
309309
/** MCP App views are the only compiled HTML documents (`mcp-apps/<name>.html`). */
310310
const isViewAsset = (path: string): boolean => path.endsWith('.html');
311311

312-
const evidenceDiagnostic = (message: string): Diagnostic =>
313-
artifactDiagnostic('AB6039', `Compile evidence ${message}`, compileEvidenceFileName);
312+
const evidenceDiagnostic = (message: string, evidencePath: string): Diagnostic =>
313+
artifactDiagnostic('AB6039', `Compile evidence ${message}`, evidencePath);
314314

315315
/**
316316
* Checks a parsed record against the artifact's file table: every compiled
@@ -322,10 +322,12 @@ const evidenceDiagnostic = (message: string): Diagnostic =>
322322
export const compileEvidenceDiagnostics = (
323323
record: CompileEvidenceRecord,
324324
files: ReadonlyMap<string, { readonly kind: string; readonly sha256: string }>,
325+
evidencePath: string = compileEvidenceFileName,
325326
): readonly Diagnostic[] => {
326327
const diagnostics: Diagnostic[] = [];
328+
const reportEvidence = (message: string): Diagnostic => evidenceDiagnostic(message, evidencePath);
327329
if (record.policy.name !== externalPolicy.name || record.policy.revision !== externalPolicy.revision) {
328-
diagnostics.push(evidenceDiagnostic(
330+
diagnostics.push(reportEvidence(
329331
`was judged under policy ${record.policy.name}@${String(record.policy.revision)}; `
330332
+ `this validator applies ${externalPolicy.name}@${String(externalPolicy.revision)}.`,
331333
));
@@ -334,18 +336,18 @@ export const compileEvidenceDiagnostics = (
334336
const compiled = new Set([...files].filter(([, file]) => file.kind === 'bundle').map(([path]) => path));
335337
for (const path of compiled) {
336338
const asset = recorded.get(path);
337-
if (asset === undefined) diagnostics.push(evidenceDiagnostic(`does not cover compiled file ${JSON.stringify(path)}.`));
338-
else if (asset.sha256 !== files.get(path)!.sha256) diagnostics.push(evidenceDiagnostic(`for ${JSON.stringify(path)} describes different bytes.`));
339+
if (asset === undefined) diagnostics.push(reportEvidence(`does not cover compiled file ${JSON.stringify(path)}.`));
340+
else if (asset.sha256 !== files.get(path)!.sha256) diagnostics.push(reportEvidence(`for ${JSON.stringify(path)} describes different bytes.`));
339341
}
340342
// A view (an HTML document) inlines every module it loads; only node bundles may load a sibling, and only another node bundle.
341343
const nodeBundles = new Set([...compiled].filter((path) => !isViewAsset(path)));
342344
for (const asset of record.assets) {
343345
if (!compiled.has(asset.path)) {
344-
diagnostics.push(evidenceDiagnostic(`names ${JSON.stringify(asset.path)}, which the file table does not list as a compiled file.`));
346+
diagnostics.push(reportEvidence(`names ${JSON.stringify(asset.path)}, which the file table does not list as a compiled file.`));
345347
}
346348
for (const external of asset.externals) {
347349
if (isViewAsset(asset.path)) {
348-
diagnostics.push(evidenceDiagnostic(
350+
diagnostics.push(reportEvidence(
349351
`for ${JSON.stringify(asset.path)} records ${JSON.stringify(external.request)} as an external; a view inlines every module it loads.`,
350352
));
351353
continue;
@@ -355,14 +357,14 @@ export const compileEvidenceDiagnostics = (
355357
switch (external.kind) {
356358
case 'builtin':
357359
if (judged !== 'builtin') {
358-
diagnostics.push(evidenceDiagnostic(
360+
diagnostics.push(reportEvidence(
359361
`for ${JSON.stringify(asset.path)} records ${JSON.stringify(external.request)} as a built-in; it is not one.`,
360362
));
361363
}
362364
break;
363365
case 'artifact-relative':
364366
if (judged !== 'artifact-relative' || external.target !== posix.join(posix.dirname(asset.path), external.request)) {
365-
diagnostics.push(evidenceDiagnostic(
367+
diagnostics.push(reportEvidence(
366368
`for ${JSON.stringify(asset.path)} records sibling ${JSON.stringify(external.request)}, which the artifact does not contain.`,
367369
));
368370
}

‎packages/agent-bundle/src/build/pack-inventory.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ export const packInventoryDiagnostics = async (options: {
287287
new Map(options.packageBuild.files
288288
.filter((file) => file.kind === 'bundle' && !artifactPaths.has(file.path))
289289
.map((file) => [file.path, { kind: file.kind, sha256: file.sha256 }])),
290+
packageCompileEvidenceFileName,
290291
));
291292
} catch (error) {
292293
diagnostics.push(diagnostic(

‎packages/agent-bundle/tests/prepack.test.ts‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,13 @@ it('reports package-only compile evidence drift as AB6039', async () => {
191191
const path = join(projectRoot, 'dist', packageCompileEvidenceFileName);
192192
const original = await readFile(path, 'utf8');
193193
try {
194-
await writeFile(path, '{"assets":[]}\n');
195-
expect(await diagnostics()).toContainEqual(expect.objectContaining({ code: 'AB6039' }));
194+
const evidence = JSON.parse(original) as { policy: { revision: number } };
195+
evidence.policy.revision += 1;
196+
await writeFile(path, `${JSON.stringify(evidence)}\n`);
197+
expect(await diagnostics()).toContainEqual(expect.objectContaining({
198+
code: 'AB6039',
199+
generatedPath: packageCompileEvidenceFileName,
200+
}));
196201
} finally {
197202
await writeFile(path, original);
198203
}

0 commit comments

Comments
 (0)