@kungfu-tech/buildchain 4.0.8 → 4.0.9-alpha.1

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.
Files changed (57) hide show
  1. package/AGENTS.md +12 -19
  2. package/CONTRIBUTING.md +6 -9
  3. package/README.md +11 -1
  4. package/architecture/agent-change-map.md +11 -4
  5. package/architecture/build-environments.json +71 -0
  6. package/architecture/build-orchestration.json +18 -0
  7. package/architecture/ci-lane-change-budget.json +51 -2
  8. package/architecture/internal-capabilities.json +17 -4
  9. package/architecture/maintainability-debt.json +37 -126
  10. package/architecture/maintainability-policy.json +19 -210
  11. package/architecture/release-topology.json +9 -7
  12. package/architecture/universal-workflow-bootstrap.json +5 -4
  13. package/architecture/universal-workflow-train-admission.json +2 -2
  14. package/architecture/workflow-taxonomy.json +13 -0
  15. package/bin/buildchain.mjs +1 -1
  16. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
  17. package/dist/site/buildchain-contract.json +41 -1131
  18. package/dist/site/buildchain-site.json +48 -153
  19. package/dist/site/capability-registry.json +2 -2
  20. package/dist/site/cli-registry.json +1 -1
  21. package/dist/site/controller-registry.json +30 -868
  22. package/dist/site/kfd-claims.json +148 -396
  23. package/dist/site/kfd-upstream-aggregate.json +1 -1
  24. package/dist/site/manual-registry.json +7 -7
  25. package/dist/site/node-api-registry.json +37 -37
  26. package/dist/site/page-registry.json +36 -141
  27. package/dist/site/public-surface-audit.json +93 -402
  28. package/dist/site/publication-authority-registry.json +22 -1
  29. package/dist/site/publication-registry.json +4 -4
  30. package/dist/site/site-manifest.json +11 -11
  31. package/dist/site/workflow-registry.json +165 -391
  32. package/docs/MAP.md +5 -4
  33. package/docs/cli-reference.md +1 -1
  34. package/docs/getting-started.md +8 -7
  35. package/docs/node-api-reference.md +85 -85
  36. package/docs/release-governance.md +19 -18
  37. package/docs/reusable-build-surface.md +160 -1430
  38. package/docs/runtime-train-validation.md +45 -172
  39. package/docs/workflow-catalog.md +1 -0
  40. package/package.json +1 -1
  41. package/packages/core/build-configuration.js +117 -0
  42. package/packages/core/buildchain-config.js +2 -0
  43. package/packages/core/buildchain-contract.js +14 -44
  44. package/packages/core/buildchain-publication-authority.js +1 -0
  45. package/packages/core/controller-evidence.js +2 -9
  46. package/scripts/buildchain-cli-help.mjs +1 -1
  47. package/scripts/check-floating-consumer-policy-contract.mjs +4 -7
  48. package/scripts/check-inventory.mjs +91 -77
  49. package/scripts/check-maintainability.mjs +23 -8
  50. package/scripts/check-universal-workflow-bootstrap.mjs +12 -2
  51. package/scripts/generate-channel-build-workflow.mjs +50 -410
  52. package/scripts/generate-site-bundle.mjs +2 -1
  53. package/scripts/generate-universal-workflow-facades.mjs +1 -0
  54. package/scripts/init-repo.mjs +25 -26
  55. package/scripts/resolve-build-configuration.mjs +105 -0
  56. package/scripts/universal-workflow-self-dogfood.mjs +8 -1
  57. package/scripts/verify-golden-path.mjs +3 -3
