@kungfu-tech/buildchain 2.14.19-alpha.0 → 2.14.19-alpha.2
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/README.md +3 -0
- package/dist/site/buildchain-contract.json +60 -10
- package/dist/site/buildchain-site.json +69 -14
- package/dist/site/capability-registry.json +4 -3
- package/dist/site/kfd-claims.json +56 -8
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +16 -2
- package/dist/site/node-api-registry.json +3 -3
- package/dist/site/page-registry.json +54 -7
- package/dist/site/public-surface-audit.json +45 -6
- package/dist/site/publication-authority-registry.json +19 -1
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/site-manifest.json +14 -6
- package/dist/site/workflow-registry.json +40 -2
- package/docs/MAP.md +1 -0
- package/docs/auditable-demo.md +155 -0
- package/docs/versioning.md +1 -0
- package/package.json +1 -1
- package/packages/core/buildchain-contract.js +45 -0
- package/packages/core/buildchain-kfd-claims.js +1 -0
- package/packages/core/buildchain-publication-authority.js +1 -0
- package/scripts/auditable-demo.mjs +576 -0
- package/scripts/check-inventory.mjs +4 -0
- package/scripts/generate-site-bundle.mjs +3 -0
- package/scripts/resolve-artifact-coordinates.mjs +174 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
resolveArtifactContract,
|
|
8
|
+
writeGitHubOutputs,
|
|
9
|
+
} from "./build-contract-core.mjs";
|
|
10
|
+
|
|
11
|
+
const DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/;
|
|
12
|
+
const SHA_PATTERN = /^[0-9a-f]{40}$/;
|
|
13
|
+
|
|
14
|
+
function required(value, label) {
|
|
15
|
+
const normalized = String(value || "").trim();
|
|
16
|
+
if (!normalized) {
|
|
17
|
+
throw new Error(`${label} is required`);
|
|
18
|
+
}
|
|
19
|
+
return normalized;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function parseArray(value, label) {
|
|
23
|
+
let parsed;
|
|
24
|
+
try {
|
|
25
|
+
parsed = JSON.parse(value);
|
|
26
|
+
} catch {
|
|
27
|
+
throw new Error(`${label} must be valid JSON`);
|
|
28
|
+
}
|
|
29
|
+
if (!Array.isArray(parsed) || parsed.length === 0) {
|
|
30
|
+
throw new Error(`${label} must be a non-empty JSON array`);
|
|
31
|
+
}
|
|
32
|
+
return parsed;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function resolveArtifactCoordinates({
|
|
36
|
+
artifacts,
|
|
37
|
+
platforms,
|
|
38
|
+
artifactName,
|
|
39
|
+
artifactNameTemplate,
|
|
40
|
+
sourceSha,
|
|
41
|
+
sourceRef = "",
|
|
42
|
+
repository,
|
|
43
|
+
runId,
|
|
44
|
+
runAttempt,
|
|
45
|
+
serverUrl = "https://github.com",
|
|
46
|
+
}) {
|
|
47
|
+
if (!Array.isArray(artifacts)) {
|
|
48
|
+
throw new Error("artifacts must be an array");
|
|
49
|
+
}
|
|
50
|
+
if (!Array.isArray(platforms) || platforms.length === 0) {
|
|
51
|
+
throw new Error("platforms must be a non-empty array");
|
|
52
|
+
}
|
|
53
|
+
if (!SHA_PATTERN.test(sourceSha)) {
|
|
54
|
+
throw new Error("source SHA must be an exact lowercase commit SHA");
|
|
55
|
+
}
|
|
56
|
+
if (!/^[^/\s]+\/[^/\s]+$/.test(repository)) {
|
|
57
|
+
throw new Error("repository must be an owner/name coordinate");
|
|
58
|
+
}
|
|
59
|
+
if (!/^[1-9][0-9]*$/.test(String(runId))) {
|
|
60
|
+
throw new Error("run id must be a positive integer");
|
|
61
|
+
}
|
|
62
|
+
if (!/^[1-9][0-9]*$/.test(String(runAttempt))) {
|
|
63
|
+
throw new Error("run attempt must be a positive integer");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const coordinates = platforms.map((platform) => {
|
|
67
|
+
const id = required(platform?.id, "platform id");
|
|
68
|
+
const name = required(platform?.name, `platform ${id} name`);
|
|
69
|
+
const contract = resolveArtifactContract({
|
|
70
|
+
artifactName,
|
|
71
|
+
artifactNameTemplate,
|
|
72
|
+
platformId: id,
|
|
73
|
+
platformName: name,
|
|
74
|
+
sha: sourceSha,
|
|
75
|
+
ref: sourceRef,
|
|
76
|
+
runId: String(runId),
|
|
77
|
+
runAttempt: String(runAttempt),
|
|
78
|
+
});
|
|
79
|
+
const matches = artifacts.filter(
|
|
80
|
+
(artifact) =>
|
|
81
|
+
artifact?.name === contract.artifactName && !artifact.expired,
|
|
82
|
+
);
|
|
83
|
+
if (matches.length !== 1) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`expected exactly one live artifact named ${contract.artifactName}, found ${matches.length}`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
const artifact = matches[0];
|
|
89
|
+
if (!/^[1-9][0-9]*$/.test(String(artifact.id || ""))) {
|
|
90
|
+
throw new Error(`artifact ${contract.artifactName} has no exact id`);
|
|
91
|
+
}
|
|
92
|
+
if (!DIGEST_PATTERN.test(String(artifact.digest || ""))) {
|
|
93
|
+
throw new Error(`artifact ${contract.artifactName} has no exact digest`);
|
|
94
|
+
}
|
|
95
|
+
if (
|
|
96
|
+
!artifact.expires_at ||
|
|
97
|
+
!Number.isFinite(Date.parse(artifact.expires_at))
|
|
98
|
+
) {
|
|
99
|
+
throw new Error(`artifact ${contract.artifactName} has no exact expiry`);
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
platformId: id,
|
|
103
|
+
id: String(artifact.id),
|
|
104
|
+
name: artifact.name,
|
|
105
|
+
digest: artifact.digest,
|
|
106
|
+
url: `${serverUrl}/${repository}/actions/runs/${runId}/artifacts/${artifact.id}`,
|
|
107
|
+
expiresAt: new Date(artifact.expires_at).toISOString(),
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
coordinates.sort((left, right) =>
|
|
112
|
+
left.platformId.localeCompare(right.platformId),
|
|
113
|
+
);
|
|
114
|
+
return {
|
|
115
|
+
schema: "buildchain.github-artifact-coordinate-set/v1",
|
|
116
|
+
repository,
|
|
117
|
+
runId: String(runId),
|
|
118
|
+
runAttempt: String(runAttempt),
|
|
119
|
+
sourceSha,
|
|
120
|
+
artifacts: coordinates,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function resolveArtifactCoordinatesCli(env = process.env) {
|
|
125
|
+
const artifactListPath = required(
|
|
126
|
+
env.BUILDCHAIN_ARTIFACT_LIST_PATH,
|
|
127
|
+
"BUILDCHAIN_ARTIFACT_LIST_PATH",
|
|
128
|
+
);
|
|
129
|
+
const outputPath = required(
|
|
130
|
+
env.BUILDCHAIN_ARTIFACT_COORDINATES_PATH,
|
|
131
|
+
"BUILDCHAIN_ARTIFACT_COORDINATES_PATH",
|
|
132
|
+
);
|
|
133
|
+
const artifacts = parseArray(
|
|
134
|
+
fs.readFileSync(artifactListPath, "utf8"),
|
|
135
|
+
"artifact list",
|
|
136
|
+
);
|
|
137
|
+
const platforms = parseArray(
|
|
138
|
+
env.BUILDCHAIN_PLATFORMS_JSON || "",
|
|
139
|
+
"platforms-json",
|
|
140
|
+
);
|
|
141
|
+
const result = resolveArtifactCoordinates({
|
|
142
|
+
artifacts,
|
|
143
|
+
platforms,
|
|
144
|
+
artifactName: env.BUILDCHAIN_ARTIFACT_NAME,
|
|
145
|
+
artifactNameTemplate: env.BUILDCHAIN_ARTIFACT_NAME_TEMPLATE,
|
|
146
|
+
sourceSha: env.BUILDCHAIN_SOURCE_SHA,
|
|
147
|
+
sourceRef: env.GITHUB_REF,
|
|
148
|
+
repository: env.GITHUB_REPOSITORY,
|
|
149
|
+
runId: env.GITHUB_RUN_ID,
|
|
150
|
+
runAttempt: env.GITHUB_RUN_ATTEMPT,
|
|
151
|
+
serverUrl: env.GITHUB_SERVER_URL,
|
|
152
|
+
});
|
|
153
|
+
const pretty = `${JSON.stringify(result, null, 2)}\n`;
|
|
154
|
+
const compact = JSON.stringify(result);
|
|
155
|
+
fs.writeFileSync(outputPath, pretty);
|
|
156
|
+
writeGitHubOutputs({
|
|
157
|
+
"artifact-coordinates-json": compact,
|
|
158
|
+
"artifact-coordinates-path": outputPath,
|
|
159
|
+
});
|
|
160
|
+
process.stdout.write(pretty);
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (
|
|
165
|
+
process.argv[1] &&
|
|
166
|
+
import.meta.url === pathToFileURL(process.argv[1]).href
|
|
167
|
+
) {
|
|
168
|
+
try {
|
|
169
|
+
resolveArtifactCoordinatesCli();
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.error(`resolve-artifact-coordinates: ${error.message}`);
|
|
172
|
+
process.exitCode = 1;
|
|
173
|
+
}
|
|
174
|
+
}
|