@kungfu-tech/buildchain 4.0.2-alpha.9 → 4.0.3-alpha.0
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 +14 -5
- package/CONTRIBUTING.md +58 -0
- package/README.md +3 -3
- package/actions/promote-buildchain-ref/README.md +1 -1
- package/actions/release-candidate-promote/README.md +31 -0
- package/architecture/agent-change-map.md +190 -126
- package/architecture/{v4-architecture-constitution.md → architecture-constitution.md} +33 -30
- package/architecture/{v3-core-mechanism-inventory.md → baseline-core-mechanism-inventory.md} +1 -1
- package/architecture/{v4-bootstrap-authority.json → bootstrap-authority.json} +3 -3
- package/architecture/{v3-v4-capability-closure.md → capability-parity-closure.md} +3 -3
- package/architecture/{v3-v4-live-capability-inventory.json → capability-parity-live-capability-inventory.json} +4 -4
- package/architecture/{v4-capability-state-machine-manifest.json → capability-state-machine-manifest.json} +2 -2
- package/architecture/{v4-capability-state-machine-manifest.schema.json → capability-state-machine-manifest.schema.json} +2 -2
- package/architecture/ci-lane-change-budget.json +384 -0
- package/architecture/{v4-cross-platform-adopter-qualification.json → cross-platform-adopter-qualification.json} +4 -4
- package/architecture/{v4-delivery-authority-parity.json → delivery-authority-parity.json} +17 -17
- package/architecture/{v4-delivery-warrant-shadow-bootstrap-plan.json → delivery-warrant-shadow-bootstrap-plan.json} +4 -4
- package/architecture/{v4-delivery-warrant-shadow-bootstrap-plan.md → delivery-warrant-shadow-bootstrap-plan.md} +7 -7
- package/architecture/{v4-floating-consumer-policy.json → floating-consumer-policy.json} +2 -2
- package/architecture/{v4-floating-consumer-policy.md → floating-consumer-policy.md} +1 -1
- package/architecture/implementation-naming.json +1273 -0
- package/architecture/internal-capabilities.json +201 -154
- package/architecture/maintainability-debt.json +205 -146
- package/architecture/maintainability-policy.json +37 -33
- package/architecture/{v4-next-development-parity.json → next-development-parity.json} +12 -12
- package/architecture/{v4-partial-mutation-recovery-qualification.json → partial-mutation-recovery-qualification.json} +8 -5
- package/architecture/{v4-platform-stage-checkpoints.json → platform-stage-checkpoints.json} +3 -3
- package/architecture/{v4-provider-operation-journal-contract.json → provider-operation-journal-contract.json} +10 -7
- package/architecture/publication-facade-patches.json +64 -0
- package/architecture/{v4-publication-rehearsal-parity.json → publication-rehearsal-parity.json} +4 -4
- package/architecture/{v4-release-activation-shadow-domain.json → release-activation-shadow-domain.json} +9 -6
- package/architecture/release-tail-contract-inventory.json +6 -6
- package/architecture/{v4-release-topology.json → release-topology.json} +163 -72
- package/architecture/{v4-release-train-parity.json → release-train-parity.json} +2 -2
- package/architecture/{v4-runtime-ref-resume-authority.json → runtime-ref-resume-authority.json} +1 -1
- package/architecture/{v4-runtime-semantic-closure.json → runtime-semantic-closure.json} +2 -2
- package/architecture/{v4-rust-libnode-bridge-evaluation.json → rust-libnode-bridge-evaluation.json} +3 -3
- package/architecture/{v4-rust-libnode-bridge-spike.md → rust-libnode-bridge-spike.md} +6 -6
- package/architecture/rust-wasm-production-authority.json +58 -0
- package/architecture/{v4-stable-publication-fence.json → stable-publication-fence.json} +7 -4
- package/architecture/{v4-stage-capsule-contract.json → stage-capsule-contract.json} +1 -1
- package/architecture/{v4-stage-capsule-qualification.json → stage-capsule-qualification.json} +8 -8
- package/architecture/{v4-stage-capsule-resume-planner.json → stage-capsule-resume-planner.json} +2 -2
- package/architecture/{v4-stage-capsule-store-contract.json → stage-capsule-store-contract.json} +4 -4
- package/architecture/{v4-tail-reseal-parity.json → tail-reseal-parity.json} +35 -33
- package/architecture/universal-workflow-bootstrap.json +176 -0
- package/architecture/universal-workflow-fault-campaign.json +72 -0
- package/architecture/universal-workflow-train-admission.json +40 -0
- package/architecture/workflow-taxonomy.json +1462 -0
- package/bin/buildchain.mjs +10 -10
- package/bin/internal/adopter-delivery-cli.mjs +9 -9
- package/contracts/buildchain-v2-residuals-v1.json +57 -48
- package/contracts/dev-delivery-authority-v2.schema.json +16 -2
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
- package/contracts/v4-canonical-contracts-v1.schema.json +1 -0
- package/crates/{buildchain-v4-bridge → buildchain-host-bridge}/Cargo.lock +1 -1
- package/crates/{buildchain-v4-bridge → buildchain-host-bridge}/Cargo.toml +1 -1
- package/crates/{buildchain-v4-bridge → buildchain-host-bridge}/src/main.rs +3 -3
- package/dist/site/buildchain-contract.json +98 -53
- package/dist/site/buildchain-site.json +351 -102
- package/dist/site/capability-registry.json +7 -7
- package/dist/site/controller-registry.json +50 -13
- package/dist/site/kfd-claims.json +2773 -1052
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +14 -14
- package/dist/site/node-api-registry.json +13176 -10733
- package/dist/site/page-registry.json +332 -83
- package/dist/site/public-surface-audit.json +3227 -1222
- package/dist/site/publication-authority-registry.json +1135 -363
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-provenance.json +18 -9
- package/dist/site/schemas/dev-delivery-authority-v2.schema.json +16 -2
- package/dist/site/site-manifest.json +18 -18
- package/dist/site/workflow-registry.json +5367 -1931
- package/docs/MAP.md +5 -3
- package/docs/auditable-demo.md +1 -1
- package/docs/cli.md +21 -8
- package/docs/dev-delivery-warrant.md +1 -1
- package/docs/engineering-housekeeper.md +3 -3
- package/docs/kfd-support.md +26 -2
- package/docs/next-development-transition.md +26 -3
- package/docs/node-api-reference.md +618 -358
- package/docs/oci-publication.md +173 -0
- package/docs/publication-authority.md +2 -2
- package/docs/publish-transaction.md +36 -3
- package/docs/release-candidate.md +3 -3
- package/docs/release-flow.md +67 -19
- package/docs/release-governance.md +8 -8
- package/docs/release-passport.md +27 -2
- package/docs/reusable-build-surface.md +17 -1
- package/docs/v4-adopter-delivery.md +4 -4
- package/docs/v4-canonical-contracts.md +7 -7
- package/docs/v4-delivery-warrant-read-candidate.md +3 -3
- package/docs/v4-delivery-warrant-semantic-diff.md +3 -3
- package/docs/v4-production-release.md +77 -8
- package/docs/v4-publication-rehearsal.md +3 -3
- package/docs/v4-runtime-ref-resume-authority.md +2 -2
- package/docs/v4-rust-wasm-production-authority.md +58 -0
- package/docs/v4-stage-capsule.md +9 -9
- package/docs/v4-tail-reseal.md +2 -2
- package/docs/workflow-catalog.md +155 -0
- package/docs/workflow-path-migration.md +109 -0
- package/package.json +39 -24
- package/packages/compatibility/adopter-delivery.js +16 -0
- package/packages/compatibility/cross-platform-adopter-qualification.js +12 -0
- package/packages/compatibility/floating-consumer-policy.js +14 -0
- package/packages/compatibility/publication-qualification.js +11 -0
- package/packages/compatibility/publication-rehearsal.js +18 -0
- package/packages/compatibility/runtime-ref-resume-authority.js +13 -0
- package/packages/compatibility/tail-reseal-receipt.js +7 -0
- package/packages/compatibility/tail-reseal.js +11 -0
- package/packages/core/{v4-adopter-delivery-parity.js → adopter-delivery-parity.js} +12 -12
- package/packages/core/{v4-adopter-delivery.js → adopter-delivery.js} +24 -24
- package/packages/core/artifact-verification-envelope.js +5 -5
- package/packages/core/buildchain-contract.js +6 -6
- package/packages/core/buildchain-domain.wasm +0 -0
- package/packages/core/buildchain-kfd-claims.js +2 -2
- package/packages/core/buildchain-publication-authority.js +43 -26
- package/packages/core/{v4-canonical-contracts.js → canonical-contracts.js} +39 -103
- package/packages/core/ci-lane-change-budget.js +14 -1
- package/packages/core/controller-evidence.js +4 -1
- package/packages/core/{v4-cross-platform-adopter-qualification.js → cross-platform-adopter-qualification.js} +19 -19
- package/packages/core/{v4-delivery-warrant-fixture-runner.js → delivery-warrant-fixture-runner.js} +36 -32
- package/packages/core/{v4-delivery-warrant-read-candidate.js → delivery-warrant-read-candidate.js} +40 -40
- package/packages/core/{v4-delivery-warrant-semantic-diff-gate.js → delivery-warrant-semantic-diff-gate.js} +58 -59
- package/packages/core/{v4-delivery-warrant-shadow-adapter.js → delivery-warrant-shadow-adapter.js} +15 -15
- package/packages/core/dev-delivery-candidate-identity.js +40 -6
- package/packages/core/dev-delivery-execution-transfer.js +6 -6
- package/packages/core/dev-delivery-native-proof.js +12 -8
- package/packages/core/dev-delivery-warrant-legacy-recovery.js +1 -1
- package/packages/core/dev-delivery-warrant-native-compatibility.js +4 -4
- package/packages/core/dev-delivery-warrant-state.js +14 -15
- package/packages/core/dev-delivery-warrant.js +15 -5
- package/packages/core/domain-wasm-artifact.js +7 -0
- package/packages/core/domain-wasm.js +216 -0
- package/packages/core/{v4-floating-consumer-evidence.js → floating-consumer-evidence.js} +14 -14
- package/packages/core/{v4-floating-consumer-policy.js → floating-consumer-policy.js} +28 -30
- package/packages/core/{v4-floating-consumer-release-passport.js → floating-consumer-release-passport.js} +25 -25
- package/packages/core/github-governance-authority.js +4 -4
- package/packages/core/index.js +4 -8
- package/packages/core/kfd-adopter-manifest.js +46 -47
- package/packages/core/next-development-projection.js +26 -3
- package/packages/core/next-development-transition.js +5 -6
- package/packages/core/oci-compose-qualification.js +143 -0
- package/packages/core/oci-publication-bundle.js +281 -0
- package/packages/core/oci-publication-graph.js +206 -0
- package/packages/core/paper-agent-entry.js +30 -4
- package/packages/core/paper-fleet.js +1 -1
- package/packages/core/paper-runtime-channels.js +348 -0
- package/packages/core/paper-scaffold-content.js +10 -0
- package/packages/core/paper.js +37 -71
- package/packages/core/partial-mutation-recovery-qualification.js +18 -0
- package/packages/core/{v4-platform-stage-checkpoints.js → platform-stage-checkpoints.js} +37 -37
- package/packages/core/product-publication.js +59 -0
- package/packages/core/{v4-protected-publication-source.js → protected-publication-source.js} +22 -24
- package/packages/core/provider-operation-journal.js +62 -0
- package/packages/core/{v4-provider-readback-idempotency.js → provider-readback-idempotency.js} +40 -125
- package/packages/core/public-export-compatibility.js +33 -0
- package/packages/core/publication-development.js +72 -0
- package/packages/core/{v4-publication-qualification.js → publication-qualification.js} +17 -17
- package/packages/core/{v4-publication-rehearsal-capsule.js → publication-rehearsal-capsule.js} +23 -23
- package/packages/core/publication-rehearsal-projection.js +2 -2
- package/packages/core/{v4-publication-rehearsal-provider-bindings.js → publication-rehearsal-provider-bindings.js} +4 -4
- package/packages/core/publication-rehearsal-runtime.js +21 -21
- package/packages/core/{v4-publication-rehearsal.js → publication-rehearsal.js} +33 -33
- package/packages/core/publication-sealed-bundle.js +78 -13
- package/packages/core/release-activation-shadow.js +32 -0
- package/packages/core/release-candidate.js +6 -6
- package/packages/core/release-invocation.js +64 -0
- package/packages/core/release-line-dry-run.js +1 -1
- package/packages/core/release-passport-contract.js +5 -5
- package/packages/core/release-passport.js +41 -40
- package/packages/core/release-tail-product-capabilities.js +9 -0
- package/packages/core/release-tail-provider-plane.js +68 -1048
- package/packages/core/{v4-runtime-ref-resume-authority.js → runtime-ref-resume-authority.js} +36 -40
- package/packages/core/{v4-runtime-selector-persistence.js → runtime-selector-persistence.js} +7 -7
- package/packages/core/stable-publication-fence.js +28 -0
- package/packages/core/{v4-stage-capsule-local-store.js → stage-capsule-local-store.js} +56 -54
- package/packages/core/{v4-stage-capsule-qualification-campaign.js → stage-capsule-qualification-campaign.js} +37 -38
- package/packages/core/{v4-stage-capsule-qualification.js → stage-capsule-qualification.js} +28 -29
- package/packages/core/{v4-stage-capsule-resume-planner.js → stage-capsule-resume-planner.js} +29 -29
- package/packages/core/{v4-stage-capsule-store.js → stage-capsule-store.js} +59 -56
- package/packages/core/{v4-stage-capsule.js → stage-capsule.js} +45 -45
- package/packages/core/{v4-tail-reseal-contract.js → tail-reseal-contract.js} +6 -6
- package/packages/core/{v4-tail-reseal-github.js → tail-reseal-github.js} +12 -12
- package/packages/core/{v4-tail-reseal-receipt.js → tail-reseal-receipt.js} +22 -22
- package/packages/core/{v4-tail-reseal.js → tail-reseal.js} +29 -29
- package/packages/core/universal-workflow-bootstrap.js +586 -0
- package/scripts/{v4-architecture.mjs → architecture.mjs} +6 -6
- package/scripts/binary-publication-evidence.mjs +135 -0
- package/scripts/{v4-bridge-bootstrap.mjs → bridge-bootstrap.mjs} +14 -18
- package/scripts/{v4-bridge-evidence.mjs → bridge-evidence.mjs} +8 -8
- package/scripts/build-contract-core.mjs +1 -14
- package/scripts/build-domain-wasm.mjs +177 -0
- package/scripts/{v3-v4-capability-catalog.mjs → capability-parity-catalog.mjs} +19 -19
- package/scripts/check-action-bundles.mjs +12 -2
- package/scripts/{check-v3-v4-capability-inventory.mjs → check-capability-parity-inventory.mjs} +42 -42
- package/scripts/check-ci-lane-change-budget.mjs +4 -1
- package/scripts/check-core-mechanism-inventory.mjs +8 -4
- package/scripts/{check-v4-floating-consumer-policy-contract.mjs → check-floating-consumer-policy-contract.mjs} +10 -10
- package/scripts/check-implementation-naming.mjs +135 -0
- package/scripts/check-inventory.mjs +39 -47
- package/scripts/check-maintainability.mjs +25 -115
- package/scripts/{check-v4-public-dogfood-contract.mjs → check-public-dogfood-contract.mjs} +37 -24
- package/scripts/{check-v4-release-topology.mjs → check-release-topology.mjs} +131 -52
- package/scripts/{check-v4-runtime-semantic-closure.mjs → check-runtime-semantic-closure.mjs} +23 -17
- package/scripts/check-universal-workflow-bootstrap.mjs +266 -0
- package/scripts/check-workflow-taxonomy.mjs +6 -0
- package/scripts/{v4-consumer-policy.mjs → consumer-policy.mjs} +15 -15
- package/scripts/copy-domain-wasm.mjs +14 -0
- package/scripts/{v4-cross-platform-adopter-qualification.mjs → cross-platform-adopter-qualification.mjs} +9 -9
- package/scripts/{v4-declarative-promotion-admission.mjs → declarative-promotion-admission.mjs} +4 -4
- package/scripts/dev-delivery-authority-command-adapters.mjs +1 -1
- package/scripts/dev-delivery-authority.mjs +8 -8
- package/scripts/dev-delivery-source-proof-reuse.mjs +2 -1
- package/scripts/dev-delivery-warrant-options.mjs +15 -10
- package/scripts/dev-delivery-warrant-store.mjs +98 -13
- package/scripts/dev-delivery-warrant-transition.mjs +109 -0
- package/scripts/dev-delivery-warrant.mjs +80 -103
- package/scripts/dev-pr-auto-merge.mjs +15 -15
- package/scripts/dev-pr-delivery-warrant.mjs +1 -1
- package/scripts/generate-channel-build-workflow.mjs +7 -2
- package/scripts/generate-channel-promotion-workflow.mjs +19 -34
- package/scripts/generate-release-candidate-passport.mjs +23 -23
- package/scripts/generate-site-bundle.mjs +28 -28
- package/scripts/generate-universal-workflow-facades.mjs +498 -0
- package/scripts/generate-workflow-taxonomy.mjs +25 -0
- package/scripts/github-output.mjs +31 -0
- package/scripts/{v4-host-adapter.mjs → host-adapter.mjs} +1 -1
- package/scripts/implementation-references.mjs +25 -0
- package/scripts/init-repo.mjs +1 -1
- package/scripts/maintainability-metrics.mjs +16 -5
- package/scripts/maintainability-public-surface.mjs +115 -0
- package/scripts/next-development-review.mjs +313 -0
- package/scripts/oci-compose-preview.mjs +261 -0
- package/scripts/paper-work-fleet-cli.mjs +2 -0
- package/scripts/{v4-platform-stage-checkpoint-rehearsal.mjs → platform-stage-checkpoint-rehearsal.mjs} +17 -17
- package/scripts/{v4-product-publication-intent.mjs → product-publication-intent.mjs} +28 -13
- package/scripts/publication-candidate-kind.mjs +93 -0
- package/scripts/publication-candidate-sealer.mjs +16 -1
- package/scripts/{v4-publication-rehearsal-fixture.mjs → publication-rehearsal-fixture.mjs} +5 -5
- package/scripts/publication-settlement.mjs +211 -0
- package/scripts/release-asset-client.mjs +91 -0
- package/scripts/{v4-release-candidate-adapter.mjs → release-candidate-adapter.mjs} +4 -4
- package/scripts/release-candidate-resolver.mjs +24 -35
- package/scripts/release-tail.mjs +5 -5
- package/scripts/resume-from-candidate-run.mjs +35 -42
- package/scripts/site-capability-metadata.mjs +9 -0
- package/scripts/source-verification-evidence.mjs +344 -0
- package/scripts/stable-candidate-qualification.mjs +1 -1
- package/scripts/{v4-stage-capsule-qualification.mjs → stage-capsule-qualification.mjs} +62 -62
- package/scripts/{v4-stage-capsule-resume-rehearsal.mjs → stage-capsule-resume-rehearsal.mjs} +6 -6
- package/scripts/{v4-tail-reseal-macos-rehearsal.mjs → tail-reseal-macos-rehearsal.mjs} +9 -9
- package/scripts/{v4-tail-reseal.mjs → tail-reseal.mjs} +19 -19
- package/scripts/universal-facade-maintainability.mjs +91 -0
- package/scripts/universal-workflow-backflow.mjs +212 -0
- package/scripts/universal-workflow-engine.mjs +620 -0
- package/scripts/universal-workflow-self-dogfood.mjs +205 -0
- package/scripts/verify-version-state-delta.mjs +175 -0
- package/scripts/{v4-warrant-shadow-plan.mjs → warrant-shadow-plan.mjs} +6 -6
- package/scripts/workflow-taxonomy.mjs +507 -0
- package/templates/native-dev-delivery.yml +4 -7
- package/templates/universal-buildchain-bootstrap-recovery.yml +282 -0
- package/templates/universal-buildchain-bootstrap.yml +28 -0
- package/actions/v4-release-candidate-promote/README.md +0 -3
- package/packages/core/v4-partial-mutation-recovery-qualification.js +0 -395
- package/packages/core/v4-product-publication.js +0 -387
- package/packages/core/v4-provider-operation-journal.js +0 -531
- package/packages/core/v4-release-activation-shadow.js +0 -519
- package/packages/core/v4-release-invocation.js +0 -425
- package/packages/core/v4-stable-publication-fence.js +0 -357
- /package/architecture/{v4-adopter-delivery-parity.json → adopter-delivery-parity.json} +0 -0
- /package/architecture/{v3-core-mechanism-inventory.json → baseline-core-mechanism-inventory.json} +0 -0
- /package/architecture/{v4-canonical-contract-fixtures.json → canonical-contract-fixtures.json} +0 -0
- /package/architecture/{v4-compatibility-facts-parity.json → compatibility-facts-parity.json} +0 -0
- /package/architecture/{v4-delivery-warrant-shadow-bootstrap-plan.schema.json → delivery-warrant-shadow-bootstrap-plan.schema.json} +0 -0
- /package/architecture/{v4-delivery-warrant-shadow-fixtures.json → delivery-warrant-shadow-fixtures.json} +0 -0
- /package/architecture/{v4-delivery-warrant-shadow-fixtures.schema.json → delivery-warrant-shadow-fixtures.schema.json} +0 -0
- /package/architecture/{v4-exception-ledger.json → exception-ledger.json} +0 -0
- /package/architecture/{v4-exception-ledger.schema.json → exception-ledger.schema.json} +0 -0
- /package/architecture/{v4-release-invocation-fixtures.json → release-invocation-fixtures.json} +0 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { execFileSync } from "node:child_process";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
import { invokeDomainWasm } from "../packages/core/domain-wasm.js";
|
|
7
|
+
|
|
8
|
+
const workflow = ".github/workflows/self-build-verify.yml";
|
|
9
|
+
const proofPath = ".buildchain/source-verification/evidence.json";
|
|
10
|
+
const hash = (bytes) =>
|
|
11
|
+
`sha256:${crypto.createHash("sha256").update(bytes).digest("hex")}`;
|
|
12
|
+
const execute = (command, args, encoding) =>
|
|
13
|
+
execFileSync(command, args, {
|
|
14
|
+
encoding,
|
|
15
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
16
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
17
|
+
});
|
|
18
|
+
const run = (command, args) => execute(command, args, "utf8").trim();
|
|
19
|
+
const git = (...args) => run("git", args);
|
|
20
|
+
const write = (file, value) => {
|
|
21
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
22
|
+
fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function verificationIdentity({
|
|
26
|
+
env = process.env,
|
|
27
|
+
command = run,
|
|
28
|
+
revision = "HEAD",
|
|
29
|
+
} = {}) {
|
|
30
|
+
const sourceSha = command("git", ["rev-parse", revision]);
|
|
31
|
+
const sourceTree = command("git", ["rev-parse", `${revision}^{tree}`]);
|
|
32
|
+
const bytes = (file) => execute("git", ["show", `${sourceSha}:${file}`]);
|
|
33
|
+
const named = (files) =>
|
|
34
|
+
hash(JSON.stringify(files.map((file) => [file, hash(bytes(file))])));
|
|
35
|
+
for (const key of ["GITHUB_REPOSITORY", "ImageOS", "ImageVersion"])
|
|
36
|
+
if (!env[key]) throw new Error(`verification identity requires ${key}`);
|
|
37
|
+
return {
|
|
38
|
+
repository: env.GITHUB_REPOSITORY,
|
|
39
|
+
sourceSha,
|
|
40
|
+
sourceTree,
|
|
41
|
+
workflowRoot: hash(bytes(workflow)),
|
|
42
|
+
checkDefinitionRoot: named([
|
|
43
|
+
"package.json",
|
|
44
|
+
".buildchain/buildchain.toml",
|
|
45
|
+
"scripts/source-verification-evidence.mjs",
|
|
46
|
+
"scripts/verify-version-state-delta.mjs",
|
|
47
|
+
]),
|
|
48
|
+
runtimeRoot: named([
|
|
49
|
+
"packages/core/buildchain-domain.wasm",
|
|
50
|
+
"packages/core/domain-wasm-artifact.js",
|
|
51
|
+
]),
|
|
52
|
+
dependencyRoot: named([
|
|
53
|
+
"pnpm-lock.yaml",
|
|
54
|
+
"pnpm-workspace.yaml",
|
|
55
|
+
"crates/buildchain-domain-contracts/Cargo.lock",
|
|
56
|
+
"crates/buildchain-host-bridge/Cargo.lock",
|
|
57
|
+
]),
|
|
58
|
+
toolchainRoot: hash(
|
|
59
|
+
JSON.stringify([
|
|
60
|
+
process.version,
|
|
61
|
+
command("corepack", ["pnpm", "--version"]),
|
|
62
|
+
command("go", ["version"]),
|
|
63
|
+
command("rustc", ["+1.96.0", "--version"]),
|
|
64
|
+
command("cargo", ["+1.96.0", "--version"]),
|
|
65
|
+
command("rustc", ["--version"]),
|
|
66
|
+
command("cargo", ["--version"]),
|
|
67
|
+
]),
|
|
68
|
+
),
|
|
69
|
+
environmentRoot: hash(
|
|
70
|
+
JSON.stringify([
|
|
71
|
+
env.ImageOS,
|
|
72
|
+
env.ImageVersion,
|
|
73
|
+
process.platform,
|
|
74
|
+
process.arch,
|
|
75
|
+
...[
|
|
76
|
+
"CI",
|
|
77
|
+
"NODE_ENV",
|
|
78
|
+
"TZ",
|
|
79
|
+
"LANG",
|
|
80
|
+
"LC_ALL",
|
|
81
|
+
"SOURCE_DATE_EPOCH",
|
|
82
|
+
"BUILDCHAIN_SITE_GENERATED_AT",
|
|
83
|
+
"BUILDCHAIN_SITE_PUBLISHED_AT",
|
|
84
|
+
"BUILDCHAIN_SITE_TIMESTAMP_POLICY",
|
|
85
|
+
"BUILDCHAIN_SOURCE_SHA",
|
|
86
|
+
"RUSTUP_TOOLCHAIN",
|
|
87
|
+
"RUSTFLAGS",
|
|
88
|
+
"CARGO_ENCODED_RUSTFLAGS",
|
|
89
|
+
"NODE_OPTIONS",
|
|
90
|
+
"GOFLAGS",
|
|
91
|
+
"GOTOOLCHAIN",
|
|
92
|
+
].map((key) => env[key] || ""),
|
|
93
|
+
]),
|
|
94
|
+
),
|
|
95
|
+
platform:
|
|
96
|
+
{ linux: "linux", darwin: "macos", win32: "windows" }[process.platform] +
|
|
97
|
+
`-${process.arch}`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function planVerification(input) {
|
|
102
|
+
return invokeDomainWasm("source-verification-plan", input);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function sealVerification(input) {
|
|
106
|
+
return invokeDomainWasm("source-verification-seal", input);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const api = (endpoint, binary = false) =>
|
|
110
|
+
execute("gh", ["api", endpoint], binary ? undefined : "utf8");
|
|
111
|
+
|
|
112
|
+
// Only the one bounded proof file is read; archive paths are never extracted.
|
|
113
|
+
export function readProofArchive(archive, digest) {
|
|
114
|
+
if (hash(archive) !== digest)
|
|
115
|
+
throw new Error("artifact archive digest mismatch");
|
|
116
|
+
const source = [
|
|
117
|
+
"import io,json,sys,zipfile",
|
|
118
|
+
"z=zipfile.ZipFile(io.BytesIO(sys.stdin.buffer.read()))",
|
|
119
|
+
"entries=[e for e in z.infolist() if e.filename=='evidence.json']",
|
|
120
|
+
"assert len(entries)==1 and entries[0].file_size <= 1048576, 'invalid proof archive'",
|
|
121
|
+
"sys.stdout.buffer.write(z.read(entries[0]))",
|
|
122
|
+
].join("\n");
|
|
123
|
+
return JSON.parse(
|
|
124
|
+
execFileSync(
|
|
125
|
+
process.platform === "win32" ? "python" : "python3",
|
|
126
|
+
["-c", source],
|
|
127
|
+
{
|
|
128
|
+
input: archive,
|
|
129
|
+
maxBuffer: 1048576,
|
|
130
|
+
encoding: "utf8",
|
|
131
|
+
},
|
|
132
|
+
),
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export async function discoverVerification({
|
|
137
|
+
expected,
|
|
138
|
+
evaluatedAtMs,
|
|
139
|
+
fetchJson,
|
|
140
|
+
fetchArchive,
|
|
141
|
+
}) {
|
|
142
|
+
const prefix = `repos/${expected.repository}/actions`;
|
|
143
|
+
const response = await fetchJson(
|
|
144
|
+
`${prefix}/workflows/self-build-verify.yml/runs?event=merge_group&status=success&head_sha=${expected.sourceSha}&per_page=10`,
|
|
145
|
+
);
|
|
146
|
+
const reasons = [];
|
|
147
|
+
for (const listed of response.workflow_runs || []) {
|
|
148
|
+
try {
|
|
149
|
+
const run = await fetchJson(`${prefix}/runs/${listed.id}`);
|
|
150
|
+
if (
|
|
151
|
+
run.repository?.full_name !== expected.repository ||
|
|
152
|
+
run.head_sha !== expected.sourceSha ||
|
|
153
|
+
run.path !== workflow ||
|
|
154
|
+
run.event !== "merge_group" ||
|
|
155
|
+
run.conclusion !== "success" ||
|
|
156
|
+
run.status !== "completed"
|
|
157
|
+
)
|
|
158
|
+
throw new Error("untrusted evidence run");
|
|
159
|
+
const assets = await fetchJson(
|
|
160
|
+
`${prefix}/runs/${run.id}/artifacts?per_page=100`,
|
|
161
|
+
);
|
|
162
|
+
const matches = (assets.artifacts || []).filter(
|
|
163
|
+
(a) =>
|
|
164
|
+
a.name === `source-verification-${run.head_sha}-${run.run_attempt}`,
|
|
165
|
+
);
|
|
166
|
+
if (
|
|
167
|
+
matches.length !== 1 ||
|
|
168
|
+
matches[0].expired ||
|
|
169
|
+
matches[0].size_in_bytes > 1048576
|
|
170
|
+
)
|
|
171
|
+
throw new Error("missing or expired proof artifact");
|
|
172
|
+
const asset = matches[0];
|
|
173
|
+
const candidate = readProofArchive(
|
|
174
|
+
await fetchArchive(`${prefix}/artifacts/${asset.id}/zip`),
|
|
175
|
+
asset.digest,
|
|
176
|
+
);
|
|
177
|
+
const decision = planVerification({
|
|
178
|
+
expected,
|
|
179
|
+
evaluatedAtMs,
|
|
180
|
+
candidate,
|
|
181
|
+
provider: {
|
|
182
|
+
repository: run.repository.full_name,
|
|
183
|
+
runId: String(run.id),
|
|
184
|
+
runAttempt: run.run_attempt,
|
|
185
|
+
headSha: run.head_sha,
|
|
186
|
+
event: run.event,
|
|
187
|
+
status: run.status,
|
|
188
|
+
conclusion: run.conclusion,
|
|
189
|
+
workflowPath: run.path,
|
|
190
|
+
artifactDigest: asset.digest,
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
if (decision.decision === "reuse")
|
|
194
|
+
return { ...decision, sourceSha: expected.sourceSha };
|
|
195
|
+
reasons.push(decision.reason);
|
|
196
|
+
} catch {
|
|
197
|
+
// Provider/transport or evidence failures are cache misses, never a green check.
|
|
198
|
+
reasons.push("unavailable-or-invalid-evidence");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
decision: "execute",
|
|
203
|
+
reason: reasons.join(",") || "missing-evidence",
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function output(decision) {
|
|
208
|
+
write(".buildchain/source-verification/decision.json", decision);
|
|
209
|
+
if (process.env.GITHUB_OUTPUT)
|
|
210
|
+
fs.appendFileSync(
|
|
211
|
+
process.env.GITHUB_OUTPUT,
|
|
212
|
+
`decision=${decision.decision}\n`,
|
|
213
|
+
);
|
|
214
|
+
if (process.env.GITHUB_STEP_SUMMARY)
|
|
215
|
+
fs.appendFileSync(
|
|
216
|
+
process.env.GITHUB_STEP_SUMMARY,
|
|
217
|
+
`Source verification: **${decision.decision}** (${decision.reason}).${decision.runId ? ` Original full execution: run ${decision.runId}, attempt ${decision.runAttempt}, proof ${decision.evidenceRoot}.` : ""}\n`,
|
|
218
|
+
);
|
|
219
|
+
console.log(JSON.stringify(decision));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function providerDiscovery(expected) {
|
|
223
|
+
return discoverVerification({
|
|
224
|
+
expected,
|
|
225
|
+
evaluatedAtMs: Date.now(),
|
|
226
|
+
fetchJson: async (endpoint) => JSON.parse(api(endpoint)),
|
|
227
|
+
fetchArchive: async (endpoint) => api(endpoint, true),
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export async function planVersionProjection({
|
|
232
|
+
baseSha,
|
|
233
|
+
headSha,
|
|
234
|
+
discover,
|
|
235
|
+
regenerate,
|
|
236
|
+
}) {
|
|
237
|
+
const proof = await discover(baseSha);
|
|
238
|
+
if (proof.decision !== "reuse")
|
|
239
|
+
return { decision: "execute", reason: "base-full-proof-unavailable" };
|
|
240
|
+
const projection = await regenerate(baseSha, headSha);
|
|
241
|
+
return {
|
|
242
|
+
...proof,
|
|
243
|
+
decision: "projection",
|
|
244
|
+
reason: "verified-base-and-exact-regenerated-version-delta",
|
|
245
|
+
projection,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async function planCurrentVerification() {
|
|
250
|
+
if (git("status", "--porcelain", "--untracked-files=no"))
|
|
251
|
+
throw new Error("dirty source");
|
|
252
|
+
const event = process.env.GITHUB_EVENT_NAME;
|
|
253
|
+
const headSha = git("rev-parse", "HEAD");
|
|
254
|
+
if (
|
|
255
|
+
event === "push" &&
|
|
256
|
+
process.env.GITHUB_REF?.startsWith("refs/heads/dev/")
|
|
257
|
+
) {
|
|
258
|
+
const exact = await providerDiscovery(verificationIdentity());
|
|
259
|
+
if (exact.decision === "reuse") return exact;
|
|
260
|
+
}
|
|
261
|
+
if (!["pull_request", "merge_group", "push"].includes(event))
|
|
262
|
+
return { decision: "execute", reason: "full-execution-required-for-event" };
|
|
263
|
+
const payload = JSON.parse(fs.readFileSync(process.env.GITHUB_EVENT_PATH));
|
|
264
|
+
const baseSha =
|
|
265
|
+
event === "merge_group"
|
|
266
|
+
? payload.merge_group?.base_sha
|
|
267
|
+
: event === "pull_request"
|
|
268
|
+
? payload.pull_request?.base.sha
|
|
269
|
+
: process.env.GITHUB_REF?.startsWith("refs/heads/dev/")
|
|
270
|
+
? payload.before
|
|
271
|
+
: null;
|
|
272
|
+
if (!/^[a-f0-9]{40}$/u.test(baseSha || ""))
|
|
273
|
+
throw new Error("no exact protected base");
|
|
274
|
+
return planVersionProjection({
|
|
275
|
+
baseSha,
|
|
276
|
+
headSha,
|
|
277
|
+
discover: (revision) =>
|
|
278
|
+
providerDiscovery(verificationIdentity({ revision })),
|
|
279
|
+
regenerate: async (baseSha, headSha) => {
|
|
280
|
+
const { verifyVersionStateDelta } =
|
|
281
|
+
await import("./verify-version-state-delta.mjs");
|
|
282
|
+
return verifyVersionStateDelta({
|
|
283
|
+
baseSha,
|
|
284
|
+
headSha,
|
|
285
|
+
nodeModules: path.resolve(".buildchain/runtime/node_modules"),
|
|
286
|
+
});
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export async function main(mode) {
|
|
292
|
+
if (mode === "plan") {
|
|
293
|
+
try {
|
|
294
|
+
output(await planCurrentVerification());
|
|
295
|
+
} catch {
|
|
296
|
+
output({
|
|
297
|
+
decision: "execute",
|
|
298
|
+
reason: "identity-provider-or-version-delta-unavailable",
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
} else if (mode === "start") {
|
|
302
|
+
write(".buildchain/source-verification/start.json", {
|
|
303
|
+
identity: verificationIdentity(),
|
|
304
|
+
startedAtMs: Date.now(),
|
|
305
|
+
});
|
|
306
|
+
} else if (mode === "seal") {
|
|
307
|
+
if (process.env.GITHUB_EVENT_NAME !== "merge_group")
|
|
308
|
+
throw new Error(
|
|
309
|
+
"only merge-group full executions produce reusable proof",
|
|
310
|
+
);
|
|
311
|
+
const started = JSON.parse(
|
|
312
|
+
fs.readFileSync(".buildchain/source-verification/start.json"),
|
|
313
|
+
);
|
|
314
|
+
if (
|
|
315
|
+
git("status", "--porcelain", "--untracked-files=no") ||
|
|
316
|
+
JSON.stringify(started.identity) !==
|
|
317
|
+
JSON.stringify(verificationIdentity())
|
|
318
|
+
)
|
|
319
|
+
throw new Error(
|
|
320
|
+
"source or verification identity changed during execution",
|
|
321
|
+
);
|
|
322
|
+
const completedAtMs = Date.now();
|
|
323
|
+
write(
|
|
324
|
+
proofPath,
|
|
325
|
+
sealVerification({
|
|
326
|
+
schema: "buildchain-v4-source-verification-evidence/v1",
|
|
327
|
+
...started,
|
|
328
|
+
runId: process.env.GITHUB_RUN_ID,
|
|
329
|
+
runAttempt: Number(process.env.GITHUB_RUN_ATTEMPT),
|
|
330
|
+
event: process.env.GITHUB_EVENT_NAME,
|
|
331
|
+
validationKind: "full-source",
|
|
332
|
+
exitCode: 0,
|
|
333
|
+
completedAtMs,
|
|
334
|
+
expiresAtMs: completedAtMs + 6 * 60 * 60 * 1000,
|
|
335
|
+
}),
|
|
336
|
+
);
|
|
337
|
+
} else throw new Error(`unknown verification evidence mode: ${mode}`);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
|
|
341
|
+
main(process.argv[2]).catch((error) => {
|
|
342
|
+
console.error(error.message);
|
|
343
|
+
process.exitCode = 1;
|
|
344
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const DEFAULTS = {
|
|
4
|
-
buildWorkflowFile: "build-
|
|
4
|
+
buildWorkflowFile: "self-build-fixture.yml",
|
|
5
5
|
buildWorkflowName: "Build Surface Fixture",
|
|
6
6
|
canaryRepository: "kungfu-systems/site-libkungfu-dev",
|
|
7
7
|
canaryWorkflowFile: "buildchain-stable-canary.yml",
|
|
@@ -7,31 +7,31 @@ import { spawnSync } from "node:child_process";
|
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from "../packages/core/
|
|
14
|
-
import {
|
|
10
|
+
ContractFault,
|
|
11
|
+
domainCanonicalBytes,
|
|
12
|
+
domainContentRoot,
|
|
13
|
+
} from "../packages/core/canonical-contracts.js";
|
|
14
|
+
import { StageCapsuleLocalStore } from "../packages/core/stage-capsule-local-store.js";
|
|
15
15
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from "../packages/core/
|
|
16
|
+
restorePlatformStageCheckpoint,
|
|
17
|
+
validatePlatformStageCheckpointDeclaration,
|
|
18
|
+
} from "../packages/core/platform-stage-checkpoints.js";
|
|
19
19
|
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
} from "../packages/core/
|
|
20
|
+
STAGE_CAPSULE_CAMPAIGN_RECORDED_AT,
|
|
21
|
+
createStageCapsuleCampaignProfile,
|
|
22
|
+
emitStageCapsuleCampaignCheckpoint,
|
|
23
|
+
runStageCapsuleFaultCampaign,
|
|
24
|
+
stageCapsuleCampaignAggregateRoots,
|
|
25
|
+
stageCapsuleCampaignDependencies,
|
|
26
|
+
stageCapsuleCampaignStages,
|
|
27
|
+
} from "../packages/core/stage-capsule-qualification-campaign.js";
|
|
28
28
|
import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
} from "../packages/core/
|
|
34
|
-
import {
|
|
29
|
+
STAGE_CAPSULE_PLATFORM_QUALIFICATION_CONTRACT,
|
|
30
|
+
qualifyStageCapsuleCampaign,
|
|
31
|
+
reconcileStageCapsuleWave,
|
|
32
|
+
validateStageCapsulePlatformQualification,
|
|
33
|
+
} from "../packages/core/stage-capsule-qualification.js";
|
|
34
|
+
import { planStageCapsuleResume } from "../packages/core/stage-capsule-resume-planner.js";
|
|
35
35
|
|
|
36
36
|
const repoRoot = path.resolve(
|
|
37
37
|
path.dirname(fileURLToPath(import.meta.url)),
|
|
@@ -56,13 +56,13 @@ function readJson(file) {
|
|
|
56
56
|
|
|
57
57
|
function writeJson(file, value) {
|
|
58
58
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
59
|
-
fs.writeFileSync(file,
|
|
59
|
+
fs.writeFileSync(file, domainCanonicalBytes(value), { flag: "wx" });
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function declaration() {
|
|
63
|
-
return
|
|
63
|
+
return validatePlatformStageCheckpointDeclaration(
|
|
64
64
|
readJson(
|
|
65
|
-
path.join(repoRoot, "architecture/
|
|
65
|
+
path.join(repoRoot, "architecture/platform-stage-checkpoints.json"),
|
|
66
66
|
),
|
|
67
67
|
);
|
|
68
68
|
}
|
|
@@ -96,7 +96,7 @@ function prepareContext(context) {
|
|
|
96
96
|
context.lifecycleConfig = buildchainConfigModule.loadBuildchainConfig(
|
|
97
97
|
context.consumerRoot,
|
|
98
98
|
);
|
|
99
|
-
context.campaignProfile =
|
|
99
|
+
context.campaignProfile = createStageCapsuleCampaignProfile(context);
|
|
100
100
|
return context;
|
|
101
101
|
}
|
|
102
102
|
|
|
@@ -115,28 +115,28 @@ function directoryBytes(directory) {
|
|
|
115
115
|
|
|
116
116
|
function seed(context) {
|
|
117
117
|
prepareContext(context);
|
|
118
|
-
const campaignStages =
|
|
118
|
+
const campaignStages = stageCapsuleCampaignStages(context);
|
|
119
119
|
const retainedStages = campaignStages.slice(
|
|
120
120
|
0,
|
|
121
121
|
Math.max(1, campaignStages.indexOf("verify")),
|
|
122
122
|
);
|
|
123
123
|
const failedStage = "verify";
|
|
124
124
|
const targetStage = campaignStages.at(-1);
|
|
125
|
-
const referenceStore = new
|
|
125
|
+
const referenceStore = new StageCapsuleLocalStore(
|
|
126
126
|
path.join(context.workRoot, "reference-store"),
|
|
127
127
|
);
|
|
128
|
-
const retainedStore = new
|
|
128
|
+
const retainedStore = new StageCapsuleLocalStore(
|
|
129
129
|
path.join(context.workRoot, "retained-store"),
|
|
130
130
|
);
|
|
131
131
|
const reference = campaignStages.map((stage) => ({
|
|
132
132
|
stage,
|
|
133
|
-
...
|
|
133
|
+
...emitStageCapsuleCampaignCheckpoint(context, stage, referenceStore),
|
|
134
134
|
}));
|
|
135
135
|
const retained = retainedStages.map((stage) => ({
|
|
136
136
|
stage,
|
|
137
|
-
...
|
|
137
|
+
...emitStageCapsuleCampaignCheckpoint(context, stage, retainedStore),
|
|
138
138
|
}));
|
|
139
|
-
const lateFailure =
|
|
139
|
+
const lateFailure = emitStageCapsuleCampaignCheckpoint(
|
|
140
140
|
context,
|
|
141
141
|
failedStage,
|
|
142
142
|
retainedStore,
|
|
@@ -150,7 +150,7 @@ function seed(context) {
|
|
|
150
150
|
platform: context.platform,
|
|
151
151
|
runtimeRef: context.runtimeRef,
|
|
152
152
|
campaignProfileRoot: context.campaignProfile.profileRoot,
|
|
153
|
-
referenceRoots:
|
|
153
|
+
referenceRoots: stageCapsuleCampaignAggregateRoots(reference),
|
|
154
154
|
retainedCapsuleRoots: retained.map(({ stage, capsule }) => ({
|
|
155
155
|
stage,
|
|
156
156
|
capsuleRoot: capsule.capsuleRoot,
|
|
@@ -165,7 +165,7 @@ function seed(context) {
|
|
|
165
165
|
};
|
|
166
166
|
const evidence = {
|
|
167
167
|
...body,
|
|
168
|
-
evidenceRoot:
|
|
168
|
+
evidenceRoot: domainContentRoot("stage-capsule-seed-evidence", body),
|
|
169
169
|
};
|
|
170
170
|
writeJson(path.join(context.workRoot, "seed-evidence.json"), evidence);
|
|
171
171
|
writeJson(path.join(context.workRoot, "campaign-state.json"), {
|
|
@@ -179,7 +179,7 @@ function seed(context) {
|
|
|
179
179
|
dependencies: Object.fromEntries(
|
|
180
180
|
campaignStages.map((stage) => [
|
|
181
181
|
stage,
|
|
182
|
-
|
|
182
|
+
stageCapsuleCampaignDependencies(context, stage),
|
|
183
183
|
]),
|
|
184
184
|
),
|
|
185
185
|
retainedStages,
|
|
@@ -200,7 +200,7 @@ function stageNode(state, store, reference) {
|
|
|
200
200
|
if (state.retainedStages.includes(reference.stage)) {
|
|
201
201
|
const restored = store.restore({
|
|
202
202
|
capsuleRoot: reference.capsule.capsuleRoot,
|
|
203
|
-
recordedAt:
|
|
203
|
+
recordedAt: STAGE_CAPSULE_CAMPAIGN_RECORDED_AT,
|
|
204
204
|
});
|
|
205
205
|
candidate = {
|
|
206
206
|
capsule: restored.capsule,
|
|
@@ -219,7 +219,7 @@ function stageNode(state, store, reference) {
|
|
|
219
219
|
function resumeRequest(state, store) {
|
|
220
220
|
return {
|
|
221
221
|
schema: "buildchain-v4-stage-capsule-resume-request/v1",
|
|
222
|
-
evaluatedAt:
|
|
222
|
+
evaluatedAt: STAGE_CAPSULE_CAMPAIGN_RECORDED_AT,
|
|
223
223
|
nodes: state.reference.map((reference) =>
|
|
224
224
|
stageNode(state, store, reference),
|
|
225
225
|
),
|
|
@@ -229,7 +229,7 @@ function resumeRequest(state, store) {
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
function emitMissing(context, state, store, stageId) {
|
|
232
|
-
const emitted =
|
|
232
|
+
const emitted = emitStageCapsuleCampaignCheckpoint(context, stageId, store);
|
|
233
233
|
const expected = state.reference.find(({ stage }) => stage === stageId);
|
|
234
234
|
if (
|
|
235
235
|
emitted.capsule.capsuleRoot !== expected.capsule.capsuleRoot ||
|
|
@@ -253,18 +253,18 @@ function resume(context) {
|
|
|
253
253
|
["consumerSourceRevision", "stage-capsule-campaign-source-revision-drift"],
|
|
254
254
|
])
|
|
255
255
|
if (state[name] !== context[name])
|
|
256
|
-
throw new
|
|
256
|
+
throw new ContractFault(code, `$/campaign/${name}`, `${name} differs`);
|
|
257
257
|
if (state.campaignProfileRoot !== context.campaignProfile.profileRoot)
|
|
258
|
-
throw new
|
|
258
|
+
throw new ContractFault(
|
|
259
259
|
"stage-capsule-campaign-lifecycle-profile-drift",
|
|
260
260
|
"$/campaign/campaignProfileRoot",
|
|
261
261
|
"campaign lifecycle profile differs",
|
|
262
262
|
);
|
|
263
|
-
const store = new
|
|
263
|
+
const store = new StageCapsuleLocalStore(
|
|
264
264
|
path.join(context.workRoot, "retained-store"),
|
|
265
265
|
);
|
|
266
266
|
const request = resumeRequest(state, store);
|
|
267
|
-
const plan =
|
|
267
|
+
const plan = planStageCapsuleResume(request);
|
|
268
268
|
const expectedRestores = [state.retainedStages.at(-1)];
|
|
269
269
|
const expectedStages = state.campaignStages.filter(
|
|
270
270
|
(stage) => !state.retainedStages.includes(stage),
|
|
@@ -292,12 +292,12 @@ function resume(context) {
|
|
|
292
292
|
const started = process.hrtime.bigint();
|
|
293
293
|
for (const stageId of plan.requiredRestores) {
|
|
294
294
|
const reference = state.reference.find(({ stage }) => stage === stageId);
|
|
295
|
-
|
|
295
|
+
restorePlatformStageCheckpoint({
|
|
296
296
|
declaration: context.declaration,
|
|
297
297
|
expectedPlatform: context.platform,
|
|
298
298
|
expectedStage: stageId,
|
|
299
299
|
capsuleRoot: reference.capsule.capsuleRoot,
|
|
300
|
-
recordedAt:
|
|
300
|
+
recordedAt: STAGE_CAPSULE_CAMPAIGN_RECORDED_AT,
|
|
301
301
|
targetDirectory: path.join(context.workRoot, "restored", stageId),
|
|
302
302
|
store,
|
|
303
303
|
});
|
|
@@ -316,9 +316,9 @@ function resume(context) {
|
|
|
316
316
|
state.campaignStages.indexOf(left.stage) -
|
|
317
317
|
state.campaignStages.indexOf(right.stage),
|
|
318
318
|
);
|
|
319
|
-
const freshBuild =
|
|
320
|
-
const resumedBuild =
|
|
321
|
-
const campaignFaults =
|
|
319
|
+
const freshBuild = stageCapsuleCampaignAggregateRoots(state.reference);
|
|
320
|
+
const resumedBuild = stageCapsuleCampaignAggregateRoots(resumedEntries);
|
|
321
|
+
const campaignFaults = runStageCapsuleFaultCampaign(request);
|
|
322
322
|
const metrics = {
|
|
323
323
|
fullStageCount: state.campaignStages.length,
|
|
324
324
|
rebuiltStageCount: plan.requiredStages.length,
|
|
@@ -341,7 +341,7 @@ function resume(context) {
|
|
|
341
341
|
planRoot: plan.planRoot,
|
|
342
342
|
freshBuild,
|
|
343
343
|
resumedBuild,
|
|
344
|
-
faultCampaignRoot:
|
|
344
|
+
faultCampaignRoot: domainContentRoot(
|
|
345
345
|
"stage-capsule-fault-campaign",
|
|
346
346
|
campaignFaults,
|
|
347
347
|
),
|
|
@@ -349,10 +349,13 @@ function resume(context) {
|
|
|
349
349
|
};
|
|
350
350
|
const resumeEvidence = {
|
|
351
351
|
...resumeBody,
|
|
352
|
-
evidenceRoot:
|
|
352
|
+
evidenceRoot: domainContentRoot(
|
|
353
|
+
"stage-capsule-resume-evidence",
|
|
354
|
+
resumeBody,
|
|
355
|
+
),
|
|
353
356
|
};
|
|
354
357
|
const reportBody = {
|
|
355
|
-
schema:
|
|
358
|
+
schema: STAGE_CAPSULE_PLATFORM_QUALIFICATION_CONTRACT,
|
|
356
359
|
mode: "shadow-only",
|
|
357
360
|
productionAuthority: "v3",
|
|
358
361
|
consumer: context.consumer,
|
|
@@ -389,9 +392,9 @@ function resume(context) {
|
|
|
389
392
|
providerEffects: false,
|
|
390
393
|
productionWrites: false,
|
|
391
394
|
};
|
|
392
|
-
const report =
|
|
395
|
+
const report = validateStageCapsulePlatformQualification({
|
|
393
396
|
...reportBody,
|
|
394
|
-
reportRoot:
|
|
397
|
+
reportRoot: domainContentRoot(
|
|
395
398
|
"stage-capsule-platform-qualification",
|
|
396
399
|
reportBody,
|
|
397
400
|
),
|
|
@@ -401,7 +404,7 @@ function resume(context) {
|
|
|
401
404
|
resumeEvidence,
|
|
402
405
|
);
|
|
403
406
|
writeJson(path.join(context.workRoot, "report.json"), report);
|
|
404
|
-
process.stdout.write(
|
|
407
|
+
process.stdout.write(domainCanonicalBytes(report));
|
|
405
408
|
}
|
|
406
409
|
|
|
407
410
|
function child(action, context) {
|
|
@@ -439,7 +442,7 @@ function child(action, context) {
|
|
|
439
442
|
function campaign(context) {
|
|
440
443
|
if (option("stage-capsule-mode", "shadow") === "v3") {
|
|
441
444
|
process.stdout.write(
|
|
442
|
-
|
|
445
|
+
domainCanonicalBytes({
|
|
443
446
|
schema: "buildchain-v4-stage-capsule-rollback/v1",
|
|
444
447
|
switch: "stage-capsule-mode=v3",
|
|
445
448
|
productionAuthority: "v3",
|
|
@@ -485,13 +488,10 @@ function aggregate() {
|
|
|
485
488
|
.map((value) => value.trim())
|
|
486
489
|
.filter(Boolean)
|
|
487
490
|
: undefined;
|
|
488
|
-
const qualification =
|
|
489
|
-
reports,
|
|
490
|
-
expectedConsumers,
|
|
491
|
-
);
|
|
491
|
+
const qualification = qualifyStageCapsuleCampaign(reports, expectedConsumers);
|
|
492
492
|
const output = option("output");
|
|
493
493
|
if (output) writeJson(path.resolve(output), qualification);
|
|
494
|
-
process.stdout.write(
|
|
494
|
+
process.stdout.write(domainCanonicalBytes(qualification));
|
|
495
495
|
}
|
|
496
496
|
|
|
497
497
|
function reconcile() {
|
|
@@ -499,10 +499,10 @@ function reconcile() {
|
|
|
499
499
|
const request = readJson(path.resolve(required("wave-evidence")));
|
|
500
500
|
if (request.qualificationRoot !== qualification.qualificationRoot)
|
|
501
501
|
throw new Error("wave evidence does not bind the qualification root");
|
|
502
|
-
const reconciliation =
|
|
502
|
+
const reconciliation = reconcileStageCapsuleWave(request);
|
|
503
503
|
const output = option("output");
|
|
504
504
|
if (output) writeJson(path.resolve(output), reconciliation);
|
|
505
|
-
process.stdout.write(
|
|
505
|
+
process.stdout.write(domainCanonicalBytes(reconciliation));
|
|
506
506
|
}
|
|
507
507
|
|
|
508
508
|
const action = process.argv[2] || "";
|
|
@@ -516,7 +516,7 @@ else if (action === "aggregate") aggregate();
|
|
|
516
516
|
else if (action === "reconcile") reconcile();
|
|
517
517
|
else if (action === "smoke") {
|
|
518
518
|
const temporary = fs.mkdtempSync(
|
|
519
|
-
path.join(os.tmpdir(), "buildchain-
|
|
519
|
+
path.join(os.tmpdir(), "buildchain-capsule-"),
|
|
520
520
|
);
|
|
521
521
|
const context = contextFromArgs();
|
|
522
522
|
context.workRoot = temporary;
|