@kungfu-tech/buildchain 3.0.3 → 3.0.4-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.
- package/AGENTS.md +13 -0
- package/dist/site/buildchain-contract.json +8 -8
- package/dist/site/buildchain-site.json +7 -7
- package/dist/site/capability-registry.json +1 -1
- package/dist/site/cli-registry.json +18 -0
- package/dist/site/kfd-claims.json +19 -7
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +1 -1
- package/dist/site/node-api-registry.json +2 -2
- package/dist/site/page-registry.json +2 -2
- package/dist/site/public-surface-audit.json +14 -4
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/site-manifest.json +5 -5
- package/docs/cli.md +22 -7
- package/package.json +1 -1
- package/packages/core/paper-agent-entry.js +361 -0
- package/packages/core/paper-repository.js +2 -0
- package/packages/core/paper-scaffold-content.js +163 -0
- package/packages/core/paper-work.js +35 -0
- package/packages/core/paper.js +151 -175
- package/scripts/aggregate-build-summary.mjs +67 -4
- package/scripts/auditable-demo-renditions.mjs +131 -0
- package/scripts/auditable-demo.mjs +88 -91
- package/scripts/buildchain-cli-help.mjs +1 -0
- package/scripts/paper-agent-cli.mjs +35 -0
- package/scripts/paper-work-fleet-cli.mjs +14 -4
- package/scripts/paper.mjs +15 -2
- package/scripts/site-capability-metadata.mjs +1 -1
package/packages/core/paper.js
CHANGED
|
@@ -31,8 +31,34 @@ import {
|
|
|
31
31
|
sha256Text,
|
|
32
32
|
stableJson,
|
|
33
33
|
} from "./paper-repository.js";
|
|
34
|
+
import {
|
|
35
|
+
PAPER_AGENT_ENTRY_CONTRACT,
|
|
36
|
+
collectPaperAgentEntry,
|
|
37
|
+
paperAgentEntryFiles,
|
|
38
|
+
resolvePaperBuildchainSha,
|
|
39
|
+
} from "./paper-agent-entry.js";
|
|
40
|
+
import {
|
|
41
|
+
managedPaperPackageJson,
|
|
42
|
+
scaffoldMainTex,
|
|
43
|
+
scaffoldMakefile,
|
|
44
|
+
scaffoldMap,
|
|
45
|
+
scaffoldPackageJson,
|
|
46
|
+
scaffoldReadme,
|
|
47
|
+
} from "./paper-scaffold-content.js";
|
|
34
48
|
|
|
35
49
|
export { PAPER_PATHS, resolvePaperRepository } from "./paper-repository.js";
|
|
50
|
+
export {
|
|
51
|
+
PAPER_AGENT_ENTRY_CONTRACT,
|
|
52
|
+
PAPER_AGENT_ENTRY_SCHEMA_VERSION,
|
|
53
|
+
PAPER_AGENT_ENTRY_SECTION_END,
|
|
54
|
+
PAPER_AGENT_ENTRY_SECTION_START,
|
|
55
|
+
collectPaperAgentEntry,
|
|
56
|
+
createPaperAgentEntry,
|
|
57
|
+
mergePaperAgentEntryInstructions,
|
|
58
|
+
paperAgentEntryFiles,
|
|
59
|
+
paperAgentEntryInstructions,
|
|
60
|
+
resolvePaperBuildchainSha,
|
|
61
|
+
} from "./paper-agent-entry.js";
|
|
36
62
|
export {
|
|
37
63
|
PAPER_WORK_START_PLAN_CONTRACT,
|
|
38
64
|
PAPER_WORK_SUBMIT_PLAN_CONTRACT,
|
|
@@ -79,9 +105,12 @@ export const PAPER_STATE_ORDER = Object.freeze([
|
|
|
79
105
|
|
|
80
106
|
const PAPER_SCAFFOLD_PATHS = Object.freeze([
|
|
81
107
|
PAPER_PATHS.config,
|
|
108
|
+
PAPER_PATHS.agentEntry,
|
|
109
|
+
PAPER_PATHS.agentInstructions,
|
|
82
110
|
PAPER_PATHS.contractLock,
|
|
83
111
|
PAPER_PATHS.versionPin,
|
|
84
112
|
PAPER_PATHS.buildWorkflow,
|
|
113
|
+
PAPER_PATHS.verifyWorkflow,
|
|
85
114
|
PAPER_PATHS.releaseWorkflow,
|
|
86
115
|
PAPER_PATHS.provisioningAuthority,
|
|
87
116
|
"Makefile",
|
|
@@ -149,8 +178,11 @@ function buildchainPackageIdentity(buildchainRoot, explicitVersion = "") {
|
|
|
149
178
|
};
|
|
150
179
|
}
|
|
151
180
|
|
|
152
|
-
function
|
|
153
|
-
|
|
181
|
+
export function resolvePaperRuntimeGitSha(
|
|
182
|
+
buildchainRoot,
|
|
183
|
+
buildchainVersion = "",
|
|
184
|
+
) {
|
|
185
|
+
const value = resolvePaperBuildchainSha(buildchainRoot);
|
|
154
186
|
if (GIT_SHA_PATTERN.test(value)) return value;
|
|
155
187
|
const identity = buildchainPackageIdentity(buildchainRoot, buildchainVersion);
|
|
156
188
|
if (!identity.version) return "";
|
|
@@ -227,18 +259,6 @@ function tomlString(value) {
|
|
|
227
259
|
return JSON.stringify(String(value || ""));
|
|
228
260
|
}
|
|
229
261
|
|
|
230
|
-
function texEscape(value) {
|
|
231
|
-
return String(value || "")
|
|
232
|
-
.replaceAll("\\", "\\textbackslash{}")
|
|
233
|
-
.replaceAll("&", "\\&")
|
|
234
|
-
.replaceAll("%", "\\%")
|
|
235
|
-
.replaceAll("$", "\\$")
|
|
236
|
-
.replaceAll("#", "\\#")
|
|
237
|
-
.replaceAll("_", "\\_")
|
|
238
|
-
.replaceAll("{", "\\{")
|
|
239
|
-
.replaceAll("}", "\\}");
|
|
240
|
-
}
|
|
241
|
-
|
|
242
262
|
function joinUrl(base, suffix = "") {
|
|
243
263
|
const normalizedBase = String(base || "")
|
|
244
264
|
.trim()
|
|
@@ -334,6 +354,31 @@ jobs:
|
|
|
334
354
|
`;
|
|
335
355
|
}
|
|
336
356
|
|
|
357
|
+
function scaffoldVerifyWorkflow(buildchainSha) {
|
|
358
|
+
return `name: Verify
|
|
359
|
+
|
|
360
|
+
on:
|
|
361
|
+
pull_request:
|
|
362
|
+
push:
|
|
363
|
+
branches:
|
|
364
|
+
- "dev/v*/v*"
|
|
365
|
+
- "alpha/v*/v*"
|
|
366
|
+
- "release/v*/v*"
|
|
367
|
+
workflow_dispatch:
|
|
368
|
+
|
|
369
|
+
permissions:
|
|
370
|
+
contents: read
|
|
371
|
+
|
|
372
|
+
jobs:
|
|
373
|
+
check:
|
|
374
|
+
uses: kungfu-systems/buildchain/.github/workflows/check.yml@${buildchainSha}
|
|
375
|
+
with:
|
|
376
|
+
buildchain-ref: ${buildchainSha}
|
|
377
|
+
require-version-state: true
|
|
378
|
+
upload-artifacts: true
|
|
379
|
+
`;
|
|
380
|
+
}
|
|
381
|
+
|
|
337
382
|
function scaffoldReleaseWorkflow(
|
|
338
383
|
buildchainSha,
|
|
339
384
|
{ artifactPaths = "_build/main.pdf", releasePassportProductName = "" } = {},
|
|
@@ -413,7 +458,10 @@ export function createPaperProvisioningAuthority({
|
|
|
413
458
|
buildchainSha,
|
|
414
459
|
contractLock,
|
|
415
460
|
buildWorkflow,
|
|
461
|
+
verifyWorkflow,
|
|
416
462
|
releaseWorkflow,
|
|
463
|
+
agentEntry,
|
|
464
|
+
agentInstructions,
|
|
417
465
|
environment = "",
|
|
418
466
|
}) {
|
|
419
467
|
const policy = paperProvisioningPolicy();
|
|
@@ -439,6 +487,12 @@ export function createPaperProvisioningAuthority({
|
|
|
439
487
|
reusablePath: ".github/workflows/publication-artifact.yml",
|
|
440
488
|
reusableRef: buildchainSha,
|
|
441
489
|
},
|
|
490
|
+
verify: {
|
|
491
|
+
path: PAPER_PATHS.verifyWorkflow,
|
|
492
|
+
sourceDigest: sha256Text(verifyWorkflow),
|
|
493
|
+
reusablePath: ".github/workflows/check.yml",
|
|
494
|
+
reusableRef: buildchainSha,
|
|
495
|
+
},
|
|
442
496
|
release: {
|
|
443
497
|
path: PAPER_PATHS.releaseWorkflow,
|
|
444
498
|
sourceDigest: sha256Text(releaseWorkflow),
|
|
@@ -446,6 +500,13 @@ export function createPaperProvisioningAuthority({
|
|
|
446
500
|
reusableRef: buildchainSha,
|
|
447
501
|
},
|
|
448
502
|
},
|
|
503
|
+
agentEntry: {
|
|
504
|
+
contract: PAPER_AGENT_ENTRY_CONTRACT,
|
|
505
|
+
policyPath: PAPER_PATHS.agentEntry,
|
|
506
|
+
policyDigest: sha256Text(agentEntry),
|
|
507
|
+
instructionsPath: PAPER_PATHS.agentInstructions,
|
|
508
|
+
instructionsDigest: sha256Text(agentInstructions),
|
|
509
|
+
},
|
|
449
510
|
admission: {
|
|
450
511
|
contractLockPath: PAPER_PATHS.contractLock,
|
|
451
512
|
contractLockDigest: sha256Text(contractLock),
|
|
@@ -469,150 +530,6 @@ export function createPaperProvisioningAuthority({
|
|
|
469
530
|
};
|
|
470
531
|
}
|
|
471
532
|
|
|
472
|
-
function scaffoldMakefile() {
|
|
473
|
-
const image = `${DEFAULT_TOOLCHAIN_IMAGE}@${DEFAULT_TOOLCHAIN_DIGEST}`;
|
|
474
|
-
return `.PHONY: check pdf clean
|
|
475
|
-
|
|
476
|
-
BUILDER_IMAGE := ${image}
|
|
477
|
-
SOURCE_DATE_EPOCH ?= 0
|
|
478
|
-
|
|
479
|
-
check:
|
|
480
|
-
\t@test -f paper/main.tex
|
|
481
|
-
\t@test -f paper/references.bib
|
|
482
|
-
\t@git diff --check
|
|
483
|
-
|
|
484
|
-
pdf:
|
|
485
|
-
\t@mkdir -p _build
|
|
486
|
-
\tdocker run --rm --network=none \\
|
|
487
|
-
\t\t-e SOURCE_DATE_EPOCH="$(SOURCE_DATE_EPOCH)" \\
|
|
488
|
-
\t\t-e TZ=UTC -e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 -e HOME=/tmp \\
|
|
489
|
-
\t\t-v "$(CURDIR):/workspace" -w /workspace \\
|
|
490
|
-
\t\t"$(BUILDER_IMAGE)" bash -lc '${DEFAULT_TOOLCHAIN_COMMAND}'
|
|
491
|
-
|
|
492
|
-
clean:
|
|
493
|
-
\trm -rf _build
|
|
494
|
-
`;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
function paperPackageScripts(current = {}) {
|
|
498
|
-
return {
|
|
499
|
-
...current,
|
|
500
|
-
"buildchain:paper": "buildchain paper",
|
|
501
|
-
"paper:preflight": "buildchain paper preflight --json",
|
|
502
|
-
"paper:work:start": "buildchain paper work start",
|
|
503
|
-
"paper:work:submit": "buildchain paper work submit",
|
|
504
|
-
"paper:status": "buildchain paper status --json",
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
function managedPaperPackageJson(current, buildchainVersion) {
|
|
509
|
-
if (!/^3\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(buildchainVersion)) {
|
|
510
|
-
throw new Error(
|
|
511
|
-
"paper repositories require an exact Buildchain v3 version",
|
|
512
|
-
);
|
|
513
|
-
}
|
|
514
|
-
const packageManager = current.packageManager || "pnpm@11.7.0";
|
|
515
|
-
if (!packageManager.startsWith("pnpm@")) {
|
|
516
|
-
throw new Error("paper repositories require a pnpm packageManager");
|
|
517
|
-
}
|
|
518
|
-
return {
|
|
519
|
-
...current,
|
|
520
|
-
private: true,
|
|
521
|
-
scripts: paperPackageScripts(current.scripts),
|
|
522
|
-
devDependencies: {
|
|
523
|
-
...(current.devDependencies || {}),
|
|
524
|
-
"@kungfu-tech/buildchain": buildchainVersion,
|
|
525
|
-
},
|
|
526
|
-
packageManager,
|
|
527
|
-
};
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
function scaffoldPackageJson({
|
|
531
|
-
name,
|
|
532
|
-
packageName,
|
|
533
|
-
repository,
|
|
534
|
-
buildchainVersion,
|
|
535
|
-
}) {
|
|
536
|
-
return jsonText({
|
|
537
|
-
...managedPaperPackageJson(
|
|
538
|
-
{
|
|
539
|
-
name: packageName,
|
|
540
|
-
description: `${name} publication source repository.`,
|
|
541
|
-
repository: {
|
|
542
|
-
type: "git",
|
|
543
|
-
url: `git+https://github.com/${repository}.git`,
|
|
544
|
-
},
|
|
545
|
-
license: "Apache-2.0",
|
|
546
|
-
},
|
|
547
|
-
buildchainVersion,
|
|
548
|
-
),
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
function scaffoldReadme({ title, packageName }) {
|
|
553
|
-
return `# ${title}
|
|
554
|
-
|
|
555
|
-
This repository is a Buildchain-governed publication artifact source.
|
|
556
|
-
|
|
557
|
-
## Local workflow
|
|
558
|
-
|
|
559
|
-
\`\`\`sh
|
|
560
|
-
pnpm paper:preflight
|
|
561
|
-
pnpm paper:work:start -- <topic>
|
|
562
|
-
pnpm paper:work:submit
|
|
563
|
-
make pdf
|
|
564
|
-
\`\`\`
|
|
565
|
-
|
|
566
|
-
The public package identity is \`${packageName}\`. Buildchain owns reproducible
|
|
567
|
-
artifact generation, sealed publication, npm Trusted Publishing, and recovery;
|
|
568
|
-
this repository owns the paper source and review history.
|
|
569
|
-
|
|
570
|
-
See [docs/MAP.md](docs/MAP.md) for the repository map.
|
|
571
|
-
`;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
function scaffoldMap() {
|
|
575
|
-
return `# Repository Map
|
|
576
|
-
|
|
577
|
-
- \`paper/main.tex\`: paper source entrypoint.
|
|
578
|
-
- \`paper/references.bib\`: bibliography source.
|
|
579
|
-
- \`.buildchain/buildchain.toml\`: publication identity, toolchain, package, and lifecycle contract.
|
|
580
|
-
- \`.buildchain/contract-lock.json\`: accepted Buildchain runtime contract.
|
|
581
|
-
- \`.github/workflows/build.yml\`: thin read-only build and reproducibility caller.
|
|
582
|
-
- \`.github/workflows/paper-release.yml\`: thin protected sealed-release caller.
|
|
583
|
-
|
|
584
|
-
The repository does not own npm transaction logic, publication authority,
|
|
585
|
-
release-state recovery, or site deployment mechanics. Those remain Buildchain,
|
|
586
|
-
npm/GitHub, and downstream site responsibilities respectively.
|
|
587
|
-
`;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
function scaffoldMainTex(title) {
|
|
591
|
-
return `\\documentclass[11pt]{article}
|
|
592
|
-
\\usepackage[T1]{fontenc}
|
|
593
|
-
\\usepackage{lmodern}
|
|
594
|
-
\\usepackage{hyperref}
|
|
595
|
-
|
|
596
|
-
\\title{${texEscape(title)}}
|
|
597
|
-
\\author{}
|
|
598
|
-
\\date{}
|
|
599
|
-
|
|
600
|
-
\\begin{document}
|
|
601
|
-
\\maketitle
|
|
602
|
-
|
|
603
|
-
\\begin{abstract}
|
|
604
|
-
Replace this paragraph with the paper abstract.
|
|
605
|
-
\\end{abstract}
|
|
606
|
-
|
|
607
|
-
\\section{Introduction}
|
|
608
|
-
Replace this section with the reviewed paper content.
|
|
609
|
-
|
|
610
|
-
\\bibliographystyle{plain}
|
|
611
|
-
\\bibliography{paper/references}
|
|
612
|
-
\\end{document}
|
|
613
|
-
`;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
533
|
function scaffoldFiles({
|
|
617
534
|
buildchainRoot,
|
|
618
535
|
buildchainVersion,
|
|
@@ -647,6 +564,15 @@ function scaffoldFiles({
|
|
|
647
564
|
artifactPaths: "_build/main.pdf",
|
|
648
565
|
releasePassportProductName: title,
|
|
649
566
|
});
|
|
567
|
+
const verifyWorkflow = scaffoldVerifyWorkflow(buildchainSha);
|
|
568
|
+
const agentEntry = paperAgentEntryFiles({
|
|
569
|
+
cwd,
|
|
570
|
+
buildchainVersion,
|
|
571
|
+
buildchainSha,
|
|
572
|
+
developmentRef: `dev/v${parsePaperVersion(version).major}/v${
|
|
573
|
+
parsePaperVersion(version).major
|
|
574
|
+
}.${parsePaperVersion(version).minor}`,
|
|
575
|
+
});
|
|
650
576
|
const provisioningAuthority = createPaperProvisioningAuthority({
|
|
651
577
|
repository,
|
|
652
578
|
packageName,
|
|
@@ -654,7 +580,10 @@ function scaffoldFiles({
|
|
|
654
580
|
buildchainSha,
|
|
655
581
|
contractLock: contractLockText,
|
|
656
582
|
buildWorkflow,
|
|
583
|
+
verifyWorkflow,
|
|
657
584
|
releaseWorkflow,
|
|
585
|
+
agentEntry: agentEntry.get(PAPER_PATHS.agentEntry),
|
|
586
|
+
agentInstructions: agentEntry.get(PAPER_PATHS.agentInstructions),
|
|
658
587
|
});
|
|
659
588
|
const licenseText = runtimeLicenseText(buildchainRoot);
|
|
660
589
|
return new Map([
|
|
@@ -671,9 +600,18 @@ function scaffoldFiles({
|
|
|
671
600
|
[PAPER_PATHS.contractLock, contractLockText],
|
|
672
601
|
[PAPER_PATHS.versionPin, `${buildchainVersion}\n`],
|
|
673
602
|
[PAPER_PATHS.buildWorkflow, buildWorkflow],
|
|
603
|
+
[PAPER_PATHS.verifyWorkflow, verifyWorkflow],
|
|
674
604
|
[PAPER_PATHS.releaseWorkflow, releaseWorkflow],
|
|
675
605
|
[PAPER_PATHS.provisioningAuthority, jsonText(provisioningAuthority)],
|
|
676
|
-
|
|
606
|
+
...agentEntry,
|
|
607
|
+
[
|
|
608
|
+
"Makefile",
|
|
609
|
+
scaffoldMakefile({
|
|
610
|
+
image: DEFAULT_TOOLCHAIN_IMAGE,
|
|
611
|
+
digest: DEFAULT_TOOLCHAIN_DIGEST,
|
|
612
|
+
command: DEFAULT_TOOLCHAIN_COMMAND,
|
|
613
|
+
}),
|
|
614
|
+
],
|
|
677
615
|
[
|
|
678
616
|
"package.json",
|
|
679
617
|
scaffoldPackageJson({
|
|
@@ -727,7 +665,8 @@ export function planPaperScaffold({
|
|
|
727
665
|
buildchainVersion,
|
|
728
666
|
);
|
|
729
667
|
const runtimeSha =
|
|
730
|
-
buildchainSha ||
|
|
668
|
+
buildchainSha ||
|
|
669
|
+
resolvePaperRuntimeGitSha(buildchainRoot, runtimeIdentity.version);
|
|
731
670
|
if (!GIT_SHA_PATTERN.test(runtimeSha)) {
|
|
732
671
|
throw new Error(
|
|
733
672
|
"paper scaffold cannot resolve the exact Buildchain runtime SHA; pass buildchainSha or use a published Buildchain package with npm gitHead provenance",
|
|
@@ -920,7 +859,8 @@ function migrationFiles({
|
|
|
920
859
|
"paper publish package",
|
|
921
860
|
);
|
|
922
861
|
const runtimeSha =
|
|
923
|
-
buildchainSha ||
|
|
862
|
+
buildchainSha ||
|
|
863
|
+
resolvePaperRuntimeGitSha(buildchainRoot, buildchainVersion);
|
|
924
864
|
if (!GIT_SHA_PATTERN.test(runtimeSha)) {
|
|
925
865
|
throw new Error("paper migration requires an exact Buildchain source SHA");
|
|
926
866
|
}
|
|
@@ -957,6 +897,12 @@ function migrationFiles({
|
|
|
957
897
|
artifactPaths: config.publication.artifactPaths.join(","),
|
|
958
898
|
releasePassportProductName: config.publication.title,
|
|
959
899
|
});
|
|
900
|
+
const verifyWorkflow = scaffoldVerifyWorkflow(runtimeSha);
|
|
901
|
+
const agentEntry = paperAgentEntryFiles({
|
|
902
|
+
cwd,
|
|
903
|
+
buildchainVersion: runtimeIdentity.version,
|
|
904
|
+
buildchainSha: runtimeSha,
|
|
905
|
+
});
|
|
960
906
|
const provisioningAuthority = createPaperProvisioningAuthority({
|
|
961
907
|
repository,
|
|
962
908
|
packageName,
|
|
@@ -964,7 +910,10 @@ function migrationFiles({
|
|
|
964
910
|
buildchainSha: runtimeSha,
|
|
965
911
|
contractLock: contractLockText,
|
|
966
912
|
buildWorkflow,
|
|
913
|
+
verifyWorkflow,
|
|
967
914
|
releaseWorkflow,
|
|
915
|
+
agentEntry: agentEntry.get(PAPER_PATHS.agentEntry),
|
|
916
|
+
agentInstructions: agentEntry.get(PAPER_PATHS.agentInstructions),
|
|
968
917
|
});
|
|
969
918
|
const currentPackage = readJson(path.resolve(cwd, "package.json"));
|
|
970
919
|
if (!currentPackage.exists || currentPackage.error || !currentPackage.value) {
|
|
@@ -978,21 +927,12 @@ function migrationFiles({
|
|
|
978
927
|
[PAPER_PATHS.contractLock, contractLockText],
|
|
979
928
|
[PAPER_PATHS.versionPin, `${runtimeIdentity.version}\n`],
|
|
980
929
|
[PAPER_PATHS.buildWorkflow, buildWorkflow],
|
|
930
|
+
[PAPER_PATHS.verifyWorkflow, verifyWorkflow],
|
|
981
931
|
[PAPER_PATHS.releaseWorkflow, releaseWorkflow],
|
|
982
932
|
[PAPER_PATHS.provisioningAuthority, jsonText(provisioningAuthority)],
|
|
933
|
+
...agentEntry,
|
|
983
934
|
["package.json", jsonText(packageJson)],
|
|
984
935
|
]);
|
|
985
|
-
const verifyWorkflowPath = path.resolve(cwd, PAPER_PATHS.verifyWorkflow);
|
|
986
|
-
if (fs.existsSync(verifyWorkflowPath)) {
|
|
987
|
-
const currentVerifyWorkflow = fs.readFileSync(verifyWorkflowPath, "utf8");
|
|
988
|
-
const migratedVerifyWorkflow = currentVerifyWorkflow.replace(
|
|
989
|
-
/(uses:\s*kungfu-systems\/buildchain\/\.github\/workflows\/check\.yml@)[^\s]+/g,
|
|
990
|
-
`$1${runtimeSha}`,
|
|
991
|
-
);
|
|
992
|
-
if (migratedVerifyWorkflow !== currentVerifyWorkflow) {
|
|
993
|
-
files.set(PAPER_PATHS.verifyWorkflow, migratedVerifyWorkflow);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
936
|
return files;
|
|
997
937
|
}
|
|
998
938
|
|
|
@@ -1687,7 +1627,27 @@ function validatePaperProvisioningAuthority(cwd) {
|
|
|
1687
1627
|
"paper release policy permits avoidable bookkeeping pull requests",
|
|
1688
1628
|
);
|
|
1689
1629
|
}
|
|
1690
|
-
|
|
1630
|
+
if (value.agentEntry?.contract !== PAPER_AGENT_ENTRY_CONTRACT) {
|
|
1631
|
+
errors.push("paper agent-entry authority contract mismatch");
|
|
1632
|
+
}
|
|
1633
|
+
for (const [entryPath, expectedDigest] of [
|
|
1634
|
+
[value.agentEntry?.policyPath, value.agentEntry?.policyDigest],
|
|
1635
|
+
[value.agentEntry?.instructionsPath, value.agentEntry?.instructionsDigest],
|
|
1636
|
+
]) {
|
|
1637
|
+
if (!entryPath || !SHA256_PATTERN.test(String(expectedDigest || ""))) {
|
|
1638
|
+
errors.push("paper agent-entry authority is incomplete");
|
|
1639
|
+
continue;
|
|
1640
|
+
}
|
|
1641
|
+
const absolute = path.resolve(cwd, entryPath);
|
|
1642
|
+
if (!fs.existsSync(absolute) || sha256File(absolute) !== expectedDigest) {
|
|
1643
|
+
errors.push(`paper agent-entry source digest mismatch: ${entryPath}`);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
for (const workflow of [
|
|
1647
|
+
value.workflows?.build,
|
|
1648
|
+
value.workflows?.verify,
|
|
1649
|
+
value.workflows?.release,
|
|
1650
|
+
]) {
|
|
1691
1651
|
if (!workflow?.path || !workflow?.sourceDigest) {
|
|
1692
1652
|
errors.push("paper workflow authority is incomplete");
|
|
1693
1653
|
continue;
|
|
@@ -1707,7 +1667,10 @@ function validatePaperProvisioningAuthority(cwd) {
|
|
|
1707
1667
|
`paper workflow reusable source is not exact: ${workflow.path}`,
|
|
1708
1668
|
);
|
|
1709
1669
|
}
|
|
1710
|
-
if (
|
|
1670
|
+
if (
|
|
1671
|
+
workflow.reusablePath !== ".github/workflows/check.yml" &&
|
|
1672
|
+
!text.includes(`buildchain-ref: ${value.runtime.resolvedSha}`)
|
|
1673
|
+
) {
|
|
1711
1674
|
errors.push(
|
|
1712
1675
|
`paper workflow runtime input is not exact: ${workflow.path}`,
|
|
1713
1676
|
);
|
|
@@ -1777,7 +1740,8 @@ function runtimeFacts({
|
|
|
1777
1740
|
version: identity.version,
|
|
1778
1741
|
ref: buildchainRef,
|
|
1779
1742
|
resolvedSha:
|
|
1780
|
-
buildchainSha ||
|
|
1743
|
+
buildchainSha ||
|
|
1744
|
+
resolvePaperRuntimeGitSha(buildchainRoot, identity.version),
|
|
1781
1745
|
contract: contractWorld.contract,
|
|
1782
1746
|
contractDigest: contractWorld.contractDigest,
|
|
1783
1747
|
compatibilityDigest: contractWorld.compatibilityDigest,
|
|
@@ -2094,6 +2058,7 @@ export function collectPaperPreflight({
|
|
|
2094
2058
|
buildchainSha = "",
|
|
2095
2059
|
registry = NPM_REGISTRY,
|
|
2096
2060
|
offline = false,
|
|
2061
|
+
agentEntryMode = "contract",
|
|
2097
2062
|
} = {}) {
|
|
2098
2063
|
const resolvedCwd = path.resolve(cwd);
|
|
2099
2064
|
const status = collectPaperStatus({ cwd: resolvedCwd });
|
|
@@ -2114,6 +2079,11 @@ export function collectPaperPreflight({
|
|
|
2114
2079
|
buildchainRef: provisioning.value?.runtime?.ref || buildchainRef,
|
|
2115
2080
|
buildchainSha,
|
|
2116
2081
|
});
|
|
2082
|
+
const agentEntry = collectPaperAgentEntry({
|
|
2083
|
+
cwd: resolvedCwd,
|
|
2084
|
+
buildchainSha: runtime.resolvedSha,
|
|
2085
|
+
mode: agentEntryMode,
|
|
2086
|
+
});
|
|
2117
2087
|
const lockPath = path.resolve(resolvedCwd, PAPER_PATHS.contractLock);
|
|
2118
2088
|
let lockEvaluation = {
|
|
2119
2089
|
status: "missing-lock",
|
|
@@ -2220,6 +2190,11 @@ export function collectPaperPreflight({
|
|
|
2220
2190
|
configResult.loaded?.config?.publication,
|
|
2221
2191
|
);
|
|
2222
2192
|
const checks = [
|
|
2193
|
+
...agentEntry.checks.map((entry) => ({
|
|
2194
|
+
...entry,
|
|
2195
|
+
blocking: true,
|
|
2196
|
+
scope: "local",
|
|
2197
|
+
})),
|
|
2223
2198
|
{
|
|
2224
2199
|
id: "provisioning.authority",
|
|
2225
2200
|
status: provisioning.valid ? "pass" : "fail",
|
|
@@ -2486,6 +2461,7 @@ export function collectPaperPreflight({
|
|
|
2486
2461
|
policyDigest: provisioning.value?.policy?.policyDigest || "",
|
|
2487
2462
|
errors: provisioning.errors,
|
|
2488
2463
|
},
|
|
2464
|
+
agentEntry,
|
|
2489
2465
|
repositoryPermissions,
|
|
2490
2466
|
repositoryActions,
|
|
2491
2467
|
generatedWriteAuthority,
|
|
@@ -8,6 +8,51 @@ function readEnv(name, fallback = "") {
|
|
|
8
8
|
return process.env[name] || fallback;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
function parsePlatformIds(name) {
|
|
12
|
+
const raw = readEnv(name, "").trim();
|
|
13
|
+
if (!raw) return [];
|
|
14
|
+
const parsed = JSON.parse(raw);
|
|
15
|
+
if (!Array.isArray(parsed)) {
|
|
16
|
+
throw new Error(`${name} must be a JSON array`);
|
|
17
|
+
}
|
|
18
|
+
const ids = parsed.map((entry) => String(
|
|
19
|
+
typeof entry === "string" ? entry : entry?.id || "",
|
|
20
|
+
).trim());
|
|
21
|
+
if (ids.some((id) => !id)) {
|
|
22
|
+
throw new Error(`${name} entries must declare non-empty platform ids`);
|
|
23
|
+
}
|
|
24
|
+
if (new Set(ids).size !== ids.length) {
|
|
25
|
+
throw new Error(`${name} must not contain duplicate platform ids`);
|
|
26
|
+
}
|
|
27
|
+
return ids;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function readManifest(file) {
|
|
31
|
+
try {
|
|
32
|
+
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function selectPlatformManifests({ inputRoot, expectedPlatformIds }) {
|
|
39
|
+
const candidates = findJsonFiles(inputRoot)
|
|
40
|
+
.filter((file) => path.basename(file) === "manifest.json")
|
|
41
|
+
.sort()
|
|
42
|
+
.map((file) => ({ file, manifest: readManifest(file) }))
|
|
43
|
+
.filter(({ manifest }) => manifest?.contract === "kungfu-buildchain-artifact");
|
|
44
|
+
if (expectedPlatformIds.length === 0) return candidates;
|
|
45
|
+
return expectedPlatformIds.map((platformId) => {
|
|
46
|
+
const matches = candidates.filter(({ manifest }) => manifest.platform?.id === platformId);
|
|
47
|
+
if (matches.length !== 1) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`expected exactly one platform manifest for ${platformId}, found ${matches.length} under ${inputRoot}`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return matches[0];
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
11
56
|
export function aggregateBuildSummaryCli() {
|
|
12
57
|
const inputRoot = path.resolve(readEnv("BUILDCHAIN_SUMMARY_INPUT", ".buildchain/downloaded-manifests"));
|
|
13
58
|
const outputPath = path.resolve(readEnv("BUILDCHAIN_SUMMARY_OUTPUT", ".buildchain/artifacts/build-summary.json"));
|
|
@@ -18,10 +63,28 @@ export function aggregateBuildSummaryCli() {
|
|
|
18
63
|
throw new Error("BUILDCHAIN_ADDITIONAL_PLATFORM_COUNT must be a non-negative integer");
|
|
19
64
|
}
|
|
20
65
|
const expectedManifestCount = expectedPlatformCount + additionalPlatformCount;
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
66
|
+
const platformIds = parsePlatformIds("BUILDCHAIN_EXPECTED_PLATFORMS_JSON");
|
|
67
|
+
const additionalPlatformIds = parsePlatformIds("BUILDCHAIN_ADDITIONAL_PLATFORM_IDS_JSON");
|
|
68
|
+
if (platformIds.length > 0 && platformIds.length !== expectedPlatformCount) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`BUILDCHAIN_EXPECTED_PLATFORMS_JSON declares ${platformIds.length} platforms, expected ${expectedPlatformCount}`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
if (additionalPlatformIds.length !== additionalPlatformCount) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`BUILDCHAIN_ADDITIONAL_PLATFORM_IDS_JSON declares ${additionalPlatformIds.length} platforms, expected ${additionalPlatformCount}`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
const expectedPlatformIds = [...platformIds, ...additionalPlatformIds];
|
|
79
|
+
if (new Set(expectedPlatformIds).size !== expectedPlatformIds.length) {
|
|
80
|
+
throw new Error("declared platform ids must be unique across primary and additional platforms");
|
|
81
|
+
}
|
|
82
|
+
const selected = selectPlatformManifests({
|
|
83
|
+
inputRoot,
|
|
84
|
+
expectedPlatformIds,
|
|
85
|
+
});
|
|
86
|
+
const manifestFiles = selected.map(({ file }) => file);
|
|
87
|
+
const manifests = selected.map(({ manifest }) => manifest);
|
|
25
88
|
if (expectedManifestCount > 0 && manifests.length !== expectedManifestCount) {
|
|
26
89
|
throw new Error(
|
|
27
90
|
`expected ${expectedManifestCount} platform manifests, found ${manifests.length} under ${inputRoot}`,
|