@kungfu-tech/buildchain 4.1.0-alpha.0 → 4.1.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +30 -41
- package/CONTRIBUTING.md +6 -7
- package/architecture/action-taxonomy.json +5 -21
- package/architecture/agent-change-map.md +74 -56
- package/architecture/build-orchestration.json +8 -1
- package/architecture/ci-lane-change-budget.json +179 -69
- package/architecture/floating-consumer-policy.json +7 -17
- package/architecture/internal-capabilities.json +58 -72
- package/architecture/maintainability-debt.json +138 -52
- package/architecture/maintainability-policy.json +6 -15
- package/architecture/promotion-job-topology.json +39 -20
- package/architecture/release-topology.json +26 -37
- package/architecture/runtime-entry.json +26 -0
- package/architecture/runtime-resume-lineage.json +23 -0
- package/architecture/stage-capsule-qualification.json +2 -2
- package/architecture/universal-workflow-bootstrap.json +10 -25
- package/architecture/universal-workflow-capability-policy.json +61 -0
- package/architecture/universal-workflow-fault-campaign.json +18 -24
- package/architecture/workflow-taxonomy.json +0 -11
- package/contracts/fixtures/{v4-runtime-ref-resume-authority-v1 → runtime-resume-lineage-v2}/scenario.json +2 -3
- package/contracts/fixtures/v4-floating-consumer-policy-v1/cases.json +2 -2
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
- package/contracts/promotion-invocation-v1.schema.json +0 -44
- package/contracts/promotion-request-v1.schema.json +0 -39
- package/contracts/runtime-resume-lineage-v2.schema.json +182 -0
- package/dist/site/buildchain-contract.json +472 -361
- package/dist/site/buildchain-site.json +99 -99
- package/dist/site/capability-registry.json +3 -3
- package/dist/site/cli-registry.json +4 -4
- package/dist/site/controller-registry.json +94 -78
- package/dist/site/kfd-claims.json +224 -343
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +15 -15
- package/dist/site/node-api-registry.json +239 -354
- package/dist/site/page-registry.json +80 -80
- package/dist/site/public-surface-audit.json +203 -254
- package/dist/site/publication-authority-registry.json +1 -24
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-provenance.json +1 -1
- package/dist/site/site-manifest.json +19 -19
- package/dist/site/workflow-registry.json +197 -357
- package/docs/MAP.md +3 -3
- package/docs/auditable-demo.md +4 -4
- package/docs/cli-reference.md +2 -2
- package/docs/code-organization.md +5 -4
- package/docs/controller-evidence.md +2 -2
- package/docs/dev-alpha-candidate-patrol.md +5 -5
- package/docs/dev-delivery-warrant.md +14 -24
- package/docs/engineering-housekeeper.md +3 -3
- package/docs/github-artifact-attestation.md +9 -12
- package/docs/github-governance-authority.md +4 -4
- package/docs/node-api-reference.md +153 -167
- package/docs/publication-artifacts.md +3 -4
- package/docs/publication-authority.md +2 -2
- package/docs/release-candidate.md +21 -27
- package/docs/release-governance.md +10 -10
- package/docs/release-promotion-request.md +11 -18
- package/docs/release-propagation.md +5 -6
- package/docs/release-tail-provider-plane.md +2 -3
- package/docs/reusable-build-surface.md +13 -7
- package/docs/runtime-entry.md +122 -0
- package/docs/runtime-train-validation.md +30 -41
- package/docs/v4-publication-rehearsal.md +5 -5
- package/docs/v4-stage-capsule.md +9 -10
- package/docs/web-surface-deployments.md +16 -20
- package/docs/workflow-catalog.md +0 -1
- package/package.json +6 -6
- package/packages/core/adoption/commands/init-repo.mjs +2 -2
- package/packages/core/adoption/cross-platform-adopter-qualification.js +2 -13
- package/packages/core/adoption/qualification/actions.js +3 -5
- package/packages/core/adoption/qualification/admission.js +2 -3
- package/packages/core/build/artifact/attestation.js +0 -1
- package/packages/core/build/artifact/contracts.js +1 -4
- package/packages/core/build/artifact/store.js +6 -5
- package/packages/core/build/artifact-signing.js +4 -10
- package/packages/core/build/binary/actions.js +15 -9
- package/packages/core/build/binary-publication-dispatch.js +2 -6
- package/packages/core/build/demo/action-context.js +2 -11
- package/packages/core/build/demo/binary-action.js +8 -10
- package/packages/core/build/gate/controller.js +0 -2
- package/packages/core/build/github-attestation/action.js +2 -7
- package/packages/core/build/github-attestation/admission.js +0 -8
- package/packages/core/build/github-attestation/transaction.js +1 -2
- package/packages/core/build/lifecycle/stage-action.js +2 -0
- package/packages/core/build/lifecycle/stage.js +6 -3
- package/packages/core/build/macos-credential-island/dmg-assembly.js +0 -2
- package/packages/core/build/macos-credential-island/lib.js +2 -6
- package/packages/core/build/plan/action-context.js +0 -7
- package/packages/core/build/plan/action.js +7 -11
- package/packages/core/build/plan/admission.js +6 -73
- package/packages/core/build/plan/configuration.js +1 -1
- package/packages/core/build/plan/environment.js +1 -1
- package/packages/core/build/plan/identity.js +1 -5
- package/packages/core/build/plan/resolve.js +7 -1
- package/packages/core/build/recovery/checkpoint.js +158 -0
- package/packages/core/build/recovery/transaction.js +51 -0
- package/packages/core/build/signing/authority-actions.js +2 -11
- package/packages/core/build/signing/control.js +0 -5
- package/packages/core/build/signing/controller-transaction.js +0 -1
- package/packages/core/build/signing/delegation.js +2 -4
- package/packages/core/build/signing/dispatch.js +10 -56
- package/packages/core/build/signing/intake.js +0 -4
- package/packages/core/build/signing/prepare.js +1 -1
- package/packages/core/build/signing/request.js +3 -8
- package/packages/core/build/source/checkout-action.js +6 -10
- package/packages/core/build/source/controller.js +1 -4
- package/packages/core/build/source/lifecycle.js +3 -13
- package/packages/core/build/stage-capsule/actions.js +3 -13
- package/packages/core/build/stage-capsule/campaign/resume.js +10 -5
- package/packages/core/build/stage-capsule/rehearsal/verify.js +3 -4
- package/packages/core/build/stage-capsule-resume-planner.js +0 -1
- package/packages/core/build/summary/aggregation.js +5 -5
- package/packages/core/build/summary/finalization.js +1 -1
- package/packages/core/build/verification/actions.js +3 -12
- package/packages/core/build/verification/runner.js +22 -20
- package/packages/core/consumer/floating-consumer-evidence.js +3 -21
- package/packages/core/consumer/floating-consumer-policy.js +2 -93
- package/packages/core/consumer/floating-consumer-release-passport.js +1 -34
- package/packages/core/consumer/policy-admission.js +1 -3
- package/packages/core/contracts/buildchain-contract.js +12 -146
- package/packages/core/contracts/workflow-yaml-contract.js +11 -1
- package/packages/core/dev-delivery/candidate/admission.js +3 -4
- package/packages/core/dev-delivery/candidate/coordinates.js +0 -8
- package/packages/core/dev-delivery/commands/dev-delivery-request.sh +5 -13
- package/packages/core/dev-delivery/commands/dev-delivery-source-proof-reuse.mjs +0 -3
- package/packages/core/dev-delivery/dev-delivery-contract-surface.js +4 -52
- package/packages/core/dev-delivery/dev-delivery-execution-transfer.js +2 -15
- package/packages/core/dev-delivery/native/action-context.js +4 -32
- package/packages/core/dev-delivery/native/provider-boundary.js +0 -2
- package/packages/core/dev-delivery/native/transactions.js +1 -2
- package/packages/core/dev-delivery/queue/reconciliation-action.js +6 -10
- package/packages/core/dev-delivery/source-proof/predicates.js +0 -6
- package/packages/core/dev-delivery/source-proof/reuse.js +0 -2
- package/packages/core/dev-delivery/source-proof/seal.js +0 -2
- package/packages/core/governance/alpha-candidate/action.js +1 -10
- package/packages/core/governance/audit/actions.js +1 -3
- package/packages/core/governance/audit/collection.js +1 -3
- package/packages/core/governance/audit/identity.js +3 -31
- package/packages/core/governance/audit/transactions.js +2 -4
- package/packages/core/governance/buildchain-publication-authority.js +0 -1
- package/packages/core/governance/commands/audit-github-governance.mjs +3 -2
- package/packages/core/governance/github-governance-authority.js +0 -5
- package/packages/core/governance/receipt-admission.js +0 -15
- package/packages/core/index.js +1 -1
- package/packages/core/observability/controller/identity.js +4 -5
- package/packages/core/observability/controller-evidence.js +5 -10
- package/packages/core/paper/commands/paper.mjs +6 -6
- package/packages/core/paper/operations/plans.js +2 -2
- package/packages/core/paper/operations/provisioning-validation.js +1 -1
- package/packages/core/paper/operations/scaffold-workflows.js +29 -12
- package/packages/core/paper/operations/scaffold.js +97 -69
- package/packages/core/paper/paper-agent-entry.js +0 -11
- package/packages/core/paper/paper-runtime-channels.js +21 -66
- package/packages/core/paper/paper-scaffold-content.js +1 -1
- package/packages/core/paper/paper.js +9 -5
- package/packages/core/paper/publication/candidate.js +0 -9
- package/packages/core/paper/publication-controller.js +2 -4
- package/packages/core/providers/github/artifact-attestation.js +1 -1
- package/packages/core/publication/authority/actions.js +9 -8
- package/packages/core/publication/authority/admission.js +0 -11
- package/packages/core/publication/authority/assembly.js +2 -7
- package/packages/core/publication/authority/control-plane.js +2 -2
- package/packages/core/publication/authority/governance.js +2 -9
- package/packages/core/publication/authority/request.js +7 -2
- package/packages/core/publication/authority/verification.js +3 -18
- package/packages/core/publication/binary/action.js +5 -7
- package/packages/core/publication/candidate/qualification-action.js +1 -6
- package/packages/core/publication/candidate/stage-capsules.js +1 -1
- package/packages/core/publication/npm/preview-action.js +9 -15
- package/packages/core/publication/oci/preview-actions.js +1 -10
- package/packages/core/publication/publication-artifact-candidate.js +2 -2
- package/packages/core/publication/publication-authority.js +2 -2
- package/packages/core/publication/publication-rehearsal-projection.js +3 -3
- package/packages/core/publication/settlement/actions.js +2 -11
- package/packages/core/release/binary/coordinates-action.js +0 -13
- package/packages/core/release/binary/coordinates.js +2 -19
- package/packages/core/release/commands/promotion-channel-router.mjs +12 -56
- package/packages/core/release/commands/resume-from-candidate-run.mjs +2 -3
- package/packages/core/release/dev-alpha-active-release-train.js +0 -5
- package/packages/core/release/line/action.js +2 -13
- package/packages/core/release/next-development/actions.js +2 -5
- package/packages/core/release/passport/consumer-validation.js +1 -28
- package/packages/core/release/promote-candidate/development-source.js +7 -8
- package/packages/core/release/promotion/actions.js +7 -38
- package/packages/core/release/promotion/admission.js +3 -50
- package/packages/core/release/promotion/candidate.js +2 -4
- package/packages/core/release/promotion/channel.js +13 -101
- package/packages/core/release/promotion/qualification-action.js +2 -13
- package/packages/core/release/promotion/routing.js +16 -81
- package/packages/core/release/promotion/selection.js +1 -9
- package/packages/core/release/promotion-request.js +1 -40
- package/packages/core/release/qualification/actions.js +0 -8
- package/packages/core/release/qualification/public-build.js +1 -1
- package/packages/core/release/recovery/candidate.js +15 -21
- package/packages/core/release/recovery/capsules.js +2 -10
- package/packages/core/release/recovery/lineage.js +305 -0
- package/packages/core/release/recovery/provenance.js +1 -2
- package/packages/core/release/recovery/publication.js +4 -14
- package/packages/core/release/recovery/readback.js +19 -32
- package/packages/core/release/recovery/runtime.js +4 -95
- package/packages/core/release/release-candidate-recovery.js +4 -9
- package/packages/core/release/release-candidate.js +2 -5
- package/packages/core/release/reseal/actions.js +3 -22
- package/packages/core/release/reseal/admission.js +0 -2
- package/packages/core/release/reseal/finalize-platform.js +0 -2
- package/packages/core/release/tail-reseal-github.js +1 -2
- package/packages/core/release/tail-reseal-receipt.js +0 -1
- package/packages/core/release/tail-reseal.js +2 -20
- package/packages/core/release/version-state.js +16 -13
- package/packages/core/runtime/buildchain-domain.wasm +0 -0
- package/packages/core/runtime/checkout-identity.js +0 -13
- package/packages/core/runtime/domain-wasm-artifact.js +2 -2
- package/packages/core/runtime/entry/actions.js +121 -0
- package/packages/core/runtime/entry/activation.js +86 -0
- package/packages/core/runtime/entry/github.js +55 -0
- package/packages/core/runtime/entry/recovery.js +37 -0
- package/packages/core/runtime/entry/selection.js +110 -0
- package/packages/core/web/controller.js +1 -1
- package/packages/core/web/publication-admission-action.js +1 -8
- package/packages/core/web/web-surface-publication-candidate.js +2 -5
- package/packages/core/workflow/admission/actions.js +6 -26
- package/packages/core/workflow/admission/recovery.js +3 -43
- package/packages/core/workflow/admission/transactions.js +8 -24
- package/packages/core/workflow/commands/buildchain-cli-help.mjs +1 -1
- package/packages/core/workflow/commands/universal-workflow-engine.mjs +2 -7
- package/packages/core/workflow/dogfood/actions.js +0 -17
- package/packages/core/workflow/engine/action.js +0 -5
- package/packages/core/workflow/engine/conformance.js +1 -1
- package/packages/core/workflow/engine/execution.js +2 -6
- package/packages/core/workflow/engine/identity.js +1 -6
- package/packages/core/workflow/engine/release-environment.js +11 -35
- package/packages/core/workflow/engine/release-promotion.js +2 -2
- package/packages/core/workflow/settlement/actions.js +0 -12
- package/packages/core/workflow/universal-self-dogfood.js +2 -16
- package/packages/core/workflow/universal-workflow-bootstrap.js +16 -241
- package/packages/core/workflow/workflow-taxonomy.mjs +2 -2
- package/scripts/check-dev-delivery-actions.mjs +17 -8
- package/scripts/check-floating-consumer-policy-contract.mjs +6 -6
- package/scripts/check-inventory.mjs +1 -10
- package/scripts/check-public-dogfood-contract.mjs +34 -21
- package/scripts/check-release-topology.mjs +2 -6
- package/scripts/check-runtime-entry.mjs +133 -0
- package/scripts/check-universal-workflow-bootstrap.mjs +45 -281
- package/scripts/check-workflows.sh +0 -7
- package/scripts/generate-bootstrap-admission.mjs +1 -1
- package/scripts/generate-channel-promotion-workflow.mjs +4 -4
- package/scripts/inventory/binary.mjs +4 -4
- package/scripts/inventory/promotion.mjs +5 -3
- package/scripts/runtime-source-boundaries.mjs +70 -0
- package/scripts/site-capability-metadata.mjs +2 -2
- package/scripts/workflow-action-graph.mjs +5 -18
- package/scripts/workflow-self-reference.mjs +20 -0
- package/templates/native-dev-delivery.yml +4 -4
- package/templates/universal-buildchain-bootstrap.yml +12 -2
- package/architecture/runtime-ref-resume-authority.json +0 -64
- package/architecture/universal-workflow-train-admission.json +0 -76
- package/contracts/v4-runtime-ref-resume-authority-v1.schema.json +0 -235
- package/docs/v4-runtime-ref-resume-authority.md +0 -69
- package/packages/core/consumer/channel-selection.js +0 -211
- package/packages/core/consumer/commands/buildchain-channel-router.mjs +0 -81
- package/packages/core/consumer/invocation-selector.js +0 -4
- package/packages/core/consumer/runtime-ref-resume-authority.js +0 -621
- package/packages/core/consumer/workflow-definition-authority.js +0 -64
- package/packages/core/contracts/runtime-contract-action.js +0 -48
- package/packages/core/release/commands/promotion-identity-resolver.mjs +0 -77
- package/packages/core/release/commands/verify-promotion-router-binding.sh +0 -36
- package/packages/core/release/promotion/identities.js +0 -56
- package/packages/core/release/runtime-override-authorization.js +0 -242
- package/packages/core/runtime/commands/runtime-ref-core.mjs +0 -171
- package/packages/core/runtime/provider-closure.js +0 -60
- package/packages/core/runtime/runtime-selection-action.js +0 -34
- package/packages/core/runtime/runtime-selection.js +0 -136
- package/packages/core/runtime/workflow-runtime.js +0 -11
- package/packages/core/workflow/admission/review.js +0 -188
- package/packages/core/workflow/commands/universal-workflow-backflow.mjs +0 -26
- package/packages/core/workflow/installation.js +0 -33
- package/packages/core/workflow/settlement/backflow.js +0 -187
- package/scripts/generate-bootstrap-recovery.mjs +0 -94
- package/templates/bootstrap-recovery/actions/build/source/admit/action.yml +0 -17
- package/templates/bootstrap-recovery/actions/build/source/admit/dist/index.js +0 -63
- package/templates/bootstrap-recovery/actions/runtime/dependencies/install/action.yml +0 -18
- package/templates/bootstrap-recovery/actions/runtime/dependencies/install/dist/index.js +0 -63
- package/templates/bootstrap-recovery/actions/runtime/environment/prepare/action.yml +0 -21
- package/templates/bootstrap-recovery/actions/workflow/admission/inspect/action.yml +0 -27
- package/templates/bootstrap-recovery/actions/workflow/admission/inspect/dist/index.js +0 -64
- package/templates/bootstrap-recovery/actions/workflow/admission/review/action.yml +0 -15
- package/templates/bootstrap-recovery/actions/workflow/admission/review/dist/index.js +0 -65
- package/templates/bootstrap-recovery/actions/workflow/recovery/admit/action.yml +0 -47
- package/templates/bootstrap-recovery/actions/workflow/recovery/execute/action.yml +0 -48
- package/templates/bootstrap-recovery/actions/workflow/recovery/settle/action.yml +0 -54
- package/templates/bootstrap-recovery/actions/workflow/settlement/seal/action.yml +0 -17
- package/templates/bootstrap-recovery/actions/workflow/settlement/seal/dist/index.js +0 -65
- package/templates/bootstrap-recovery/manifest.json +0 -68
- package/templates/bootstrap-recovery/package.json +0 -9
- package/templates/universal-buildchain-bootstrap-recovery.yml +0 -115
|
@@ -25,6 +25,7 @@ export async function runBuildStage({
|
|
|
25
25
|
stage,
|
|
26
26
|
sourceRoot,
|
|
27
27
|
environment,
|
|
28
|
+
recovery,
|
|
28
29
|
}) {
|
|
29
30
|
const file = path.join(
|
|
30
31
|
sourceRoot,
|
|
@@ -57,6 +58,7 @@ export async function runBuildStage({
|
|
|
57
58
|
),
|
|
58
59
|
});
|
|
59
60
|
try {
|
|
61
|
+
const restored = stage === "build" && recovery ? await recovery.restore() : null;
|
|
60
62
|
if (stage === "install" && plan.anchored_material) {
|
|
61
63
|
const evidence = await session.phase((env) =>
|
|
62
64
|
createAnchoredVersionMaterialEvidence({
|
|
@@ -78,22 +80,23 @@ export async function runBuildStage({
|
|
|
78
80
|
const usesCache =
|
|
79
81
|
cache.provider !== "none" &&
|
|
80
82
|
JSON.parse(cache.platforms_json).includes(platform.id);
|
|
81
|
-
if (stage === "build" && usesCache)
|
|
83
|
+
if (stage === "build" && usesCache && !restored)
|
|
82
84
|
await session.phase((env) =>
|
|
83
85
|
prepareCompilerCacheEvidence({ cwd: sourceRoot, env }),
|
|
84
86
|
);
|
|
85
|
-
await session.phase((env) =>
|
|
87
|
+
if (!restored) await session.phase((env) =>
|
|
86
88
|
runLifecycle({
|
|
87
89
|
...lifecycleOptions(plan, platform, stage, sourceRoot),
|
|
88
90
|
env,
|
|
89
91
|
}),
|
|
90
92
|
);
|
|
91
93
|
if (stage === "build") {
|
|
92
|
-
if (usesCache)
|
|
94
|
+
if (usesCache && !restored)
|
|
93
95
|
await session.phase((env) =>
|
|
94
96
|
verifyCompilerCacheActivity({ cwd: sourceRoot, env }),
|
|
95
97
|
);
|
|
96
98
|
await sealSigning(plan, platform, sourceRoot);
|
|
99
|
+
if (recovery) await recovery.retain();
|
|
97
100
|
}
|
|
98
101
|
if (
|
|
99
102
|
stage === "verify" &&
|
|
@@ -366,7 +366,6 @@ export function createRunBoundDmg({
|
|
|
366
366
|
function acceptedAssemblyBinding(binding, request, expectedExecution) {
|
|
367
367
|
return (
|
|
368
368
|
binding?.sourceSha === request.source.sha &&
|
|
369
|
-
binding?.runtimeSha === request.runtime.sha &&
|
|
370
369
|
binding?.requestDigest === request.digest &&
|
|
371
370
|
binding?.unsignedArchiveDigest === request.artifact.transport.digest &&
|
|
372
371
|
binding?.runId === expectedExecution.runId &&
|
|
@@ -427,7 +426,6 @@ export function acceptedMacosCredentialEvidence(
|
|
|
427
426
|
evidence.source?.repository === request.source.repository &&
|
|
428
427
|
evidence.source?.sha === request.source.sha &&
|
|
429
428
|
evidence.source?.treeSha === request.source.treeSha &&
|
|
430
|
-
evidence.buildchain?.runtimeSha === request.runtime.sha &&
|
|
431
429
|
evidence.input?.requestDigest === request.digest &&
|
|
432
430
|
evidence.app?.architecture === request.artifact.arch &&
|
|
433
431
|
evidence.execution?.runId === expectedExecution.runId &&
|
|
@@ -363,18 +363,14 @@ export function loadArtifactSigningInput(inputRoot, expected = {}) {
|
|
|
363
363
|
request.source.treeSha,
|
|
364
364
|
"artifact signing source tree SHA",
|
|
365
365
|
);
|
|
366
|
-
const runtimeSha =
|
|
367
|
-
request.runtime.sha,
|
|
368
|
-
"artifact signing runtime SHA",
|
|
369
|
-
);
|
|
366
|
+
const runtimeSha = request.runtime.sha;
|
|
370
367
|
if (expected.repository && repository !== expected.repository)
|
|
371
368
|
throw new Error("artifact signing request repository mismatch");
|
|
372
369
|
if (expected.sourceSha && sourceSha !== expected.sourceSha)
|
|
373
370
|
throw new Error("artifact signing request source SHA mismatch");
|
|
374
371
|
if (expected.sourceTreeSha && sourceTreeSha !== expected.sourceTreeSha)
|
|
375
372
|
throw new Error("artifact signing request source tree SHA mismatch");
|
|
376
|
-
|
|
377
|
-
throw new Error("artifact signing request runtime SHA mismatch");
|
|
373
|
+
|
|
378
374
|
const transport = request.artifact.transport;
|
|
379
375
|
if (transport?.format !== "ditto-zip") {
|
|
380
376
|
throw new Error("apple app signing request must use ditto-zip transport");
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { execFileSync } from "node:child_process";
|
|
3
2
|
import { installationRoot } from "../../runtime/installation-root.js";
|
|
4
3
|
import { bindBuildPlan } from "./identity.js";
|
|
5
4
|
export function readBuildActionContext(core, env) {
|
|
6
5
|
const workspace = path.resolve(env.GITHUB_WORKSPACE);
|
|
7
6
|
const runtimeRoot = installationRoot(import.meta.url);
|
|
8
|
-
const runtimeSha = execFileSync("git", ["rev-parse", "HEAD"], {
|
|
9
|
-
cwd: runtimeRoot,
|
|
10
|
-
encoding: "utf8",
|
|
11
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
12
|
-
}).trim();
|
|
13
7
|
const selected = core.getInput("platform");
|
|
14
8
|
const context = bindBuildPlan({
|
|
15
9
|
plan: JSON.parse(core.getInput("plan", { required: true })),
|
|
16
10
|
platformId: selected ? JSON.parse(selected).id : "",
|
|
17
11
|
workspace,
|
|
18
|
-
runtimeSha,
|
|
19
12
|
run: {
|
|
20
13
|
repository: env.GITHUB_REPOSITORY,
|
|
21
14
|
id: env.GITHUB_RUN_ID,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { execFileSync } from "node:child_process";
|
|
3
2
|
import { getOctokit } from "@actions/github";
|
|
4
3
|
import { installationRoot } from "../../runtime/installation-root.js";
|
|
5
4
|
import { reportBuildchainIssue } from "../../governance/issue-reporting.js";
|
|
@@ -10,12 +9,7 @@ export async function resolveBuildPlanAction(core, env) {
|
|
|
10
9
|
const workspace = path.resolve(env.GITHUB_WORKSPACE || process.cwd());
|
|
11
10
|
const runtimeRoot = installationRoot(import.meta.url);
|
|
12
11
|
const workflowSha = core.getInput("workflow-sha", { required: true });
|
|
13
|
-
|
|
14
|
-
execFileSync("git", ["-C", runtimeRoot, "rev-parse", "HEAD"], {
|
|
15
|
-
encoding: "utf8",
|
|
16
|
-
}).trim() !== workflowSha
|
|
17
|
-
)
|
|
18
|
-
throw new Error("Executing runtime differs from called workflow");
|
|
12
|
+
const selectedSource = JSON.parse(env.BUILDCHAIN_EXECUTION_SOURCE || "{}");
|
|
19
13
|
const token = core.getInput("token", { required: true });
|
|
20
14
|
const github = getOctokit(token);
|
|
21
15
|
const coordinates = (repository) => {
|
|
@@ -27,6 +21,7 @@ export async function resolveBuildPlanAction(core, env) {
|
|
|
27
21
|
workspace,
|
|
28
22
|
sourceRoot: path.join(workspace, "source"),
|
|
29
23
|
runtimeRoot,
|
|
24
|
+
runtime: JSON.parse(env.BUILDCHAIN_RUNTIME_SELECTION),
|
|
30
25
|
configPath: core.getInput("config-path"),
|
|
31
26
|
workflow: {
|
|
32
27
|
ref: core.getInput("workflow-ref", { required: true }),
|
|
@@ -35,11 +30,12 @@ export async function resolveBuildPlanAction(core, env) {
|
|
|
35
30
|
name: env.GITHUB_WORKFLOW,
|
|
36
31
|
runUrl: `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}`,
|
|
37
32
|
},
|
|
33
|
+
recovery: selectedSource.runId ? selectedSource : undefined,
|
|
38
34
|
source: {
|
|
39
|
-
sha: env.GITHUB_SHA,
|
|
40
|
-
ref: env.GITHUB_REF,
|
|
41
|
-
refName: env.GITHUB_REF_NAME,
|
|
42
|
-
baseRef: env.GITHUB_BASE_REF,
|
|
35
|
+
sha: selectedSource.sha || env.GITHUB_SHA,
|
|
36
|
+
ref: selectedSource.ref || env.GITHUB_REF,
|
|
37
|
+
refName: selectedSource.ref?.replace(/^refs\/(?:heads|tags)\//u, "") || env.GITHUB_REF_NAME,
|
|
38
|
+
baseRef: selectedSource.runId ? "" : env.GITHUB_BASE_REF,
|
|
43
39
|
},
|
|
44
40
|
event: {
|
|
45
41
|
name: env.GITHUB_EVENT_NAME,
|
|
@@ -2,21 +2,11 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { scanConsumerPolicy } from "../../consumer/policy-scan.js";
|
|
4
4
|
import { validatePackageManagerContract } from "../package-manager.js";
|
|
5
|
-
import {
|
|
6
|
-
inspectRuntimeContract,
|
|
7
|
-
assertRuntimeContractAccepted,
|
|
8
|
-
} from "../../contracts/runtime-contract-inspection.js";
|
|
9
5
|
|
|
10
|
-
export async function admitBuildSource(
|
|
11
|
-
{ plan, sourceRoot, runtimeRoot, workspace, workflow },
|
|
12
|
-
{ reportIssue, summarize, warn },
|
|
13
|
-
) {
|
|
6
|
+
export async function admitBuildSource({ plan, sourceRoot, runtimeRoot, workflow }) {
|
|
14
7
|
const policy = scanConsumerPolicy({
|
|
15
8
|
runtimeRoot,
|
|
16
|
-
output: path.join(
|
|
17
|
-
sourceRoot,
|
|
18
|
-
".buildchain/evidence/consumer-policy-receipt.json",
|
|
19
|
-
),
|
|
9
|
+
output: path.join(sourceRoot, ".buildchain/evidence/consumer-policy-receipt.json"),
|
|
20
10
|
root: sourceRoot,
|
|
21
11
|
invocationRoot: sourceRoot,
|
|
22
12
|
repository: plan.run.repository,
|
|
@@ -24,70 +14,13 @@ export async function admitBuildSource(
|
|
|
24
14
|
invokedWorkflow: plan.identity.visible_workflow,
|
|
25
15
|
invocationSourcePath: workflow.callerRef,
|
|
26
16
|
expectedInvocationChannel: plan.identity.channel,
|
|
27
|
-
resolvedWorkflowSha: plan.
|
|
17
|
+
resolvedWorkflowSha: plan.entry.sha,
|
|
28
18
|
resolvedRuntimeSha: plan.identity.sha,
|
|
29
19
|
stableLockPath: ".buildchain/contract-lock.json",
|
|
30
20
|
alphaLockPath: ".buildchain/alpha-contract-lock.json",
|
|
31
21
|
});
|
|
32
|
-
if (!policy.ok)
|
|
33
|
-
throw new Error("Build source rejected by floating consumer policy");
|
|
22
|
+
if (!policy.ok) throw new Error("Build source rejected by floating consumer policy");
|
|
34
23
|
validatePackageManagerContract({ cwd: sourceRoot, expectedManager: "" });
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
currentContractPath: path.join(
|
|
38
|
-
runtimeRoot,
|
|
39
|
-
"dist/site/buildchain-contract.json",
|
|
40
|
-
),
|
|
41
|
-
runtimeRoot,
|
|
42
|
-
runtimeRef: plan.identity.ref,
|
|
43
|
-
runtimeSha: plan.identity.sha,
|
|
44
|
-
runtimeClass: plan.identity.channel,
|
|
45
|
-
compatibilityPolicy: plan.build.contract.compatibility_policy,
|
|
46
|
-
workflowShellRef: plan.identity.ref,
|
|
47
|
-
expectedChannel: plan.identity.channel,
|
|
48
|
-
expectedMajor: plan.identity.major,
|
|
49
|
-
allowOpaqueRuntime: false,
|
|
50
|
-
issueMode: plan.build.contract.drift_issue_mode,
|
|
51
|
-
issueBodyPath: path.join(
|
|
52
|
-
workspace,
|
|
53
|
-
".buildchain/contract-drift/issue-body.md",
|
|
54
|
-
),
|
|
55
|
-
repository: plan.run.repository,
|
|
56
|
-
workflow: workflow.name,
|
|
57
|
-
runUrl: workflow.runUrl,
|
|
58
|
-
});
|
|
59
|
-
await summarize(lock.summary);
|
|
60
|
-
const admission = {
|
|
61
|
-
policy: policy.receipt,
|
|
62
|
-
policy_root: policy.receiptRoot,
|
|
63
|
-
contract_digest: lock.outputs["contract-digest"],
|
|
64
|
-
lock_status: lock.outputs["contract-lock-status"],
|
|
65
|
-
};
|
|
66
|
-
if (lock.shouldIssue) {
|
|
67
|
-
try {
|
|
68
|
-
await reportIssue({
|
|
69
|
-
targetRepository: plan.run.repository,
|
|
70
|
-
title: `[Buildchain contract] ${plan.run.repository} drift on ${plan.identity.ref}`,
|
|
71
|
-
summary: `Buildchain contract drift: ${admission.lock_status}`,
|
|
72
|
-
failureCode: `buildchain-contract-${admission.lock_status}`,
|
|
73
|
-
buildchainRef: plan.identity.ref,
|
|
74
|
-
buildchainVersion: admission.contract_digest,
|
|
75
|
-
consumerRepository: plan.run.repository,
|
|
76
|
-
consumerRef: plan.source.ref,
|
|
77
|
-
consumerSha: plan.source.sha,
|
|
78
|
-
workflow: workflow.name,
|
|
79
|
-
runId: plan.run.id,
|
|
80
|
-
body: fs.readFileSync(
|
|
81
|
-
lock.outputs["contract-lock-issue-body-file"],
|
|
82
|
-
"utf8",
|
|
83
|
-
),
|
|
84
|
-
labels: "buildchain-contract-drift",
|
|
85
|
-
commentCooldownHours: 24,
|
|
86
|
-
});
|
|
87
|
-
} catch {
|
|
88
|
-
warn("Contract drift report could not be submitted");
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
assertRuntimeContractAccepted(lock);
|
|
92
|
-
return admission;
|
|
24
|
+
const contract = JSON.parse(fs.readFileSync(path.join(runtimeRoot, "dist/site/buildchain-contract.json"), "utf8"));
|
|
25
|
+
return { policy: policy.receipt, policy_root: policy.receiptRoot, contract_digest: contract.contractDigest, lock_status: plan.runtime?.origin || "contract-lock" };
|
|
93
26
|
}
|
|
@@ -32,7 +32,7 @@ export function resolveBuildConfiguration({
|
|
|
32
32
|
),
|
|
33
33
|
),
|
|
34
34
|
}) {
|
|
35
|
-
for (const [label, value] of Object.entries({
|
|
35
|
+
for (const [label, value] of Object.entries({ sourceSha })) {
|
|
36
36
|
if (!/^[a-f0-9]{40}$/u.test(value || ""))
|
|
37
37
|
throw new Error(`${label} must be an exact SHA`);
|
|
38
38
|
}
|
|
@@ -7,7 +7,7 @@ export function commonEnv(plan, platform) {
|
|
|
7
7
|
BUILDCHAIN_SOURCE_REF: plan.source.ref,
|
|
8
8
|
BUILDCHAIN_RUNTIME_REPOSITORY: plan.identity.repository,
|
|
9
9
|
BUILDCHAIN_RUNTIME_SHA: plan.identity.sha,
|
|
10
|
-
BUILDCHAIN_RUNTIME_REF: plan.identity.ref,
|
|
10
|
+
BUILDCHAIN_RUNTIME_REF: plan.runtime?.ref || plan.identity.ref,
|
|
11
11
|
BUILDCHAIN_PLATFORM_ID: platform?.id || "",
|
|
12
12
|
BUILDCHAIN_PLATFORM_NAME: platform?.name || "",
|
|
13
13
|
BUILDCHAIN_ARTIFACT_NAME: plan.artifacts.name,
|
|
@@ -4,13 +4,12 @@ export function assertPlan(plan) {
|
|
|
4
4
|
if (plan.schema !== "buildchain.build-plan/v1" || root !== rootOf(body))
|
|
5
5
|
throw new Error("Build plan root mismatch");
|
|
6
6
|
for (const sha of [
|
|
7
|
-
plan.identity.sha,
|
|
8
7
|
plan.source.sha,
|
|
9
8
|
plan.source.tree_sha,
|
|
10
9
|
]) {
|
|
11
10
|
if (!/^[a-f0-9]{40}$/u.test(sha))
|
|
12
11
|
throw new Error(
|
|
13
|
-
"Build plan requires exact source
|
|
12
|
+
"Build plan requires exact source and tree identities",
|
|
14
13
|
);
|
|
15
14
|
}
|
|
16
15
|
if (
|
|
@@ -28,7 +27,6 @@ export function bindBuildPlan({
|
|
|
28
27
|
run,
|
|
29
28
|
platformId = "",
|
|
30
29
|
workspace,
|
|
31
|
-
runtimeSha,
|
|
32
30
|
}) {
|
|
33
31
|
assertPlan(plan);
|
|
34
32
|
if (
|
|
@@ -37,8 +35,6 @@ export function bindBuildPlan({
|
|
|
37
35
|
plan.run.attempt !== run.attempt
|
|
38
36
|
)
|
|
39
37
|
throw new Error("Build plan belongs to another run");
|
|
40
|
-
if (runtimeSha !== plan.identity.sha)
|
|
41
|
-
throw new Error("Executing runtime differs from the build plan");
|
|
42
38
|
const platform = platformId
|
|
43
39
|
? plan.platforms.find((item) => item.id === platformId)
|
|
44
40
|
: null;
|
|
@@ -39,10 +39,16 @@ export async function resolveBuildPlan(request, providers) {
|
|
|
39
39
|
execFileSync("git", ["-C", sourceRoot, ...args], {
|
|
40
40
|
encoding: "utf8",
|
|
41
41
|
}).trim();
|
|
42
|
+
plan.entry = { ref: workflow.ref, sha: workflow.sha };
|
|
43
|
+
if (request.runtime) {
|
|
44
|
+
plan.identity.sha = request.runtime.sha;
|
|
45
|
+
plan.runtime = request.runtime;
|
|
46
|
+
}
|
|
42
47
|
if (git("rev-parse", "HEAD") !== plan.source.sha)
|
|
43
48
|
throw new Error("Checked out source differs from invocation");
|
|
44
49
|
plan.source.tree_sha = git("rev-parse", "HEAD^{tree}");
|
|
45
50
|
plan.run = { ...run };
|
|
51
|
+
if (request.recovery) plan.recovery = request.recovery;
|
|
46
52
|
plan.admission = await admitBuildSource(
|
|
47
53
|
{ plan, sourceRoot, runtimeRoot, workspace, workflow },
|
|
48
54
|
providers,
|
|
@@ -64,7 +70,7 @@ export async function resolveBuildPlan(request, providers) {
|
|
|
64
70
|
inputBoundary: "strict",
|
|
65
71
|
source: { repository: run.repository, sha: plan.source.sha },
|
|
66
72
|
runtime: {
|
|
67
|
-
ref: plan.identity.ref,
|
|
73
|
+
ref: plan.runtime?.ref || plan.identity.ref,
|
|
68
74
|
sha: plan.identity.sha,
|
|
69
75
|
contractDigest: plan.admission.contract_digest,
|
|
70
76
|
},
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { rootOf, readJson, writeJson } from "../plan/values.js";
|
|
5
|
+
import { verifyManifest } from "../artifact/contracts.js";
|
|
6
|
+
|
|
7
|
+
export function buildRecoveryIdentity(plan, platform) {
|
|
8
|
+
return rootOf({
|
|
9
|
+
source: {
|
|
10
|
+
repository: plan.run.repository,
|
|
11
|
+
sha: plan.source.sha,
|
|
12
|
+
tree: plan.source.tree_sha,
|
|
13
|
+
},
|
|
14
|
+
configuration: plan.configuration_root,
|
|
15
|
+
platform,
|
|
16
|
+
project: plan.project,
|
|
17
|
+
lifecycle: plan.lifecycle,
|
|
18
|
+
tools: plan.tools,
|
|
19
|
+
container: plan.container,
|
|
20
|
+
environment: plan.environment,
|
|
21
|
+
artifacts: plan.artifacts,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const digestFile = (file) =>
|
|
25
|
+
createHash("sha256").update(fs.readFileSync(file)).digest("hex");
|
|
26
|
+
function supportFiles(plan) {
|
|
27
|
+
return plan.build?.diagnostics?.sample_process_tree
|
|
28
|
+
? [
|
|
29
|
+
".buildchain/diagnostics/process-summary.json",
|
|
30
|
+
".buildchain/diagnostics/process-samples.jsonl",
|
|
31
|
+
]
|
|
32
|
+
: [];
|
|
33
|
+
}
|
|
34
|
+
export const checkpointName = (platform) =>
|
|
35
|
+
`buildchain-build-checkpoint-${platform.id}`;
|
|
36
|
+
|
|
37
|
+
export function sealBuildCheckpoint({ plan, platform, sourceRoot }) {
|
|
38
|
+
const manifestPath = `.buildchain/artifacts/${platform.id}/manifest-build.json`;
|
|
39
|
+
const file = path.join(sourceRoot, manifestPath);
|
|
40
|
+
if (!fs.existsSync(file)) return null;
|
|
41
|
+
const manifest = verifyManifest(file, sourceRoot, plan, platform);
|
|
42
|
+
// A command without retained outputs cannot promise that another runner can
|
|
43
|
+
// continue it. Its ordinary execution remains valid and will run again.
|
|
44
|
+
if (!manifest.files.length) return null;
|
|
45
|
+
const retainedFiles = [
|
|
46
|
+
...manifest.files.map(({ path }) => path),
|
|
47
|
+
manifestPath,
|
|
48
|
+
...supportFiles(plan),
|
|
49
|
+
];
|
|
50
|
+
const body = {
|
|
51
|
+
schema: "buildchain.build-checkpoint/v1",
|
|
52
|
+
identity: buildRecoveryIdentity(plan, platform),
|
|
53
|
+
source: plan.source,
|
|
54
|
+
producer: plan.run,
|
|
55
|
+
runtime: plan.runtime,
|
|
56
|
+
platform: platform.id,
|
|
57
|
+
manifestPath,
|
|
58
|
+
files: retainedFiles.map((relative) => ({
|
|
59
|
+
path: relative,
|
|
60
|
+
mode: fs.statSync(path.join(sourceRoot, relative)).mode & 0o777,
|
|
61
|
+
sha256: digestFile(path.join(sourceRoot, relative)),
|
|
62
|
+
})),
|
|
63
|
+
};
|
|
64
|
+
const checkpoint = { ...body, root: rootOf(body) };
|
|
65
|
+
const checkpointPath = `.buildchain/recovery/${platform.id}/checkpoint.json`;
|
|
66
|
+
writeJson(path.join(sourceRoot, checkpointPath), checkpoint);
|
|
67
|
+
return { checkpoint, paths: [checkpointPath, ...retainedFiles] };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function restoreBuildCheckpoint({
|
|
71
|
+
plan,
|
|
72
|
+
platform,
|
|
73
|
+
sourceRoot,
|
|
74
|
+
retainedRoot,
|
|
75
|
+
}) {
|
|
76
|
+
const checkpoint = readJson(
|
|
77
|
+
path.join(
|
|
78
|
+
retainedRoot,
|
|
79
|
+
`.buildchain/recovery/${platform.id}/checkpoint.json`,
|
|
80
|
+
),
|
|
81
|
+
);
|
|
82
|
+
const { root, ...body } = checkpoint;
|
|
83
|
+
if (
|
|
84
|
+
checkpoint.schema !== "buildchain.build-checkpoint/v1" ||
|
|
85
|
+
rootOf(body) !== root ||
|
|
86
|
+
checkpoint.identity !== buildRecoveryIdentity(plan, platform) ||
|
|
87
|
+
checkpoint.platform !== platform.id ||
|
|
88
|
+
checkpoint.producer.repository !== plan.run.repository ||
|
|
89
|
+
checkpoint.producer.id !== plan.recovery.runId
|
|
90
|
+
)
|
|
91
|
+
throw new Error(
|
|
92
|
+
"Build checkpoint does not match the retained source, inputs or producer",
|
|
93
|
+
);
|
|
94
|
+
const expectedManifest = `.buildchain/artifacts/${platform.id}/manifest-build.json`;
|
|
95
|
+
if (checkpoint.manifestPath !== expectedManifest)
|
|
96
|
+
throw new Error("Unexpected build checkpoint manifest");
|
|
97
|
+
const manifest = verifyManifest(
|
|
98
|
+
path.join(retainedRoot, expectedManifest),
|
|
99
|
+
retainedRoot,
|
|
100
|
+
plan,
|
|
101
|
+
platform,
|
|
102
|
+
);
|
|
103
|
+
if (!manifest.files.length)
|
|
104
|
+
throw new Error("Build checkpoint has no retained outputs");
|
|
105
|
+
const files = [
|
|
106
|
+
...manifest.files.map(({ path }) => path),
|
|
107
|
+
expectedManifest,
|
|
108
|
+
...supportFiles(plan),
|
|
109
|
+
];
|
|
110
|
+
if (
|
|
111
|
+
!Array.isArray(checkpoint.files) ||
|
|
112
|
+
JSON.stringify(checkpoint.files.map((f) => f.path)) !==
|
|
113
|
+
JSON.stringify(files) ||
|
|
114
|
+
checkpoint.files.some(
|
|
115
|
+
(f) => !Number.isInteger(f.mode) || f.mode < 0 || f.mode > 0o777,
|
|
116
|
+
)
|
|
117
|
+
)
|
|
118
|
+
throw new Error("Build checkpoint file metadata is invalid");
|
|
119
|
+
for (const file of checkpoint.files)
|
|
120
|
+
if (file.sha256 !== digestFile(path.join(retainedRoot, file.path)))
|
|
121
|
+
throw new Error("Build checkpoint retained file digest mismatch");
|
|
122
|
+
// Validate every destination before changing the fresh source checkout.
|
|
123
|
+
for (const relative of files) {
|
|
124
|
+
if (relative.split("/").some((p) => [".git", ".github"].includes(p)))
|
|
125
|
+
throw new Error(
|
|
126
|
+
"Build checkpoint cannot replace repository control files",
|
|
127
|
+
);
|
|
128
|
+
const destination = path.resolve(sourceRoot, relative);
|
|
129
|
+
if (!destination.startsWith(path.resolve(sourceRoot) + path.sep))
|
|
130
|
+
throw new Error("Build checkpoint destination escapes source");
|
|
131
|
+
let current = destination;
|
|
132
|
+
while (current !== path.resolve(sourceRoot)) {
|
|
133
|
+
let stat;
|
|
134
|
+
try {
|
|
135
|
+
stat = fs.lstatSync(current);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
if (error.code !== "ENOENT") throw error;
|
|
138
|
+
}
|
|
139
|
+
if (stat?.isSymbolicLink())
|
|
140
|
+
throw new Error("Build checkpoint destination traverses a symlink");
|
|
141
|
+
current = path.dirname(current);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
for (const relative of files) {
|
|
145
|
+
const destination = path.resolve(sourceRoot, relative);
|
|
146
|
+
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
|
147
|
+
fs.copyFileSync(path.join(retainedRoot, relative), destination);
|
|
148
|
+
fs.chmodSync(
|
|
149
|
+
destination,
|
|
150
|
+
checkpoint.files.find((f) => f.path === relative).mode,
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
checkpointRoot: root,
|
|
155
|
+
producer: checkpoint.producer,
|
|
156
|
+
stage: "build",
|
|
157
|
+
};
|
|
158
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { createBuildArtifactStore } from "../artifact/store.js";
|
|
3
|
+
import {
|
|
4
|
+
checkpointName,
|
|
5
|
+
sealBuildCheckpoint,
|
|
6
|
+
restoreBuildCheckpoint,
|
|
7
|
+
} from "./checkpoint.js";
|
|
8
|
+
|
|
9
|
+
export function buildStageRecovery(
|
|
10
|
+
context,
|
|
11
|
+
token,
|
|
12
|
+
store = createBuildArtifactStore({ token }),
|
|
13
|
+
) {
|
|
14
|
+
const { plan, platform, sourceRoot, workspace } = context;
|
|
15
|
+
return {
|
|
16
|
+
async restore() {
|
|
17
|
+
if (!plan.recovery) return null;
|
|
18
|
+
const retainedRoot = path.join(
|
|
19
|
+
workspace,
|
|
20
|
+
`.buildchain/recovery-input/${platform.id}`,
|
|
21
|
+
);
|
|
22
|
+
const name = checkpointName(platform);
|
|
23
|
+
let ref;
|
|
24
|
+
try {
|
|
25
|
+
ref = await store.lookup(plan, name, { runId: plan.recovery.runId });
|
|
26
|
+
} catch (error) {
|
|
27
|
+
// Only a proven absent checkpoint permits rebuilding. Provider errors,
|
|
28
|
+
// duplicates and digest failures remain errors with the original signal.
|
|
29
|
+
if (error.code === "artifact-not-found") return null;
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
await store.download(ref, retainedRoot);
|
|
33
|
+
return restoreBuildCheckpoint({
|
|
34
|
+
plan,
|
|
35
|
+
platform,
|
|
36
|
+
sourceRoot,
|
|
37
|
+
retainedRoot,
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
async retain() {
|
|
41
|
+
const sealed = sealBuildCheckpoint({ plan, platform, sourceRoot });
|
|
42
|
+
if (!sealed) return null;
|
|
43
|
+
return store.upload(
|
|
44
|
+
plan,
|
|
45
|
+
checkpointName(platform),
|
|
46
|
+
sealed.paths,
|
|
47
|
+
sourceRoot,
|
|
48
|
+
);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { installationRoot } from "../../runtime/installation-root.js";
|
|
4
|
-
import { verifyCheckoutIdentity } from "../../runtime/checkout-identity.js";
|
|
5
4
|
import { inspectArtifactSigningRequests } from "./intake.js";
|
|
6
5
|
import { signDetachedArtifactRequests } from "./detached.js";
|
|
7
6
|
import { finalizeNativeArtifactSigningResult } from "./native-result.js";
|
|
@@ -14,15 +13,8 @@ const get = (core, name) => core.getInput(name, { required: true });
|
|
|
14
13
|
function context(core, env, needsItem = false) {
|
|
15
14
|
const workspace = path.resolve(env.GITHUB_WORKSPACE),
|
|
16
15
|
runtimeRoot = installationRoot(import.meta.url);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"Signing authority must execute its checked-out source implementation",
|
|
20
|
-
);
|
|
21
|
-
verifyCheckoutIdentity({
|
|
22
|
-
directory: runtimeRoot,
|
|
23
|
-
sha: env.GITHUB_SHA,
|
|
24
|
-
label: "Signing authority source",
|
|
25
|
-
});
|
|
16
|
+
|
|
17
|
+
|
|
26
18
|
const request = JSON.parse(get(core, "request-json")),
|
|
27
19
|
item = needsItem ? JSON.parse(get(core, "item-json")) : undefined;
|
|
28
20
|
if (item && item.slug !== safeSigningId(item.id))
|
|
@@ -52,7 +44,6 @@ export function admitSigningRequestsAction(core, env) {
|
|
|
52
44
|
const matrices = inspectArtifactSigningRequests({
|
|
53
45
|
inputRoot: requestRoot,
|
|
54
46
|
expectedRepository: request["source-repository"],
|
|
55
|
-
expectedRuntimeSha: request["expected-runtime-sha"],
|
|
56
47
|
expectedRequestRoot: request["expected-request-root"],
|
|
57
48
|
});
|
|
58
49
|
for (const [key, value] of Object.entries(matrices))
|
|
@@ -190,11 +190,6 @@ export function assertArtifactSigningControllerReceipt({
|
|
|
190
190
|
finalDelegation.authority.runId,
|
|
191
191
|
"authority run ID",
|
|
192
192
|
],
|
|
193
|
-
[
|
|
194
|
-
result.authority.runtimeSha,
|
|
195
|
-
finalDelegation.authority.runtimeSha,
|
|
196
|
-
"authority runtime SHA",
|
|
197
|
-
],
|
|
198
193
|
[
|
|
199
194
|
result.authority.resultArtifact,
|
|
200
195
|
finalDelegation.authority.resultArtifact,
|
|
@@ -42,7 +42,6 @@ export async function controlSigning(context) {
|
|
|
42
42
|
authority = (
|
|
43
43
|
await dispatch({
|
|
44
44
|
authorityRepository: request.authority.repository,
|
|
45
|
-
authorityRef: request.runtime.ref,
|
|
46
45
|
runtimeSha: request.runtime.sha,
|
|
47
46
|
sourceRepository: plan.run.repository,
|
|
48
47
|
sourceRunId: plan.run.id,
|
|
@@ -89,7 +89,7 @@ export function validateArtifactSigningDelegation(value) {
|
|
|
89
89
|
},
|
|
90
90
|
runtime: {
|
|
91
91
|
repository: repository(value.runtime?.repository, "runtime.repository"),
|
|
92
|
-
sha:
|
|
92
|
+
sha: value.runtime?.sha,
|
|
93
93
|
},
|
|
94
94
|
platform: {
|
|
95
95
|
id: required(value.platform?.id, "platform.id"),
|
|
@@ -106,7 +106,7 @@ export function validateArtifactSigningDelegation(value) {
|
|
|
106
106
|
authority: {
|
|
107
107
|
runtimeSha:
|
|
108
108
|
requestCount > 0
|
|
109
|
-
?
|
|
109
|
+
? value.authority?.runtimeSha
|
|
110
110
|
: optional(value.authority?.runtimeSha, "authority.runtimeSha"),
|
|
111
111
|
runId:
|
|
112
112
|
requestCount > 0
|
|
@@ -269,8 +269,6 @@ export function assertArtifactSigningDelegationContext(
|
|
|
269
269
|
[sourceRunId, value.source.runId, "source run ID"],
|
|
270
270
|
[sourceRunAttempt, String(value.source.runAttempt), "source run attempt"],
|
|
271
271
|
[sourceSha, value.source.sha, "source SHA"],
|
|
272
|
-
[runtimeRepository, value.runtime.repository, "runtime repository"],
|
|
273
|
-
[runtimeSha, value.runtime.sha, "runtime SHA"],
|
|
274
272
|
[platformId, value.platform.id, "platform ID"],
|
|
275
273
|
];
|
|
276
274
|
for (const [expected, actual, label] of expectations) {
|