@kungfu-tech/buildchain 2.12.1-alpha.1 → 2.12.1-alpha.11
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/bin/buildchain.mjs +18 -0
- package/dist/site/buildchain-contract.json +7 -7
- package/dist/site/buildchain-site.json +44 -24
- package/dist/site/capability-registry.json +2 -2
- package/dist/site/cli-registry.json +12 -0
- package/dist/site/kfd-claims.json +108 -12
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +6 -6
- package/dist/site/node-api-registry.json +7 -7
- package/dist/site/page-registry.json +34 -14
- package/dist/site/public-surface-audit.json +58 -9
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/site-manifest.json +10 -10
- package/dist/site/workflow-registry.json +30 -3
- package/docs/binary-distribution.md +20 -1
- package/docs/cli.md +17 -0
- package/docs/kfd-support.md +44 -1
- package/docs/lifecycle-protocol.md +16 -0
- package/docs/release-governance.md +7 -0
- package/docs/reusable-build-surface.md +69 -0
- package/docs/stable-candidate-patrol.md +16 -0
- package/package.json +2 -1
- package/packages/core/buildchain-kfd-claims.js +51 -2
- package/packages/core/buildchain-layout.js +46 -0
- package/packages/core/index.js +4 -0
- package/packages/core/kfd3-surface-register.js +59 -2
- package/scripts/build-standalone-binary.mjs +2 -1
- package/scripts/check-inventory.mjs +4 -1
- package/scripts/generate-site-bundle.mjs +4 -1
- package/scripts/init-repo.mjs +1 -1
- package/scripts/locked-source-checkout.mjs +52 -12
- package/scripts/npm-publish-dry-run.mjs +1 -1
- package/scripts/publication-artifact.mjs +1 -1
- package/scripts/publication-package.mjs +1 -1
- package/scripts/release-propagation.mjs +1 -1
- package/scripts/stable-candidate-qualification.mjs +239 -0
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
BUILDCHAIN_PUBLIC_SURFACE_AUDIT_CONTRACT,
|
|
7
7
|
collectPublicSurfaceReverseAudit,
|
|
8
8
|
} from "./public-surface-audit.js";
|
|
9
|
+
import { normalizeKfd3DistributionDeclaration } from "./kfd3-surface-register.js";
|
|
9
10
|
|
|
10
11
|
export const BUILDCHAIN_KFD_CLAIM_REGISTRY_CONTRACT = "kungfu-buildchain-kfd-claim-registry";
|
|
11
12
|
export const BUILDCHAIN_KFD_COLLABORATION_INTERFACE_CONTRACT = "kungfu-buildchain-kfd-collaboration-interface";
|
|
@@ -307,6 +308,23 @@ export function createBuildchainPublicClaimDefinitions() {
|
|
|
307
308
|
"dist/site/public-surface-audit.json",
|
|
308
309
|
],
|
|
309
310
|
},
|
|
311
|
+
{
|
|
312
|
+
id: "claim:buildchain-shifu-kfd-discovery",
|
|
313
|
+
claim: "Buildchain exposes a versioned repository-layout discovery contract and KFD-3 distribution declarations so Shifu can locate the registry and determine jurisdiction without copying Buildchain layout paths.",
|
|
314
|
+
sourcePaths: [
|
|
315
|
+
"packages/core/buildchain-layout.js",
|
|
316
|
+
"packages/core/buildchain-kfd-claims.js",
|
|
317
|
+
"packages/core/kfd3-surface-register.js",
|
|
318
|
+
"bin/buildchain.mjs",
|
|
319
|
+
"scripts/build-standalone-binary.mjs",
|
|
320
|
+
"docs/kfd-support.md",
|
|
321
|
+
],
|
|
322
|
+
artifactPaths: [
|
|
323
|
+
"dist/site/kfd-claims.json",
|
|
324
|
+
"dist/site/cli-registry.json",
|
|
325
|
+
"dist/site/node-api-registry.json",
|
|
326
|
+
],
|
|
327
|
+
},
|
|
310
328
|
{
|
|
311
329
|
id: "claim:buildchain-readme-badge-facts",
|
|
312
330
|
claim: "Buildchain README status badges are generated from repository-owned facts and verified release-passport evidence, not hand-maintained README prose.",
|
|
@@ -431,6 +449,37 @@ export function createBuildchainKfdSurfaceRegistry({ root = process.cwd() } = {}
|
|
|
431
449
|
];
|
|
432
450
|
const siteConsumptionContracts = SITE_CONTRACT_FILES.map((relPath) => surface(`site:${relPath}`, "site-consumption-contract", relPath));
|
|
433
451
|
const controlSurfaces = WORKFLOW_AND_ACTION_FILES.map((relPath) => surface(`control:${relPath}`, relPath.includes("actions/") ? "action" : "workflow", relPath));
|
|
452
|
+
const standaloneDistribution = surface(
|
|
453
|
+
"distribution:buildchain-standalone",
|
|
454
|
+
"binary-distribution",
|
|
455
|
+
"scripts/build-standalone-binary.mjs",
|
|
456
|
+
{
|
|
457
|
+
name: "Buildchain standalone binary distribution",
|
|
458
|
+
artifactPath: "dist/binary",
|
|
459
|
+
evidencePath: ".github/workflows/binary-distribution.yml",
|
|
460
|
+
distribution: normalizeKfd3DistributionDeclaration({
|
|
461
|
+
registrar: "shifu",
|
|
462
|
+
tasks: ["binary:build"],
|
|
463
|
+
artifacts: [
|
|
464
|
+
{
|
|
465
|
+
kind: "binary",
|
|
466
|
+
platform: "linux",
|
|
467
|
+
pathGlob: "dist/binary/buildchain-x86_64-unknown-linux-gnu.tar.gz",
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
kind: "binary",
|
|
471
|
+
platform: "macos",
|
|
472
|
+
pathGlob: "dist/binary/buildchain-aarch64-apple-darwin.tar.gz",
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
kind: "binary",
|
|
476
|
+
platform: "windows",
|
|
477
|
+
pathGlob: "dist/binary/buildchain-x86_64-pc-windows-msvc.zip",
|
|
478
|
+
},
|
|
479
|
+
],
|
|
480
|
+
}, { surfaceId: "distribution:buildchain-standalone" }),
|
|
481
|
+
},
|
|
482
|
+
);
|
|
434
483
|
const reverseEnumeratedSurfaces = uniqueById([
|
|
435
484
|
...reverseAudit.enumerated.cliCommands.map((entry) => surface(`cli:${entry.id}`, "cli-command", "bin/buildchain.mjs", {
|
|
436
485
|
name: entry.usage,
|
|
@@ -463,8 +512,8 @@ export function createBuildchainKfdSurfaceRegistry({ root = process.cwd() } = {}
|
|
|
463
512
|
siteConsumptionContracts,
|
|
464
513
|
reverseEnumeratedSurfaces,
|
|
465
514
|
},
|
|
466
|
-
additionalSurfaces: controlSurfaces,
|
|
467
|
-
publicSurfaceCount: docs.length + schemas.length + standardsMetadata.length + exports.length + siteConsumptionContracts.length + reverseEnumeratedSurfaces.length + controlSurfaces.length,
|
|
515
|
+
additionalSurfaces: [...controlSurfaces, standaloneDistribution],
|
|
516
|
+
publicSurfaceCount: docs.length + schemas.length + standardsMetadata.length + exports.length + siteConsumptionContracts.length + reverseEnumeratedSurfaces.length + controlSurfaces.length + 1,
|
|
468
517
|
};
|
|
469
518
|
}
|
|
470
519
|
|
|
@@ -2,6 +2,8 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
4
|
export const BUILDCHAIN_DIR = ".buildchain";
|
|
5
|
+
export const BUILDCHAIN_VERSION_PIN_PATH = ".buildchain-version";
|
|
6
|
+
export const BUILDCHAIN_LAYOUT_DISCOVERY_CONTRACT = "kungfu-buildchain-layout-discovery";
|
|
5
7
|
export const BUILDCHAIN_CONFIG_PATH = ".buildchain/buildchain.toml";
|
|
6
8
|
export const LEGACY_BUILDCHAIN_CONFIG_PATH = "buildchain.toml";
|
|
7
9
|
export const BUILDCHAIN_CONTRACT_LOCK_PATH = ".buildchain/contract-lock.json";
|
|
@@ -94,6 +96,50 @@ export function resolveReleasePassportPath(cwd = process.cwd()) {
|
|
|
94
96
|
]);
|
|
95
97
|
}
|
|
96
98
|
|
|
99
|
+
export function createBuildchainLayoutDiscovery({
|
|
100
|
+
cwd = process.cwd(),
|
|
101
|
+
buildchainVersion = "",
|
|
102
|
+
} = {}) {
|
|
103
|
+
const resolvedCwd = path.resolve(cwd);
|
|
104
|
+
const configPath = resolveBuildchainConfigPath(resolvedCwd);
|
|
105
|
+
const kfd3RegistryPath = resolveKfd3SurfaceRegistryPath(resolvedCwd);
|
|
106
|
+
return {
|
|
107
|
+
schemaVersion: 1,
|
|
108
|
+
contract: BUILDCHAIN_LAYOUT_DISCOVERY_CONTRACT,
|
|
109
|
+
buildchain: {
|
|
110
|
+
version: String(buildchainVersion || ""),
|
|
111
|
+
versionPinPath: BUILDCHAIN_VERSION_PIN_PATH,
|
|
112
|
+
},
|
|
113
|
+
repository: {
|
|
114
|
+
root: resolvedCwd,
|
|
115
|
+
managed: fs.existsSync(repoPath(resolvedCwd, configPath))
|
|
116
|
+
|| fs.existsSync(repoPath(resolvedCwd, BUILDCHAIN_VERSION_PIN_PATH))
|
|
117
|
+
|| fs.existsSync(repoPath(resolvedCwd, kfd3RegistryPath)),
|
|
118
|
+
configPath,
|
|
119
|
+
},
|
|
120
|
+
kfd: {
|
|
121
|
+
root: BUILDCHAIN_KFD_ROOT,
|
|
122
|
+
registries: {
|
|
123
|
+
"kfd-3": {
|
|
124
|
+
standard: "kfd-3",
|
|
125
|
+
schemaVersion: 1,
|
|
126
|
+
path: kfd3RegistryPath,
|
|
127
|
+
canonicalPath: BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATH,
|
|
128
|
+
exists: fs.existsSync(repoPath(resolvedCwd, kfd3RegistryPath)),
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
shifu: {
|
|
133
|
+
jurisdiction: {
|
|
134
|
+
source: "kfd-3-distribution-declaration",
|
|
135
|
+
registryStandard: "kfd-3",
|
|
136
|
+
field: "surfaces[].distribution.registrar",
|
|
137
|
+
value: "shifu",
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
97
143
|
export function discoverBuildchainRepoFiles(cwd = process.cwd()) {
|
|
98
144
|
const files = [
|
|
99
145
|
{
|
package/packages/core/index.js
CHANGED
|
@@ -292,6 +292,8 @@ export {
|
|
|
292
292
|
BUILDCHAIN_CONFIG_PATH,
|
|
293
293
|
BUILDCHAIN_CONTRACT_LOCK_PATH,
|
|
294
294
|
BUILDCHAIN_DIR,
|
|
295
|
+
BUILDCHAIN_LAYOUT_DISCOVERY_CONTRACT,
|
|
296
|
+
BUILDCHAIN_VERSION_PIN_PATH,
|
|
295
297
|
BUILDCHAIN_GENERATED_DIRS,
|
|
296
298
|
BUILDCHAIN_KFD_ROOT,
|
|
297
299
|
BUILDCHAIN_KFD1_CONTRACT_WORLD_WITNESS_PATH,
|
|
@@ -317,6 +319,7 @@ export {
|
|
|
317
319
|
LEGACY_BUILDCHAIN_KFD3_SURFACE_REGISTRY_PATHS,
|
|
318
320
|
LEGACY_BUILDCHAIN_RELEASE_PASSPORT_PATH,
|
|
319
321
|
discoverBuildchainRepoFiles,
|
|
322
|
+
createBuildchainLayoutDiscovery,
|
|
320
323
|
migrateBuildchainLayout,
|
|
321
324
|
planBuildchainLayoutMigration,
|
|
322
325
|
resolveBuildchainConfigPath,
|
|
@@ -359,6 +362,7 @@ export {
|
|
|
359
362
|
auditKfd3Surfaces,
|
|
360
363
|
createKfd3SurfaceWitness,
|
|
361
364
|
detectKfd3Surfaces,
|
|
365
|
+
normalizeKfd3DistributionDeclaration,
|
|
362
366
|
queryKfd3Capabilities,
|
|
363
367
|
readKfd3SurfaceRegistry,
|
|
364
368
|
registerKfd3Surfaces,
|
|
@@ -67,6 +67,63 @@ function normalizeKinds(kinds = []) {
|
|
|
67
67
|
return [...new Set(selected.map(normalizeKind))].sort();
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
export function normalizeKfd3DistributionDeclaration(distribution, { surfaceId = "surface" } = {}) {
|
|
71
|
+
if (!distribution || typeof distribution !== "object" || Array.isArray(distribution)) {
|
|
72
|
+
throw new Error(`KFD-3 surface ${surfaceId} distribution must be an object`);
|
|
73
|
+
}
|
|
74
|
+
const registrar = String(distribution.registrar || "").trim();
|
|
75
|
+
if (!registrar) {
|
|
76
|
+
throw new Error(`KFD-3 surface ${surfaceId} distribution.registrar is required`);
|
|
77
|
+
}
|
|
78
|
+
const tasks = Array.isArray(distribution.tasks)
|
|
79
|
+
? [...new Set(distribution.tasks.map((entry) => String(entry || "").trim()).filter(Boolean))]
|
|
80
|
+
: [];
|
|
81
|
+
if (tasks.length === 0) {
|
|
82
|
+
throw new Error(`KFD-3 surface ${surfaceId} distribution.tasks must contain at least one task`);
|
|
83
|
+
}
|
|
84
|
+
const sourceArtifacts = Array.isArray(distribution.artifacts) ? distribution.artifacts : [];
|
|
85
|
+
if (sourceArtifacts.length === 0) {
|
|
86
|
+
throw new Error(`KFD-3 surface ${surfaceId} distribution.artifacts must contain at least one artifact`);
|
|
87
|
+
}
|
|
88
|
+
const artifacts = sourceArtifacts.map((artifact, index) => {
|
|
89
|
+
if (!artifact || typeof artifact !== "object" || Array.isArray(artifact)) {
|
|
90
|
+
throw new Error(`KFD-3 surface ${surfaceId} distribution.artifacts[${index}] must be an object`);
|
|
91
|
+
}
|
|
92
|
+
const normalized = {
|
|
93
|
+
...artifact,
|
|
94
|
+
kind: String(artifact.kind || "").trim(),
|
|
95
|
+
platform: String(artifact.platform || "").trim(),
|
|
96
|
+
pathGlob: String(artifact.pathGlob || "").trim(),
|
|
97
|
+
};
|
|
98
|
+
for (const field of ["kind", "platform", "pathGlob"]) {
|
|
99
|
+
if (!normalized[field]) {
|
|
100
|
+
throw new Error(`KFD-3 surface ${surfaceId} distribution.artifacts[${index}].${field} is required`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (artifact.sha256 !== undefined) {
|
|
104
|
+
normalized.sha256 = String(artifact.sha256 || "").trim().toLowerCase();
|
|
105
|
+
if (!/^[a-f0-9]{64}$/.test(normalized.sha256)) {
|
|
106
|
+
throw new Error(`KFD-3 surface ${surfaceId} distribution.artifacts[${index}].sha256 must be 64 lowercase hex characters`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return normalized;
|
|
110
|
+
});
|
|
111
|
+
return {
|
|
112
|
+
...distribution,
|
|
113
|
+
registrar,
|
|
114
|
+
tasks,
|
|
115
|
+
artifacts,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function normalizeRegistrySurface(entry) {
|
|
120
|
+
if (!entry?.distribution) return entry;
|
|
121
|
+
return {
|
|
122
|
+
...entry,
|
|
123
|
+
distribution: normalizeKfd3DistributionDeclaration(entry.distribution, { surfaceId: entry.id || "surface" }),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
70
127
|
function stableId(value) {
|
|
71
128
|
return String(value || "")
|
|
72
129
|
.toLowerCase()
|
|
@@ -366,7 +423,7 @@ export function readKfd3SurfaceRegistry({ cwd = process.cwd(), registryPath = ""
|
|
|
366
423
|
contract: registry.contract || KFD3_SURFACE_REGISTRY_CONTRACT,
|
|
367
424
|
product: registry.product || {},
|
|
368
425
|
registryPath: registry.registryPath || effectiveRegistryPath,
|
|
369
|
-
surfaces: Array.isArray(registry.surfaces) ? registry.surfaces : [],
|
|
426
|
+
surfaces: Array.isArray(registry.surfaces) ? registry.surfaces.map(normalizeRegistrySurface) : [],
|
|
370
427
|
policy: registry.policy || {},
|
|
371
428
|
};
|
|
372
429
|
}
|
|
@@ -379,7 +436,7 @@ export function writeKfd3SurfaceRegistry({ cwd = process.cwd(), registryPath = "
|
|
|
379
436
|
product: registry.product || {},
|
|
380
437
|
registryPath: effectiveRegistryPath,
|
|
381
438
|
surfaces: uniqueSurfaces(registry.surfaces || []).map((entry) => ({
|
|
382
|
-
...entry,
|
|
439
|
+
...normalizeRegistrySurface(entry),
|
|
383
440
|
state: entry.state || "declared",
|
|
384
441
|
declaration: entry.declaration || {
|
|
385
442
|
owner: "product",
|
|
@@ -176,9 +176,10 @@ function bundleCli({ cwd, tempDir, version, logger }) {
|
|
|
176
176
|
sourcemap: false,
|
|
177
177
|
dts: false,
|
|
178
178
|
shims: true,
|
|
179
|
-
noExternal: ["smol-toml"],
|
|
179
|
+
noExternal: ["smol-toml", /^@kungfu-tech\\/kfd(?:\\/|$)/],
|
|
180
180
|
define: {
|
|
181
181
|
"process.env.BUILDCHAIN_EMBEDDED_PACKAGE_VERSION": ${JSON.stringify(JSON.stringify(version || packageVersion(cwd)))},
|
|
182
|
+
"process.env.BUILDCHAIN_EMBEDDED_ENTRYPOINT": ${JSON.stringify(JSON.stringify("1"))},
|
|
182
183
|
},
|
|
183
184
|
};
|
|
184
185
|
`);
|
|
@@ -683,6 +683,8 @@ for (const requiredSnippet of [
|
|
|
683
683
|
"checkout-cache-mode",
|
|
684
684
|
"BUILDCHAIN_CHECKOUT_CACHE_MIRROR_URL_TEMPLATE",
|
|
685
685
|
"sourceCheckout",
|
|
686
|
+
"Shifu Cache Profile Passthrough",
|
|
687
|
+
"opaque reference and digest",
|
|
686
688
|
]) {
|
|
687
689
|
if (!reusableBuildSurfaceDoc.includes(requiredSnippet)) {
|
|
688
690
|
throw new Error(`reusable build surface doc missing contract lock snippet: ${requiredSnippet}`);
|
|
@@ -732,7 +734,8 @@ for (const requiredSnippet of [
|
|
|
732
734
|
"../packages/core/logging.js",
|
|
733
735
|
"standalone.cli-bundle.create",
|
|
734
736
|
"BUILDCHAIN_EMBEDDED_PACKAGE_VERSION",
|
|
735
|
-
"
|
|
737
|
+
"BUILDCHAIN_EMBEDDED_ENTRYPOINT",
|
|
738
|
+
"noExternal: [\"smol-toml\",",
|
|
736
739
|
"--macho-segment-name",
|
|
737
740
|
"mainFormat: \"commonjs\"",
|
|
738
741
|
"standalone.sea-blob.create",
|
|
@@ -395,6 +395,7 @@ function cliCommandMeta(id) {
|
|
|
395
395
|
"inspect-artifact": { group: "release-passport-trust", purpose: "Inspect artifact evidence." },
|
|
396
396
|
"inspect-release": { group: "release-passport-trust", purpose: "Inspect release passport evidence." },
|
|
397
397
|
kfd: { group: "kfd-trust", purpose: "Inspect KFD standards, schemas, and versioned KFD command families." },
|
|
398
|
+
layout: { group: "kfd-trust", purpose: "Return the versioned repository-layout and KFD registry discovery contract for tools such as Shifu." },
|
|
398
399
|
"kfd-schema": { group: "kfd-trust", purpose: "Inspect KFD schema command families." },
|
|
399
400
|
"kfd-schema-list": { group: "kfd-trust", purpose: "List machine-readable schemas exposed by the KFD package standards metadata." },
|
|
400
401
|
"kfd-schema-show": { group: "kfd-trust", purpose: "Print a machine-readable KFD schema from the KFD package standards metadata." },
|
|
@@ -479,7 +480,7 @@ function nodeApiMeta(exportName) {
|
|
|
479
480
|
"./buildchain-contract": { group: "governance-versioning", summary: "Runtime contract world and compatibility digest APIs for floating-ref drift checks." },
|
|
480
481
|
"./surface-manifest": { group: "site-and-propagation", summary: "Surface manifest timestamp and reproducibility policy APIs." },
|
|
481
482
|
"./issue-reporting": { group: "observability-diagnostics", summary: "Buildchain-owned issue reporting API for workflow friction feedback." },
|
|
482
|
-
"./buildchain-layout": { group: "kfd-trust", summary: "
|
|
483
|
+
"./buildchain-layout": { group: "kfd-trust", summary: "Versioned Buildchain repository-layout discovery contract plus canonical .buildchain path resolution and migration APIs." },
|
|
483
484
|
"./kfd": { group: "kfd-trust", summary: "Unified KFD standards, schema discovery, KFD-1/KFD-2/KFD-3 grouped APIs, KFD-4 schema discovery, upstream KFD aggregate facts, and Buildchain KFD claim helpers." },
|
|
484
485
|
"./public-surface-audit": { group: "kfd-trust", summary: "Reverse audit APIs for CLI, workflow, action, site page, and documentation command surfaces." },
|
|
485
486
|
"./kfd-gate": { group: "kfd-trust", summary: "KFD-1/KFD-2/KFD-3 release gate evidence and validation APIs." },
|
|
@@ -832,6 +833,7 @@ function buildSiteBundle() {
|
|
|
832
833
|
["buildchain-patrol-monthly", "repository-patrol"],
|
|
833
834
|
["stable-candidate-patrol", "repository-patrol"],
|
|
834
835
|
["buildchain-stable-candidate-patrol", "repository-patrol"],
|
|
836
|
+
["buildchain-stable-candidate-qualification", "repository-patrol"],
|
|
835
837
|
["patrol-daily", "repository-patrol"],
|
|
836
838
|
["patrol-weekly", "repository-patrol"],
|
|
837
839
|
["patrol-monthly", "repository-patrol"],
|
|
@@ -840,6 +842,7 @@ function buildSiteBundle() {
|
|
|
840
842
|
["release-propagation", "preview"],
|
|
841
843
|
["candidate-lab", "repository-internal"],
|
|
842
844
|
["build-surface-fixture", "repository-internal"],
|
|
845
|
+
["buildchain-stable-candidate-qualification", "repository-internal"],
|
|
843
846
|
["self-hosted-runner-smoke", "compatibility-fixture"],
|
|
844
847
|
]);
|
|
845
848
|
return {
|
package/scripts/init-repo.mjs
CHANGED
|
@@ -477,7 +477,7 @@ function readArg(name, fallback = "") {
|
|
|
477
477
|
return process.argv[index + 1] || "";
|
|
478
478
|
}
|
|
479
479
|
|
|
480
|
-
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
480
|
+
if (!process.env.BUILDCHAIN_EMBEDDED_ENTRYPOINT && process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
481
481
|
try {
|
|
482
482
|
const result = initBuildchainRepo({
|
|
483
483
|
cwd: readArg("cwd", process.cwd()),
|
|
@@ -179,7 +179,13 @@ function hasCommit(targetPath, sha, timeoutMs) {
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
function checkoutFetchedCommit(targetPath, sha, timeoutMs) {
|
|
182
|
-
|
|
182
|
+
// The locked Git tree is also the byte-level source of release evidence.
|
|
183
|
+
// Override runner-global autocrlf only at checkout time so this also works
|
|
184
|
+
// when a container workspace uses an external Git metadata pointer.
|
|
185
|
+
git(["-c", "core.autocrlf=false", "-c", "core.eol=lf", "checkout", "--force", "--detach", sha], {
|
|
186
|
+
cwd: targetPath,
|
|
187
|
+
timeoutMs,
|
|
188
|
+
});
|
|
183
189
|
}
|
|
184
190
|
|
|
185
191
|
function retryableGitFetchError(error) {
|
|
@@ -194,6 +200,7 @@ export function fetchSourceCommit({
|
|
|
194
200
|
remoteUrl,
|
|
195
201
|
sha,
|
|
196
202
|
fetchRef,
|
|
203
|
+
sourceTreeSha = "",
|
|
197
204
|
timeoutMs,
|
|
198
205
|
env = {},
|
|
199
206
|
runGit = git,
|
|
@@ -216,10 +223,22 @@ export function fetchSourceCommit({
|
|
|
216
223
|
cwd: targetPath,
|
|
217
224
|
timeoutMs,
|
|
218
225
|
env,
|
|
219
|
-
stdio: "ignore",
|
|
220
226
|
});
|
|
221
227
|
if (containsCommit(targetPath, sha, timeoutMs)) {
|
|
222
|
-
return { selector: "ref" };
|
|
228
|
+
return { selector: "ref", checkoutSha: sha };
|
|
229
|
+
}
|
|
230
|
+
if (/^refs\/pull\/\d+\/merge$/.test(fetchRef) && sourceTreeSha) {
|
|
231
|
+
const fetchedSha = runGit(["rev-parse", "refs/buildchain/source-ref^{commit}"], {
|
|
232
|
+
cwd: targetPath,
|
|
233
|
+
timeoutMs,
|
|
234
|
+
});
|
|
235
|
+
const fetchedTree = runGit(["rev-parse", "refs/buildchain/source-ref^{tree}"], {
|
|
236
|
+
cwd: targetPath,
|
|
237
|
+
timeoutMs,
|
|
238
|
+
});
|
|
239
|
+
if (fetchedTree === sourceTreeSha) {
|
|
240
|
+
return { selector: "ref-tree", checkoutSha: fetchedSha };
|
|
241
|
+
}
|
|
223
242
|
}
|
|
224
243
|
} catch (error) {
|
|
225
244
|
// A retryable transport failure belongs to the bounded outer retry. Do
|
|
@@ -234,12 +253,11 @@ export function fetchSourceCommit({
|
|
|
234
253
|
cwd: targetPath,
|
|
235
254
|
timeoutMs,
|
|
236
255
|
env,
|
|
237
|
-
stdio: "ignore",
|
|
238
256
|
});
|
|
239
257
|
if (!containsCommit(targetPath, sha, timeoutMs)) {
|
|
240
258
|
throw new Error(`fetched ${fetchRef || sha}, but ${sha} is not available`);
|
|
241
259
|
}
|
|
242
|
-
return { selector: "sha" };
|
|
260
|
+
return { selector: "sha", checkoutSha: sha };
|
|
243
261
|
}
|
|
244
262
|
|
|
245
263
|
export function runBoundedFetch({ attempts = 1, fetch, onAttempt = () => {}, onRetry = () => {}, shouldRetry = () => true }) {
|
|
@@ -266,18 +284,30 @@ function githubRemoteUrl({ repository, serverUrl = "https://github.com" }) {
|
|
|
266
284
|
return `${base}/${repository}.git`;
|
|
267
285
|
}
|
|
268
286
|
|
|
269
|
-
function verifyCheckout({ targetPath, sourceSha, sourceTreeSha = "" }) {
|
|
287
|
+
function verifyCheckout({ targetPath, sourceSha, sourceTreeSha = "", fetchRef = "" }) {
|
|
270
288
|
const head = git(["rev-parse", "HEAD"], { cwd: targetPath });
|
|
271
289
|
const tree = git(["rev-parse", "HEAD^{tree}"], { cwd: targetPath });
|
|
272
290
|
const headOk = head === sourceSha;
|
|
273
291
|
const treeOk = !sourceTreeSha || tree === sourceTreeSha;
|
|
274
|
-
|
|
292
|
+
const pullMergeTreeEquivalent = !headOk
|
|
293
|
+
&& /^refs\/pull\/\d+\/merge$/.test(fetchRef)
|
|
294
|
+
&& Boolean(sourceTreeSha)
|
|
295
|
+
&& treeOk;
|
|
296
|
+
if (!headOk && !pullMergeTreeEquivalent) {
|
|
275
297
|
throw new Error(`locked source checkout head mismatch: expected ${sourceSha}, got ${head}`);
|
|
276
298
|
}
|
|
277
299
|
if (!treeOk) {
|
|
278
300
|
throw new Error(`locked source checkout tree mismatch: expected ${sourceTreeSha}, got ${tree}`);
|
|
279
301
|
}
|
|
280
|
-
return {
|
|
302
|
+
return {
|
|
303
|
+
head,
|
|
304
|
+
expectedHead: sourceSha,
|
|
305
|
+
tree,
|
|
306
|
+
headOk,
|
|
307
|
+
treeOk,
|
|
308
|
+
identityOk: headOk || pullMergeTreeEquivalent,
|
|
309
|
+
identityMode: pullMergeTreeEquivalent ? "tree-equivalent-pull-merge" : "commit",
|
|
310
|
+
};
|
|
281
311
|
}
|
|
282
312
|
|
|
283
313
|
function writeEvidence(filePath, evidence) {
|
|
@@ -359,6 +389,7 @@ export function lockedSourceCheckout({
|
|
|
359
389
|
durationMs: 0,
|
|
360
390
|
};
|
|
361
391
|
let checkoutError;
|
|
392
|
+
let checkoutSha = sha;
|
|
362
393
|
if (normalizedMode !== "off") {
|
|
363
394
|
try {
|
|
364
395
|
if (renderedReferenceRepository) {
|
|
@@ -374,15 +405,17 @@ export function lockedSourceCheckout({
|
|
|
374
405
|
checkoutFetchedCommit(targetPath, sha, timeoutMs);
|
|
375
406
|
} else if (renderedMirrorUrl) {
|
|
376
407
|
evidence.cache.transport = "mirror-url";
|
|
377
|
-
fetchSourceCommit({
|
|
408
|
+
const fetchResult = fetchSourceCommit({
|
|
378
409
|
targetPath,
|
|
379
410
|
remoteName: "buildchain-cache",
|
|
380
411
|
remoteUrl: renderedMirrorUrl,
|
|
381
412
|
sha,
|
|
382
413
|
fetchRef,
|
|
414
|
+
sourceTreeSha: treeSha,
|
|
383
415
|
timeoutMs,
|
|
384
416
|
});
|
|
385
|
-
|
|
417
|
+
checkoutSha = fetchResult.checkoutSha || sha;
|
|
418
|
+
checkoutFetchedCommit(targetPath, checkoutSha, timeoutMs);
|
|
386
419
|
} else {
|
|
387
420
|
throw new Error("checkout cache is enabled but no mirror URL or reference repository template was provided");
|
|
388
421
|
}
|
|
@@ -416,6 +449,7 @@ export function lockedSourceCheckout({
|
|
|
416
449
|
remoteUrl,
|
|
417
450
|
sha,
|
|
418
451
|
fetchRef,
|
|
452
|
+
sourceTreeSha: treeSha,
|
|
419
453
|
timeoutMs: githubTimeoutMs,
|
|
420
454
|
env: githubAuthEnv(githubToken),
|
|
421
455
|
}),
|
|
@@ -424,14 +458,20 @@ export function lockedSourceCheckout({
|
|
|
424
458
|
shouldRetry: retryableGitFetchError,
|
|
425
459
|
});
|
|
426
460
|
evidence.cache.githubFetchAttempts = fetchResult.attempts;
|
|
461
|
+
checkoutSha = fetchResult.value.checkoutSha || sha;
|
|
427
462
|
} catch (error) {
|
|
428
463
|
evidence.durationMs = Date.now() - startedAt;
|
|
429
464
|
writeEvidence(path.resolve(workspace, diagnosticsPath), evidence);
|
|
430
465
|
throw error;
|
|
431
466
|
}
|
|
432
|
-
checkoutFetchedCommit(targetPath,
|
|
467
|
+
checkoutFetchedCommit(targetPath, checkoutSha, timeoutMs);
|
|
433
468
|
}
|
|
434
|
-
evidence.verification = verifyCheckout({
|
|
469
|
+
evidence.verification = verifyCheckout({
|
|
470
|
+
targetPath,
|
|
471
|
+
sourceSha: sha,
|
|
472
|
+
sourceTreeSha: treeSha,
|
|
473
|
+
fetchRef,
|
|
474
|
+
});
|
|
435
475
|
evidence.durationMs = Date.now() - startedAt;
|
|
436
476
|
writeEvidence(path.resolve(workspace, diagnosticsPath), evidence);
|
|
437
477
|
return evidence;
|
|
@@ -155,7 +155,7 @@ function usage() {
|
|
|
155
155
|
`;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
158
|
+
if (!process.env.BUILDCHAIN_EMBEDDED_ENTRYPOINT && process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
159
159
|
try {
|
|
160
160
|
const argv = process.argv.slice(2);
|
|
161
161
|
if (hasFlag(argv, "help") || hasFlag(argv, "h")) {
|
|
@@ -57,7 +57,7 @@ export function runPublicationArtifactCli(args = process.argv.slice(2)) {
|
|
|
57
57
|
return result;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
60
|
+
if (!process.env.BUILDCHAIN_EMBEDDED_ENTRYPOINT && process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
61
61
|
try {
|
|
62
62
|
runPublicationArtifactCli();
|
|
63
63
|
} catch (error) {
|
|
@@ -28,7 +28,7 @@ export function runPublicationPackageCli(args = process.argv.slice(2)) {
|
|
|
28
28
|
return result;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
31
|
+
if (!process.env.BUILDCHAIN_EMBEDDED_ENTRYPOINT && process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
32
32
|
try {
|
|
33
33
|
runPublicationPackageCli();
|
|
34
34
|
} catch (error) {
|
|
@@ -93,6 +93,6 @@ export function runReleasePropagationCli(argv = process.argv.slice(2)) {
|
|
|
93
93
|
throw new Error(`unsupported release-propagation command: ${mode}`);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
96
|
+
if (!process.env.BUILDCHAIN_EMBEDDED_ENTRYPOINT && process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
97
97
|
runReleasePropagationCli();
|
|
98
98
|
}
|