@kungfu-tech/buildchain 3.0.6-alpha.3 → 3.0.6-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -148,7 +148,11 @@ function candidateArtifactNames({ passport, selected, artifacts, artifactPattern
148
148
  if (!reference.artifact) throw new Error(`Passport controller receipt ${reference.controllerId} has no artifact identity`);
149
149
  names.add(reference.artifact);
150
150
  }
151
- for (const platform of passport.platformMatrix || []) names.add(platform.artifactName);
151
+ for (const platform of passport.platformMatrix || []) {
152
+ names.add(platform.artifactName);
153
+ const diagnosticsArtifactName = `${selected.prefix}-diagnostics-${platform.platformId}-${selected.sourceSha}`;
154
+ if (artifacts.some((artifact) => artifact.name === diagnosticsArtifactName)) names.add(diagnosticsArtifactName);
155
+ }
152
156
  const manifestPattern = new RegExp(`^${selected.prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}-manifest-.+-${selected.sourceSha}$`);
153
157
  for (const artifact of artifacts) {
154
158
  if (manifestPattern.test(String(artifact.name || ""))) names.add(artifact.name);
@@ -162,18 +166,42 @@ function candidateArtifactNames({ passport, selected, artifacts, artifactPattern
162
166
 
163
167
  function normalizePlatformManifests(downloads, passport) {
164
168
  const manifests = [];
169
+ const evidenceByArtifact = new Map();
170
+ function addEvidence(artifactName, files) {
171
+ if (!artifactName) return;
172
+ const evidenceFiles = evidenceByArtifact.get(artifactName) || new Map();
173
+ for (const file of files) {
174
+ const existing = evidenceFiles.get(file.path);
175
+ if (existing && (existing.size !== file.size || existing.sha256 !== file.sha256)) {
176
+ throw new Error(`platform evidence disagrees for ${artifactName}/${file.path}`);
177
+ }
178
+ evidenceFiles.set(file.path, file);
179
+ }
180
+ evidenceByArtifact.set(artifactName, evidenceFiles);
181
+ }
165
182
  for (const download of downloads) {
166
- if (!String(download.artifact.name).includes("-manifest-")) continue;
167
- for (const file of download.files.filter((entry) => path.basename(entry.path) === "manifest.json")) {
183
+ if (String(download.artifact.name).includes("-manifest-")) for (const file of download.files.filter((entry) => path.basename(entry.path) === "manifest.json")) {
168
184
  const manifest = JSON.parse(fs.readFileSync(file.absolutePath, "utf8"));
169
185
  if (!manifest.artifactName) {
170
186
  const platformId = String(manifest.platform?.id || manifest.platformId || "");
171
187
  manifest.artifactName = (passport.platformMatrix || []).find((entry) => entry.platformId === platformId)?.artifactName || "";
172
188
  }
173
189
  manifests.push(manifest);
190
+ addEvidence(manifest.artifactName, download.record.files);
191
+ }
192
+ if (String(download.artifact.name).includes("-diagnostics-")) {
193
+ const diagnosticsFiles = download.files.filter((entry) => path.basename(entry.path) === "diagnostics.json");
194
+ if (diagnosticsFiles.length === 1) {
195
+ const diagnostics = JSON.parse(fs.readFileSync(diagnosticsFiles[0].absolutePath, "utf8"));
196
+ addEvidence(String(diagnostics.links?.artifactName || ""), download.record.files);
197
+ }
174
198
  }
175
199
  }
176
- return manifests;
200
+ const evidence = [...evidenceByArtifact].map(([artifactName, files]) => ({
201
+ artifactName,
202
+ files: [...files.values()].sort((left, right) => left.path.localeCompare(right.path)),
203
+ }));
204
+ return { manifests, evidence };
177
205
  }
178
206
 
179
207
  function normalizeControllerReceipts(downloads, passport) {
@@ -258,9 +286,6 @@ async function recoverCandidateEvidence({
258
286
  for (const artifact of [selected.passport, selected.summary]) initialDownloads.push(await downloadArtifact({ artifact, repoInfo, apiUrl, token, archiveDir, bundleRoot, fetchImpl }));
259
287
  const passport = readOnlyJson(initialDownloads[0].files.filter((file) => path.basename(file.path) === "release-candidate-passport.json"), "release-candidate-passport.json");
260
288
  const buildSummary = readOnlyJson(initialDownloads[1].files.filter((file) => path.basename(file.path) === "build-summary.json"), "build-summary.json");
261
- const candidateVersion = String(passport.target?.version || "").trim();
262
- if (!candidateVersion) throw new Error("Release Candidate Passport has no exact target version");
263
- const existingTransaction = await readExistingTransaction({ repoInfo, apiUrl, token, fetchImpl, version: candidateVersion });
264
289
  const requiredNames = candidateArtifactNames({ passport, selected, artifacts, artifactPatterns });
265
290
  const chosen = artifacts.filter((artifact) => requiredNames.has(artifact.name));
266
291
  if (chosen.length !== requiredNames.size) {
@@ -272,7 +297,7 @@ async function recoverCandidateEvidence({
272
297
  for (const artifact of chosen.filter((entry) => ![selected.passport.id, selected.summary.id].includes(entry.id))) downloads.push(await downloadArtifact({ artifact, repoInfo, apiUrl, token, archiveDir, bundleRoot, fetchImpl }));
273
298
  return {
274
299
  run, workflow, selected, resolvedOutput, bundleRoot, initialDownloads,
275
- passport, buildSummary, candidateVersion, existingTransaction, chosen, downloads,
300
+ passport, buildSummary, chosen, downloads,
276
301
  };
277
302
  }
278
303
 
@@ -311,7 +336,7 @@ export async function resumeFromCandidateRun({
311
336
  try {
312
337
  const {
313
338
  run, workflow, selected, resolvedOutput, bundleRoot, initialDownloads,
314
- passport, buildSummary, candidateVersion, existingTransaction, chosen, downloads,
339
+ passport, buildSummary, chosen, downloads,
315
340
  } = await recoverCandidateEvidence({
316
341
  repoInfo, runId, artifactName, artifactPatterns, requiredArtifactCount,
317
342
  outputDir, apiUrl, token, fetchImpl, archiveDir,
@@ -323,9 +348,20 @@ export async function resumeFromCandidateRun({
323
348
  const targetRefState = await githubJson({ apiUrl, token, fetchImpl, path: `/repos/${repoInfo.owner}/${repoInfo.repo}/git/ref/heads/${targetRef.replace(/^refs\/heads\//, "")}` });
324
349
  if (targetRefState.object?.sha !== targetSha) throw new Error(`target ref ${targetRef} no longer points at ${targetSha}`);
325
350
  const compare = await githubJson({ apiUrl, token, fetchImpl, path: `/repos/${repoInfo.owner}/${repoInfo.repo}/compare/${pullRequest.merge_commit_sha}...${targetSha}` });
326
- const platformManifests = normalizePlatformManifests(downloads, passport);
351
+ const platformManifestEvidence = normalizePlatformManifests(downloads, passport);
327
352
  const controllerReceipts = normalizeControllerReceipts(downloads, passport);
328
353
  const productPayloadManifests = normalizeProductPayloadManifests(downloads);
354
+ const sealed = createSealedBundle({
355
+ downloads,
356
+ bundleRoot,
357
+ repository: repoInfo.fullName,
358
+ passport,
359
+ runtimeSha,
360
+ publishPackageMain,
361
+ releasePatterns,
362
+ });
363
+ const candidateVersion = sealed.manifest.npm.version;
364
+ const existingTransaction = await readExistingTransaction({ repoInfo, apiUrl, token, fetchImpl, version: candidateVersion });
329
365
  const recovery = verifyReleaseCandidateRecovery({
330
366
  candidateRepository: repoInfo.fullName,
331
367
  targetRepository,
@@ -369,21 +405,14 @@ export async function resumeFromCandidateRun({
369
405
  passport,
370
406
  buildSummary,
371
407
  controllerReceipts,
372
- platformManifests,
408
+ platformManifests: platformManifestEvidence.manifests,
409
+ platformManifestEvidence: platformManifestEvidence.evidence,
373
410
  productPayloadManifests,
374
411
  artifacts: downloads.map((download) => download.record),
412
+ publicationVersion: candidateVersion,
375
413
  currentToolingSha: runtimeSha,
376
414
  recoveryRunId,
377
415
  });
378
- const sealed = createSealedBundle({
379
- downloads,
380
- bundleRoot,
381
- repository: repoInfo.fullName,
382
- passport,
383
- runtimeSha,
384
- publishPackageMain,
385
- releasePatterns,
386
- });
387
416
  const recoveryReceiptPath = path.join(resolvedOutput, "recovery-receipt.json");
388
417
  const sealedManifestPath = path.join(resolvedOutput, "sealed-bundle.json");
389
418
  const requiredArtifactsPath = path.join(resolvedOutput, "publish-required-artifacts.json");