@kungfu-tech/buildchain 2.8.8-alpha.6 → 2.8.8-alpha.7

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.
@@ -123,6 +123,9 @@ if (rootPackage.exports?.["./release-passport"] !== "./packages/core/release-pas
123
123
  if (rootPackage.exports?.["./release-propagation"] !== "./packages/core/release-propagation.js") {
124
124
  throw new Error("root package must export @kungfu-tech/buildchain/release-propagation");
125
125
  }
126
+ if (rootPackage.exports?.["./surface-manifest"] !== "./packages/core/surface-manifest.js") {
127
+ throw new Error("root package must export @kungfu-tech/buildchain/surface-manifest");
128
+ }
126
129
  if (rootPackage.exports?.["./buildchain-kfd-claims"] !== "./packages/core/buildchain-kfd-claims.js") {
127
130
  throw new Error("root package must export @kungfu-tech/buildchain/buildchain-kfd-claims");
128
131
  }
@@ -193,9 +196,18 @@ if (!coreIndexSource.includes("KFD2_RELEASE_TRUST_PASSPORT_CONTRACT")) {
193
196
  if (!coreIndexSource.includes("KFD2_TRUST_PROOF_CONTRACT")) {
194
197
  throw new Error("packages/core/index.js must export KFD-2 trust proof contract");
195
198
  }
199
+ if (!coreIndexSource.includes("createSurfaceTimestampPolicy")) {
200
+ throw new Error("packages/core/index.js must export surface manifest timestamp policy APIs");
201
+ }
196
202
  if (siteBundle.contract !== "kungfu-buildchain-site-bundle") {
197
203
  throw new Error("buildchain-site.json must expose the Buildchain site bundle contract");
198
204
  }
205
+ if (siteBundle.package?.version !== rootPackage.version) {
206
+ throw new Error("buildchain-site.json package.version must match package.json version");
207
+ }
208
+ if (siteManifest.package?.version !== rootPackage.version) {
209
+ throw new Error("site-manifest.json package.version must match package.json version");
210
+ }
199
211
  if (siteBundle.source?.homepageTextSource !== "README.md") {
200
212
  throw new Error("buildchain-site.json source.homepageTextSource must be README.md");
201
213
  }
@@ -241,6 +253,20 @@ if (siteBundle.pageRegistry?.path !== "page-registry.json" || siteBundle.pageReg
241
253
  if (!siteManifest.facts?.includes("page-registry.json") || !siteBundle.entrypoints?.includes("page-registry.json")) {
242
254
  throw new Error("site bundle entrypoints must include page-registry.json");
243
255
  }
256
+ for (const [name, manifest] of [["buildchain-site.json", siteBundle], ["site-manifest.json", siteManifest]]) {
257
+ if (!manifest.generatedAt) {
258
+ throw new Error(`${name} must expose generatedAt`);
259
+ }
260
+ if (manifest.timestampPolicy === "ci-injected" && manifest.generatedAt === "1970-01-01T00:00:00.000Z") {
261
+ throw new Error(`${name} must not use epoch generatedAt when timestampPolicy=ci-injected`);
262
+ }
263
+ if (!manifest.timestampPolicy || !manifest.reproducible || !Array.isArray(manifest.deterministicInputs)) {
264
+ throw new Error(`${name} must expose the Buildchain surface timestamp/reproducibility policy`);
265
+ }
266
+ if (manifest.timestampPolicyDetails?.contract !== "kungfu-buildchain-surface-timestamp-policy") {
267
+ throw new Error(`${name} must expose timestampPolicyDetails.contract`);
268
+ }
269
+ }
244
270
  function immediateReadmes(dir) {
245
271
  const absoluteDir = path.join(root, dir);
246
272
  if (!fs.existsSync(absoluteDir)) return [];
@@ -8,6 +8,7 @@ import {
8
8
  BUILDCHAIN_AGENT_MANUALS,
9
9
  createBuildchainKfdClaimRegistry,
10
10
  } from "../packages/core/buildchain-kfd-claims.js";
11
+ import { createSurfaceTimestampPolicy } from "../packages/core/surface-manifest.js";
11
12
 
12
13
  const SITE_BUNDLE_CONTRACT = "kungfu-buildchain-site-bundle";
13
14
  const README_PATH = "README.md";
@@ -31,6 +32,10 @@ function stableJson(value) {
31
32
  return `${JSON.stringify(value, null, 2)}\n`;
32
33
  }
33
34
 
35
+ function env(name) {
36
+ return String(process.env[name] || "").trim();
37
+ }
38
+
34
39
  function sha256File(rel) {
35
40
  const filePath = path.join(root, rel);
36
41
  return fs.existsSync(filePath) && fs.statSync(filePath).isFile()
@@ -215,6 +220,30 @@ function buildSiteBundle() {
215
220
  const readme = parseReadme(readText(README_PATH));
216
221
  const docs = BUILDCHAIN_AGENT_MANUALS.map((manual) => docEntry(manual.id, manual.title, manual.path, manual.plane));
217
222
  const pages = buildSitePages();
223
+ const generatedAtInput = env("BUILDCHAIN_SITE_GENERATED_AT") || env("BUILDCHAIN_SURFACE_GENERATED_AT");
224
+ const publishedAtInput = env("BUILDCHAIN_SITE_PUBLISHED_AT") || env("BUILDCHAIN_SURFACE_PUBLISHED_AT");
225
+ const timestampPolicyInput = env("BUILDCHAIN_SITE_TIMESTAMP_POLICY") || env("BUILDCHAIN_SURFACE_TIMESTAMP_POLICY");
226
+ const sourceRevisionInput =
227
+ env("BUILDCHAIN_SOURCE_SHA") ||
228
+ (generatedAtInput || publishedAtInput || timestampPolicyInput ? env("GITHUB_SHA") : "");
229
+ const timestampPolicy = createSurfaceTimestampPolicy({
230
+ generatedAt: generatedAtInput,
231
+ publishedAt: publishedAtInput,
232
+ sourceDateEpoch: env("SOURCE_DATE_EPOCH") || "0",
233
+ sourceRevision: sourceRevisionInput,
234
+ timestampPolicy: timestampPolicyInput,
235
+ deterministicInputs: [
236
+ "README.md",
237
+ "docs/*.md",
238
+ "actions/*/README.md",
239
+ "fixtures/*/README.md",
240
+ "packages/core/README.md",
241
+ "package.json#exports",
242
+ "tests/buildchain-inventory.json",
243
+ ],
244
+ timestampFieldsParticipateInArtifactDigest: true,
245
+ artifactDigestScope: "npm package dist/site JSON files",
246
+ });
218
247
 
219
248
  const cliRegistry = {
220
249
  schemaVersion: 1,
@@ -438,6 +467,7 @@ function buildSiteBundle() {
438
467
  const siteManifest = {
439
468
  schemaVersion: 1,
440
469
  contract: "kungfu-buildchain-site-manifest",
470
+ ...timestampPolicy,
441
471
  product: {
442
472
  name: "Buildchain",
443
473
  formalName: "Buildchain by Kungfu",
@@ -445,6 +475,7 @@ function buildSiteBundle() {
445
475
  },
446
476
  package: {
447
477
  name: packageJson.name,
478
+ version: packageJson.version,
448
479
  versionSource: "package.json#version",
449
480
  },
450
481
  entrypoint: "buildchain-site.json",
@@ -549,6 +580,7 @@ function buildSiteBundle() {
549
580
  const siteBundle = {
550
581
  schemaVersion: 1,
551
582
  contract: SITE_BUNDLE_CONTRACT,
583
+ ...timestampPolicy,
552
584
  product: siteManifest.product,
553
585
  package: siteManifest.package,
554
586
  source: {
@@ -5,6 +5,7 @@ import fs from "node:fs";
5
5
  import os from "node:os";
6
6
  import path from "node:path";
7
7
  import { loadBuildchainConfig, validateBuildchainConfig } from "../packages/core/buildchain-config.js";
8
+ import { createSurfaceTimestampPolicy } from "../packages/core/surface-manifest.js";
8
9
 
9
10
  const DEFAULT_RETENTION = Object.freeze({
10
11
  preview: {
@@ -609,9 +610,27 @@ export function createWebSurfaceDeploymentManifest({
609
610
  deployConfig,
610
611
  });
611
612
  const primaryBinding = surfaceBindings[0];
613
+ const timestampPolicy = createSurfaceTimestampPolicy({
614
+ generatedAt: deployedAt,
615
+ publishedAt: deployedAt,
616
+ sourceRevision: sourceSha,
617
+ timestampPolicy: "ci-injected",
618
+ deterministicInputs: [
619
+ "web-surface artifact content",
620
+ "buildchain.toml web-surface channels/deploy/surfaces",
621
+ "sourceSha",
622
+ "artifactHash",
623
+ "deployment channel",
624
+ "deployment alias",
625
+ ],
626
+ timestampFields: ["generatedAt", "publishedAt", "deployedAt"],
627
+ timestampFieldsParticipateInArtifactDigest: false,
628
+ artifactDigestScope: "web-surface artifactHash excludes deployment manifest timestamps",
629
+ });
612
630
  return {
613
631
  schemaVersion: 1,
614
632
  contract: "kungfu-buildchain-web-surface-deployment",
633
+ ...timestampPolicy,
615
634
  site: config.project.site || config.project.name || "",
616
635
  channel,
617
636
  alias,
@@ -77,6 +77,10 @@ export function webSurfaceCli() {
77
77
  "alias",
78
78
  process.env.BUILDCHAIN_WEB_SURFACE_ALIAS || defaultWebSurfaceAlias({ channel, sourceSha, pullNumber }),
79
79
  );
80
+ const generatedAt = readArg(
81
+ "generated-at",
82
+ process.env.BUILDCHAIN_SITE_GENERATED_AT || process.env.BUILDCHAIN_SURFACE_GENERATED_AT || "",
83
+ );
80
84
  const result = planWebSurfaceDeploy({
81
85
  cwd,
82
86
  channel,
@@ -89,6 +93,7 @@ export function webSurfaceCli() {
89
93
  rollbackPointer: readArg("rollback-pointer", process.env.BUILDCHAIN_ROLLBACK_REF || ""),
90
94
  rollbackLimitations: readArg("rollback-limitations", process.env.BUILDCHAIN_ROLLBACK_LIMITATIONS || ""),
91
95
  dryRun: readBooleanArg("dry-run", true),
96
+ ...(generatedAt ? { deployedAt: generatedAt } : {}),
92
97
  });
93
98
  const outputResult = mode === "manifest" ? result.manifest : result;
94
99
  writeJson(outputResult, output);
@@ -111,6 +116,10 @@ export function webSurfaceCli() {
111
116
  "alias",
112
117
  process.env.BUILDCHAIN_WEB_SURFACE_ALIAS || defaultWebSurfaceAlias({ channel, sourceSha, pullNumber }),
113
118
  );
119
+ const publishedAt = readArg(
120
+ "published-at",
121
+ process.env.BUILDCHAIN_SITE_PUBLISHED_AT || process.env.BUILDCHAIN_SURFACE_PUBLISHED_AT || "",
122
+ );
114
123
  const result = applyWebSurfaceDeploy({
115
124
  cwd,
116
125
  channel,
@@ -122,6 +131,7 @@ export function webSurfaceCli() {
122
131
  dryRun: readBooleanArg("dry-run", true),
123
132
  actor: readArg("actor", process.env.GITHUB_ACTOR || ""),
124
133
  runId: readArg("run-id", process.env.GITHUB_RUN_ID || ""),
134
+ ...(publishedAt ? { appliedAt: publishedAt } : {}),
125
135
  });
126
136
  writeJson(result, output);
127
137
  writeGitHubOutputs({