@kungfu-tech/buildchain 2.8.8-alpha.6 → 2.8.8-alpha.8
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.
- package/dist/site/buildchain-contract.json +6 -6
- package/dist/site/buildchain-site.json +44 -9
- package/dist/site/kfd-claims.json +13 -1
- package/dist/site/manual-registry.json +3 -3
- package/dist/site/node-api-registry.json +10 -4
- package/dist/site/page-registry.json +11 -6
- package/dist/site/release-provenance.json +1 -0
- package/dist/site/site-manifest.json +33 -3
- package/docs/release-passport.md +4 -0
- package/docs/site-bundle-contract.md +34 -0
- package/docs/web-surface-deployments.md +26 -0
- package/package.json +2 -1
- package/packages/core/index.js +6 -0
- package/packages/core/release-passport.js +20 -1
- package/packages/core/surface-manifest.js +87 -0
- package/scripts/check-inventory.mjs +26 -0
- package/scripts/generate-site-bundle.mjs +60 -0
- package/scripts/web-surface-core.mjs +19 -0
- package/scripts/web-surface.mjs +10 -0
|
@@ -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()
|
|
@@ -42,6 +47,26 @@ function existingJson(filePath) {
|
|
|
42
47
|
return fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf8") : "";
|
|
43
48
|
}
|
|
44
49
|
|
|
50
|
+
function readExistingSiteTimestampPolicy(packageVersion) {
|
|
51
|
+
const manifestPath = path.join(outputDir, "site-manifest.json");
|
|
52
|
+
if (!fs.existsSync(manifestPath)) return null;
|
|
53
|
+
try {
|
|
54
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
55
|
+
if (manifest?.package?.version !== packageVersion) return null;
|
|
56
|
+
if (manifest?.timestampPolicy !== "ci-injected") return null;
|
|
57
|
+
if (!manifest?.generatedAt || manifest.generatedAt === "1970-01-01T00:00:00.000Z") return null;
|
|
58
|
+
return {
|
|
59
|
+
generatedAt: manifest.generatedAt,
|
|
60
|
+
publishedAt: manifest.publishedAt || manifest.generatedAt,
|
|
61
|
+
sourceDateEpoch: manifest.sourceDateEpoch,
|
|
62
|
+
sourceRevision: manifest.sourceRevision,
|
|
63
|
+
timestampPolicy: manifest.timestampPolicy,
|
|
64
|
+
};
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
45
70
|
function normalizeMarkdown(value) {
|
|
46
71
|
return String(value || "").replace(/\r\n/g, "\n").trim();
|
|
47
72
|
}
|
|
@@ -215,6 +240,38 @@ function buildSiteBundle() {
|
|
|
215
240
|
const readme = parseReadme(readText(README_PATH));
|
|
216
241
|
const docs = BUILDCHAIN_AGENT_MANUALS.map((manual) => docEntry(manual.id, manual.title, manual.path, manual.plane));
|
|
217
242
|
const pages = buildSitePages();
|
|
243
|
+
const preservedTimestampPolicy = readExistingSiteTimestampPolicy(packageJson.version);
|
|
244
|
+
const generatedAtInput = env("BUILDCHAIN_SITE_GENERATED_AT") || env("BUILDCHAIN_SURFACE_GENERATED_AT");
|
|
245
|
+
const publishedAtInput = env("BUILDCHAIN_SITE_PUBLISHED_AT") || env("BUILDCHAIN_SURFACE_PUBLISHED_AT");
|
|
246
|
+
const timestampPolicyInput = env("BUILDCHAIN_SITE_TIMESTAMP_POLICY") || env("BUILDCHAIN_SURFACE_TIMESTAMP_POLICY");
|
|
247
|
+
const sourceRevisionEnv = env("BUILDCHAIN_SOURCE_SHA");
|
|
248
|
+
const shouldPreserveExistingTimestampPolicy =
|
|
249
|
+
!generatedAtInput && !publishedAtInput && !timestampPolicyInput && !sourceRevisionEnv;
|
|
250
|
+
const sourceRevisionInput =
|
|
251
|
+
sourceRevisionEnv ||
|
|
252
|
+
(generatedAtInput || publishedAtInput || timestampPolicyInput
|
|
253
|
+
? env("GITHUB_SHA")
|
|
254
|
+
: shouldPreserveExistingTimestampPolicy
|
|
255
|
+
? preservedTimestampPolicy?.sourceRevision || ""
|
|
256
|
+
: "");
|
|
257
|
+
const timestampPolicy = createSurfaceTimestampPolicy({
|
|
258
|
+
generatedAt: generatedAtInput || (shouldPreserveExistingTimestampPolicy ? preservedTimestampPolicy?.generatedAt : ""),
|
|
259
|
+
publishedAt: publishedAtInput || (shouldPreserveExistingTimestampPolicy ? preservedTimestampPolicy?.publishedAt : ""),
|
|
260
|
+
sourceDateEpoch: env("SOURCE_DATE_EPOCH") || (shouldPreserveExistingTimestampPolicy ? preservedTimestampPolicy?.sourceDateEpoch : "") || "0",
|
|
261
|
+
sourceRevision: sourceRevisionInput,
|
|
262
|
+
timestampPolicy: timestampPolicyInput || (shouldPreserveExistingTimestampPolicy ? preservedTimestampPolicy?.timestampPolicy : ""),
|
|
263
|
+
deterministicInputs: [
|
|
264
|
+
"README.md",
|
|
265
|
+
"docs/*.md",
|
|
266
|
+
"actions/*/README.md",
|
|
267
|
+
"fixtures/*/README.md",
|
|
268
|
+
"packages/core/README.md",
|
|
269
|
+
"package.json#exports",
|
|
270
|
+
"tests/buildchain-inventory.json",
|
|
271
|
+
],
|
|
272
|
+
timestampFieldsParticipateInArtifactDigest: true,
|
|
273
|
+
artifactDigestScope: "npm package dist/site JSON files",
|
|
274
|
+
});
|
|
218
275
|
|
|
219
276
|
const cliRegistry = {
|
|
220
277
|
schemaVersion: 1,
|
|
@@ -438,6 +495,7 @@ function buildSiteBundle() {
|
|
|
438
495
|
const siteManifest = {
|
|
439
496
|
schemaVersion: 1,
|
|
440
497
|
contract: "kungfu-buildchain-site-manifest",
|
|
498
|
+
...timestampPolicy,
|
|
441
499
|
product: {
|
|
442
500
|
name: "Buildchain",
|
|
443
501
|
formalName: "Buildchain by Kungfu",
|
|
@@ -445,6 +503,7 @@ function buildSiteBundle() {
|
|
|
445
503
|
},
|
|
446
504
|
package: {
|
|
447
505
|
name: packageJson.name,
|
|
506
|
+
version: packageJson.version,
|
|
448
507
|
versionSource: "package.json#version",
|
|
449
508
|
},
|
|
450
509
|
entrypoint: "buildchain-site.json",
|
|
@@ -549,6 +608,7 @@ function buildSiteBundle() {
|
|
|
549
608
|
const siteBundle = {
|
|
550
609
|
schemaVersion: 1,
|
|
551
610
|
contract: SITE_BUNDLE_CONTRACT,
|
|
611
|
+
...timestampPolicy,
|
|
552
612
|
product: siteManifest.product,
|
|
553
613
|
package: siteManifest.package,
|
|
554
614
|
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,
|
package/scripts/web-surface.mjs
CHANGED
|
@@ -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({
|