@@ -0,0 +1,105 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import { loadBuildchainConfig } from "../packages/core/buildchain-config.js";
6
+ import { containedBuildPath, discoverBuildConfiguration, normalizeBuildConfiguration } from "../packages/core/build-configuration.js";
7
+ import { writeGitHubOutputs } from "./github-output.mjs";
8
+
9
+ const runtimeRoot = path.resolve(import.meta.dirname, "..");
10
+ const digest = (value) => `sha256:${crypto.createHash("sha256").update(value).digest("hex")}`;
11
+ const rootOf = (value) => digest(JSON.stringify(value));
12
+
13
+ export function resolveBuildConfiguration({ root, locator = "", workflowRef, workflowSha, repository, sourceSha, sourceRef, callerWorkflowRef = "", eventName = "", baseRef = "", environmentRegistry = JSON.parse(fs.readFileSync(path.join(runtimeRoot, "architecture/build-environments.json"), "utf8")) }) {
14
+ for (const [label, value] of Object.entries({ workflowSha, sourceSha })) {
15
+ if (!/^[a-f0-9]{40}$/u.test(value || "")) throw new Error(`${label} must be an exact SHA`);
16
+ }
17
+ const match = String(workflowRef).match(/^([^/]+\/[^/]+)\/(\.github\/workflows\/[^@]+)@(?:refs\/(?:heads|tags)\/)?(v([1-9]\d*)(-alpha)?)$/u);
18
+ if (!match || match[1] !== repository) throw new Error("Ordinary builds require the exact called workflow identity on a floating channel");
19
+ const identity = {
20
+ repository, ref: match[3], full_ref: `refs/tags/${match[3]}`,
21
+ sha: workflowSha, channel: match[5] ? "alpha" : "stable", major: match[4],
22
+ visible_workflow: match[2],
23
+ };
24
+ const callerPath = callerWorkflowRef.split("@")[0].split("/.github/workflows/")[1];
25
+ if (callerPath) {
26
+ const caller = fs.readFileSync(containedBuildPath(root, `.github/workflows/${callerPath}`), "utf8");
27
+ const calls = [...caller.matchAll(/uses:\s+kungfu-systems\/buildchain\/(\.github\/workflows\/(?:build|\.build|public-build-candidate|\.build-engine)\.yml)@(v\d+(?:-alpha)?)\s*$/gmu)]
28
+ .filter((call) => call[2] === identity.ref);
29
+ const paths = [...new Set(calls.map((call) => call[1]))];
30
+ if (paths.length !== 1) throw new Error("Unable to derive one visible build workflow from the exact caller");
31
+ identity.visible_workflow = paths[0];
32
+ }
33
+ const project = discoverBuildConfiguration(root, locator);
34
+ const loaded = loadBuildchainConfig(path.resolve(root, project.cwd));
35
+ const build = normalizeBuildConfiguration(loaded.config.build);
36
+ if (environmentRegistry.schema !== "buildchain.build-environments/v1" || !Object.hasOwn(environmentRegistry.profiles, build.environment)) {
37
+ throw new Error(`Unknown governed build environment: ${build.environment}`);
38
+ }
39
+ const overrides = environmentRegistry.profiles[build.environment];
40
+ const environment = Object.fromEntries(Object.entries(environmentRegistry.defaults).map(([group, values]) => [group, { ...values, ...overrides[group] }]));
41
+ const projectPath = (relative) => {
42
+ containedBuildPath(path.resolve(root, project.cwd), relative);
43
+ const selected = path.posix.join(project.cwd, relative);
44
+ containedBuildPath(root, selected);
45
+ return selected;
46
+ };
47
+ const evidence = (relative) => relative ? JSON.stringify(JSON.parse(fs.readFileSync(containedBuildPath(root, projectPath(relative)), "utf8"))) : "";
48
+ const dependencyFiles = ["pnpm-lock.yaml", "package-lock.json", "Cargo.lock", "go.sum"].map(projectPath).filter((file) => fs.existsSync(path.join(root, file)));
49
+ const plan = {
50
+ schema: "buildchain.build-plan/v1", project,
51
+ configuration_root: digest(fs.readFileSync(loaded.filePath)),
52
+ identity,
53
+ source: {
54
+ sha: sourceSha, ref: sourceRef,
55
+ candidate_channel: /^(?:refs\/heads\/)?release\//u.test(baseRef || sourceRef) ? "release"
56
+ : /^(?:refs\/heads\/)?(?:alpha|dev)\//u.test(baseRef || sourceRef) ? "alpha"
57
+ : eventName === "workflow_dispatch" ? (identity.channel === "stable" ? "release" : "alpha") : "none",
58
+ },
59
+ environment, environment_root: rootOf(environment),
60
+ build,
61
+ lifecycle: Object.fromEntries(["install", "build", "verify"].map((stage) => [stage, { required: stage === "build" || Boolean(loaded.config.lifecycle?.[stage]), configured: Boolean(loaded.config.lifecycle?.[stage]) }])),
62
+ tools: { node: build.tools.node, setup_node: Boolean(build.tools.node), rust: build.tools.rust || "stable", setup_rust: Boolean(build.tools.rust), go: build.tools.go, setup_go: Boolean(build.tools.go) },
63
+ artifacts: {
64
+ name: build.artifacts.name,
65
+ paths: build.artifacts.paths.map(projectPath).join("\n"),
66
+ expected_json: JSON.stringify({
67
+ minFiles: build.artifacts.min_files, maxFiles: build.artifacts.max_files,
68
+ minTotalBytes: build.artifacts.min_total_bytes,
69
+ requiredPaths: build.artifacts.required_paths.map(projectPath),
70
+ }),
71
+ },
72
+ evidence: { gate_profile_json: evidence(build.evidence.gate_profile_path), candidate_family_json: evidence(build.evidence.candidate_family_path) },
73
+ cache: {
74
+ dependency_root: rootOf(dependencyFiles.map((file) => [file, digest(fs.readFileSync(path.join(root, file)))])),
75
+ toolchain_root: rootOf({ tools: build.tools, environment: environment.tools }),
76
+ policy_root: rootOf(environment.cache),
77
+ },
78
+ contract: { lock_path: identity.channel === "alpha" ? ".buildchain/alpha-contract-lock.json" : ".buildchain/contract-lock.json" },
79
+ };
80
+ for (const [stage, status] of Object.entries(plan.lifecycle)) {
81
+ if (status.required && !status.configured) throw new Error(`buildchain.toml must declare lifecycle.${stage}`);
82
+ }
83
+ return { plan, root: rootOf(plan) };
84
+ }
85
+
86
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
87
+ try {
88
+ const resolved = resolveBuildConfiguration({
89
+ root: process.env.BUILDCHAIN_CONSUMER_ROOT,
90
+ locator: process.env.BUILDCHAIN_CONFIG_PATH,
91
+ workflowRef: process.env.BUILDCHAIN_WORKFLOW_REF,
92
+ workflowSha: process.env.BUILDCHAIN_WORKFLOW_SHA,
93
+ repository: process.env.BUILDCHAIN_WORKFLOW_REPOSITORY,
94
+ sourceSha: process.env.GITHUB_SHA,
95
+ sourceRef: process.env.GITHUB_REF,
96
+ callerWorkflowRef: process.env.GITHUB_WORKFLOW_REF,
97
+ eventName: process.env.GITHUB_EVENT_NAME,
98
+ baseRef: process.env.GITHUB_BASE_REF,
99
+ });
100
+ writeGitHubOutputs({ "plan-json": JSON.stringify(resolved.plan), "plan-root": resolved.root });
101
+ } catch (error) {
102
+ console.error(`::error::${String(error.message).replaceAll("\n", "%0A")}`);
103
+ process.exitCode = 1;
104
+ }
105
+ }
@@ -70,7 +70,14 @@ export function createUniversalSelfDogfoodRequest({
70
70
  id: "bootstrap-conformance",
71
71
  payload: {
72
72
  schema: "kungfu-buildchain-v4-universal-bootstrap-conformance/v1",
73
- expectedGovernedWorkflowCount: 40,
73
+ expectedGovernedWorkflowCount: JSON.parse(
74
+ fs.readFileSync(
75
+ new URL(
76
+ "../architecture/universal-workflow-bootstrap.json",
77
+ import.meta.url,
78
+ ),
79
+ ),
80
+ ).bootstrapGovernedWorkflows.length,
74
81
  },
75
82
  }
76
83
  : {
@@ -129,14 +129,14 @@ export function verifyGoldenPath() {
129
129
  "Golden Path validation did not retain the required lifecycle stages",
130
130
  );
131
131
  assert(
132
- /uses:\s+kungfu-systems\/buildchain\/.github\/workflows\/.build.yml@v4/.test(
132
+ /uses:\s+kungfu-systems\/buildchain\/\.github\/workflows\/build\.yml@v4/.test(
133
133
  workflow,
134
134
  ),
135
135
  "Golden Path workflow is not a thin v4 reusable-workflow caller",
136
136
  );
137
137
  assert(
138
- /buildchain-ref:/.test(workflow),
139
- "Golden Path workflow lacks the bounded runtime override input",
138
+ !/\n\s+(?:inputs|with|steps):/.test(workflow),
139
+ "Golden Path ordinary caller must have zero inputs and delegate its steps",
140
140
  );
141
141
  assert(
142
142
  releaseDryRun && typeof releaseDryRun === "object",