@kungfu-tech/buildchain 4.0.2 → 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 +4 -4
- package/CONTRIBUTING.md +34 -0
- package/README.md +1 -1
- package/architecture/agent-change-map.md +154 -147
- package/architecture/{v4-architecture-constitution.md → architecture-constitution.md} +11 -11
- 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 +18 -0
- package/architecture/{v4-cross-platform-adopter-qualification.json → cross-platform-adopter-qualification.json} +3 -3
- package/architecture/{v4-delivery-authority-parity.json → delivery-authority-parity.json} +16 -16
- package/architecture/{v4-delivery-warrant-shadow-bootstrap-plan.json → delivery-warrant-shadow-bootstrap-plan.json} +3 -3
- package/architecture/{v4-delivery-warrant-shadow-bootstrap-plan.md → delivery-warrant-shadow-bootstrap-plan.md} +7 -7
- 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 +171 -169
- package/architecture/maintainability-debt.json +87 -82
- package/architecture/maintainability-policy.json +15 -15
- package/architecture/{v4-next-development-parity.json → next-development-parity.json} +8 -8
- package/architecture/{v4-partial-mutation-recovery-qualification.json → partial-mutation-recovery-qualification.json} +8 -8
- package/architecture/{v4-platform-stage-checkpoints.json → platform-stage-checkpoints.json} +2 -2
- package/architecture/{v4-provider-operation-journal-contract.json → provider-operation-journal-contract.json} +9 -9
- 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} +8 -8
- package/architecture/{v4-release-topology.json → release-topology.json} +112 -56
- 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/{v4-rust-wasm-production-authority.json → rust-wasm-production-authority.json} +11 -11
- package/architecture/{v4-stable-publication-fence.json → stable-publication-fence.json} +6 -6
- package/architecture/{v4-stage-capsule-contract.json → stage-capsule-contract.json} +1 -1
- package/architecture/{v4-stage-capsule-qualification.json → stage-capsule-qualification.json} +6 -6
- 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} +28 -28
- package/architecture/{v4-universal-workflow-bootstrap.json → universal-workflow-bootstrap.json} +9 -4
- package/architecture/{v4-universal-workflow-fault-campaign.json → universal-workflow-fault-campaign.json} +8 -8
- package/architecture/{v4-universal-workflow-train-admission.json → universal-workflow-train-admission.json} +8 -8
- package/architecture/workflow-taxonomy.json +11 -0
- package/bin/buildchain.mjs +3 -3
- package/bin/internal/adopter-delivery-cli.mjs +9 -9
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
- 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 +18 -18
- package/dist/site/buildchain-site.json +167 -71
- package/dist/site/capability-registry.json +5 -5
- package/dist/site/kfd-claims.json +226 -90
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +7 -7
- package/dist/site/node-api-registry.json +12929 -10491
- package/dist/site/page-registry.json +155 -59
- package/dist/site/public-surface-audit.json +65 -46
- package/dist/site/publication-authority-registry.json +27 -17
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-provenance.json +18 -9
- package/dist/site/site-manifest.json +11 -11
- package/dist/site/workflow-registry.json +86 -52
- package/docs/MAP.md +4 -3
- package/docs/next-development-transition.md +24 -1
- package/docs/node-api-reference.md +435 -175
- package/docs/oci-publication.md +173 -0
- package/docs/publish-transaction.md +36 -3
- package/docs/release-flow.md +1 -1
- package/docs/reusable-build-surface.md +1 -1
- package/docs/v4-adopter-delivery.md +2 -2
- 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 +8 -2
- 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 +6 -6
- package/docs/v4-stage-capsule.md +7 -7
- package/docs/v4-tail-reseal.md +1 -1
- package/docs/workflow-catalog.md +1 -0
- package/package.json +37 -26
- 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/buildchain-contract.js +5 -5
- package/packages/core/buildchain-domain.wasm +0 -0
- package/packages/core/buildchain-publication-authority.js +1 -0
- package/packages/core/{v4-canonical-contracts.js → canonical-contracts.js} +32 -31
- 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-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 +11 -11
- package/packages/core/dev-delivery-warrant.js +3 -3
- package/packages/core/domain-wasm-artifact.js +7 -0
- package/packages/core/{v4-domain-wasm.js → domain-wasm.js} +31 -31
- package/packages/core/{v4-floating-consumer-evidence.js → floating-consumer-evidence.js} +13 -13
- package/packages/core/{v4-floating-consumer-policy.js → floating-consumer-policy.js} +27 -29
- package/packages/core/{v4-floating-consumer-release-passport.js → floating-consumer-release-passport.js} +25 -25
- package/packages/core/index.js +4 -8
- package/packages/core/next-development-projection.js +24 -1
- 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-runtime-channels.js +2 -2
- package/packages/core/paper.js +3 -3
- 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/{v4-product-publication.js → product-publication.js} +11 -9
- package/packages/core/{v4-protected-publication-source.js → protected-publication-source.js} +3 -3
- package/packages/core/provider-operation-journal.js +62 -0
- package/packages/core/{v4-provider-readback-idempotency.js → provider-readback-idempotency.js} +33 -33
- 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/{v4-release-invocation.js → release-invocation.js} +15 -15
- package/packages/core/release-passport.js +36 -36
- package/packages/core/release-tail-product-capabilities.js +9 -0
- package/packages/core/release-tail-provider-plane.js +10 -10
- 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/{v4-universal-workflow-bootstrap.js → universal-workflow-bootstrap.js} +23 -23
- package/scripts/{v4-architecture.mjs → architecture.mjs} +6 -6
- package/scripts/binary-publication-evidence.mjs +1 -1
- 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-v4-domain-wasm.mjs → build-domain-wasm.mjs} +6 -18
- package/scripts/{v3-v4-capability-catalog.mjs → capability-parity-catalog.mjs} +19 -19
- package/scripts/check-action-bundles.mjs +2 -2
- package/scripts/{check-v3-v4-capability-inventory.mjs → check-capability-parity-inventory.mjs} +42 -42
- package/scripts/check-core-mechanism-inventory.mjs +4 -1
- package/scripts/{check-v4-floating-consumer-policy-contract.mjs → check-floating-consumer-policy-contract.mjs} +8 -8
- package/scripts/check-implementation-naming.mjs +135 -0
- package/scripts/check-inventory.mjs +6 -5
- package/scripts/check-maintainability.mjs +9 -2
- package/scripts/{check-v4-public-dogfood-contract.mjs → check-public-dogfood-contract.mjs} +15 -15
- package/scripts/{check-v4-release-topology.mjs → check-release-topology.mjs} +53 -31
- package/scripts/{check-v4-runtime-semantic-closure.mjs → check-runtime-semantic-closure.mjs} +19 -16
- package/scripts/{check-v4-universal-workflow-bootstrap.mjs → check-universal-workflow-bootstrap.mjs} +14 -14
- package/scripts/{v4-consumer-policy.mjs → consumer-policy.mjs} +15 -15
- package/scripts/{copy-v4-domain-wasm.mjs → copy-domain-wasm.mjs} +3 -3
- 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-warrant-options.mjs +1 -1
- package/scripts/dev-delivery-warrant-store.mjs +29 -10
- package/scripts/dev-delivery-warrant.mjs +4 -4
- package/scripts/dev-pr-delivery-warrant.mjs +1 -1
- package/scripts/generate-channel-build-workflow.mjs +2 -2
- package/scripts/generate-channel-promotion-workflow.mjs +14 -31
- package/scripts/generate-release-candidate-passport.mjs +23 -23
- package/scripts/generate-site-bundle.mjs +17 -17
- package/scripts/{generate-v4-universal-workflow-facades.mjs → generate-universal-workflow-facades.mjs} +61 -21
- 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/next-development-review.mjs +17 -11
- package/scripts/oci-compose-preview.mjs +261 -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} +16 -8
- 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/{v4-publication-settlement.mjs → publication-settlement.mjs} +8 -8
- package/scripts/{v4-release-candidate-adapter.mjs → release-candidate-adapter.mjs} +4 -4
- package/scripts/release-candidate-resolver.mjs +15 -26
- 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 +7 -7
- 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 +12 -3
- package/scripts/{v4-universal-workflow-backflow.mjs → universal-workflow-backflow.mjs} +10 -10
- package/scripts/{v4-universal-workflow-engine.mjs → universal-workflow-engine.mjs} +40 -38
- package/scripts/{v4-universal-workflow-self-dogfood.mjs → universal-workflow-self-dogfood.mjs} +12 -12
- package/scripts/verify-version-state-delta.mjs +4 -2
- package/scripts/{v4-warrant-shadow-plan.mjs → warrant-shadow-plan.mjs} +6 -6
- package/templates/universal-buildchain-bootstrap-recovery.yml +4 -4
- package/packages/core/buildchain-v4-domain.wasm +0 -0
- package/packages/core/v4-domain-wasm-artifact.js +0 -7
- package/packages/core/v4-partial-mutation-recovery-qualification.js +0 -18
- package/packages/core/v4-provider-operation-journal.js +0 -62
- package/packages/core/v4-release-activation-shadow.js +0 -32
- package/packages/core/v4-stable-publication-fence.js +0 -28
- /package/actions/{v4-release-candidate-promote → release-candidate-promote}/README.md +0 -0
- /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-floating-consumer-policy.json → floating-consumer-policy.json} +0 -0
- /package/architecture/{v4-publication-facade-patches.json → publication-facade-patches.json} +0 -0
- /package/architecture/{v4-release-invocation-fixtures.json → release-invocation-fixtures.json} +0 -0
|
@@ -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;
|
package/scripts/{v4-stage-capsule-resume-rehearsal.mjs → stage-capsule-resume-rehearsal.mjs}
RENAMED
|
@@ -4,8 +4,8 @@ import fs from "node:fs";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { domainCanonicalBytes } from "../packages/core/canonical-contracts.js";
|
|
8
|
+
import { planStageCapsuleResume } from "../packages/core/stage-capsule-resume-planner.js";
|
|
9
9
|
|
|
10
10
|
const repoRoot = path.resolve(
|
|
11
11
|
path.dirname(fileURLToPath(import.meta.url)),
|
|
@@ -22,7 +22,7 @@ if (!platform) throw new Error("--platform is required");
|
|
|
22
22
|
|
|
23
23
|
const declaration = JSON.parse(
|
|
24
24
|
fs.readFileSync(
|
|
25
|
-
path.join(repoRoot, "architecture/
|
|
25
|
+
path.join(repoRoot, "architecture/platform-stage-checkpoints.json"),
|
|
26
26
|
"utf8",
|
|
27
27
|
),
|
|
28
28
|
);
|
|
@@ -38,13 +38,13 @@ const fixture = JSON.parse(
|
|
|
38
38
|
"utf8",
|
|
39
39
|
),
|
|
40
40
|
);
|
|
41
|
-
const first =
|
|
42
|
-
const second =
|
|
41
|
+
const first = planStageCapsuleResume(fixture);
|
|
42
|
+
const second = planStageCapsuleResume(structuredClone(fixture));
|
|
43
43
|
if (first.planRoot !== second.planRoot)
|
|
44
44
|
throw new Error("resume planner is not deterministic");
|
|
45
45
|
|
|
46
46
|
process.stdout.write(
|
|
47
|
-
|
|
47
|
+
domainCanonicalBytes({
|
|
48
48
|
schema: "buildchain-v4-stage-capsule-resume-rehearsal/v1",
|
|
49
49
|
mode: "shadow-only",
|
|
50
50
|
platform,
|
|
@@ -6,8 +6,8 @@ import os from "node:os";
|
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { pathToFileURL } from "node:url";
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { domainContentRoot } from "../packages/core/canonical-contracts.js";
|
|
10
|
+
import { verifyTailResealPlatform } from "./tail-reseal.mjs";
|
|
11
11
|
|
|
12
12
|
function flag(args, name, fallback = "") {
|
|
13
13
|
const index = args.indexOf(`--${name}`);
|
|
@@ -56,12 +56,12 @@ function writeCandidate(root, request, content) {
|
|
|
56
56
|
fs.mkdirSync(path.dirname(manifestPath), { recursive: true });
|
|
57
57
|
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
58
58
|
return {
|
|
59
|
-
artifactRoot:
|
|
59
|
+
artifactRoot: domainContentRoot("tail-reseal-artifact-files", [file]),
|
|
60
60
|
manifestRoot: fileRoot(manifestPath),
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export function
|
|
64
|
+
export function rehearseTailResealMacos({
|
|
65
65
|
fixturePath = "contracts/fixtures/v4-tail-reseal-v1/valid.json",
|
|
66
66
|
outputPath = "",
|
|
67
67
|
} = {}) {
|
|
@@ -69,20 +69,20 @@ export function rehearseV4TailResealMacos({
|
|
|
69
69
|
fs.readFileSync(path.resolve(fixturePath), "utf8"),
|
|
70
70
|
);
|
|
71
71
|
const workRoot = fs.mkdtempSync(
|
|
72
|
-
path.join(os.tmpdir(), "buildchain-
|
|
72
|
+
path.join(os.tmpdir(), "buildchain-tail-macos-"),
|
|
73
73
|
);
|
|
74
74
|
try {
|
|
75
75
|
const retainedRoots = writeCandidate(workRoot, request, "unsigned");
|
|
76
76
|
const platform = request.platforms.find(({ id }) => id === "macos-arm64");
|
|
77
77
|
Object.assign(platform, retainedRoots);
|
|
78
|
-
const retained =
|
|
78
|
+
const retained = verifyTailResealPlatform({
|
|
79
79
|
request,
|
|
80
80
|
platformId: "macos-arm64",
|
|
81
81
|
artifactRoot: workRoot,
|
|
82
82
|
mode: "retained",
|
|
83
83
|
});
|
|
84
84
|
writeCandidate(workRoot, request, "signed-and-notarized");
|
|
85
|
-
const resealed =
|
|
85
|
+
const resealed = verifyTailResealPlatform({
|
|
86
86
|
request,
|
|
87
87
|
platformId: "macos-arm64",
|
|
88
88
|
artifactRoot: workRoot,
|
|
@@ -100,7 +100,7 @@ export function rehearseV4TailResealMacos({
|
|
|
100
100
|
};
|
|
101
101
|
const evidence = {
|
|
102
102
|
...payload,
|
|
103
|
-
evidenceRoot:
|
|
103
|
+
evidenceRoot: domainContentRoot("tail-reseal-admission", payload),
|
|
104
104
|
};
|
|
105
105
|
if (outputPath) {
|
|
106
106
|
const output = path.resolve(outputPath);
|
|
@@ -118,7 +118,7 @@ if (
|
|
|
118
118
|
import.meta.url === pathToFileURL(process.argv[1]).href
|
|
119
119
|
) {
|
|
120
120
|
try {
|
|
121
|
-
const evidence =
|
|
121
|
+
const evidence = rehearseTailResealMacos({
|
|
122
122
|
fixturePath: flag(
|
|
123
123
|
process.argv.slice(2),
|
|
124
124
|
"fixture",
|
|
@@ -6,13 +6,13 @@ import path from "node:path";
|
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} from "../packages/core/
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
9
|
+
TAIL_RESEAL_PLATFORMS,
|
|
10
|
+
normalizeTailResealRequest,
|
|
11
|
+
planTailReseal,
|
|
12
|
+
} from "../packages/core/tail-reseal.js";
|
|
13
|
+
import { createTailResealReceipt } from "../packages/core/tail-reseal-receipt.js";
|
|
14
|
+
import { validateTailResealGitHubEvidence } from "../packages/core/tail-reseal-github.js";
|
|
15
|
+
import { domainContentRoot } from "../packages/core/canonical-contracts.js";
|
|
16
16
|
|
|
17
17
|
function flag(args, name, fallback = "") {
|
|
18
18
|
const index = args.indexOf(`--${name}`);
|
|
@@ -137,7 +137,7 @@ async function admitFromGitHub(request) {
|
|
|
137
137
|
token,
|
|
138
138
|
),
|
|
139
139
|
]);
|
|
140
|
-
return
|
|
140
|
+
return validateTailResealGitHubEvidence({
|
|
141
141
|
request,
|
|
142
142
|
sourceCommit,
|
|
143
143
|
sourceRun,
|
|
@@ -183,14 +183,14 @@ function resolvePayload(root, relative, platformId) {
|
|
|
183
183
|
return absolute;
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
export function
|
|
186
|
+
export function verifyTailResealPlatform({
|
|
187
187
|
request,
|
|
188
188
|
platformId,
|
|
189
189
|
artifactRoot,
|
|
190
190
|
mode = "retained",
|
|
191
191
|
providerReadbackRoot = null,
|
|
192
192
|
} = {}) {
|
|
193
|
-
const normalized =
|
|
193
|
+
const normalized = normalizeTailResealRequest(request);
|
|
194
194
|
const platform = normalized.platforms.find(({ id }) => id === platformId);
|
|
195
195
|
if (!platform)
|
|
196
196
|
throw new Error(`tail reseal request does not bind platform ${platformId}`);
|
|
@@ -243,7 +243,7 @@ export function verifyV4TailResealPlatform({
|
|
|
243
243
|
);
|
|
244
244
|
if (files.length === 0)
|
|
245
245
|
throw new Error(`${platformId} manifest has no retained files`);
|
|
246
|
-
const observedArtifactRoot =
|
|
246
|
+
const observedArtifactRoot = domainContentRoot(
|
|
247
247
|
"tail-reseal-artifact-files",
|
|
248
248
|
files,
|
|
249
249
|
);
|
|
@@ -290,21 +290,21 @@ function collectReadbacks(directory) {
|
|
|
290
290
|
throw new Error(`duplicate tail reseal readback for ${value.platformId}`);
|
|
291
291
|
byPlatform.set(value.platformId, value);
|
|
292
292
|
}
|
|
293
|
-
return
|
|
293
|
+
return TAIL_RESEAL_PLATFORMS.map((platformId) => {
|
|
294
294
|
if (!byPlatform.has(platformId))
|
|
295
295
|
throw new Error(`missing tail reseal readback for ${platformId}`);
|
|
296
296
|
return byPlatform.get(platformId);
|
|
297
297
|
});
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
-
export function
|
|
300
|
+
export function runTailResealCli(args = process.argv.slice(2)) {
|
|
301
301
|
const [command, ...options] = args;
|
|
302
302
|
const requestPath = flag(options, "request");
|
|
303
303
|
if (command === "plan") {
|
|
304
|
-
const request =
|
|
304
|
+
const request = normalizeTailResealRequest(
|
|
305
305
|
readJson(required(requestPath, "--request"), "tail reseal request"),
|
|
306
306
|
);
|
|
307
|
-
const plan =
|
|
307
|
+
const plan = planTailReseal(request);
|
|
308
308
|
const output = writeJson(
|
|
309
309
|
flag(options, "output", ".buildchain/tail-reseal/plan.json"),
|
|
310
310
|
plan,
|
|
@@ -331,7 +331,7 @@ export function runV4TailResealCli(args = process.argv.slice(2)) {
|
|
|
331
331
|
return plan;
|
|
332
332
|
}
|
|
333
333
|
if (command === "admit") {
|
|
334
|
-
const request =
|
|
334
|
+
const request = normalizeTailResealRequest(
|
|
335
335
|
readJson(required(requestPath, "--request"), "tail reseal request"),
|
|
336
336
|
);
|
|
337
337
|
return admitFromGitHub(request).then((admission) => {
|
|
@@ -347,7 +347,7 @@ export function runV4TailResealCli(args = process.argv.slice(2)) {
|
|
|
347
347
|
});
|
|
348
348
|
}
|
|
349
349
|
if (command === "verify-platform") {
|
|
350
|
-
const readback =
|
|
350
|
+
const readback = verifyTailResealPlatform({
|
|
351
351
|
request: readJson(required(requestPath, "--request")),
|
|
352
352
|
platformId: required(flag(options, "platform"), "--platform"),
|
|
353
353
|
artifactRoot: flag(options, "artifact-root", process.cwd()),
|
|
@@ -371,7 +371,7 @@ export function runV4TailResealCli(args = process.argv.slice(2)) {
|
|
|
371
371
|
}
|
|
372
372
|
if (command === "seal") {
|
|
373
373
|
const request = readJson(required(requestPath, "--request"));
|
|
374
|
-
const receipt =
|
|
374
|
+
const receipt = createTailResealReceipt({
|
|
375
375
|
request,
|
|
376
376
|
plan: readJson(required(flag(options, "plan"), "--plan")),
|
|
377
377
|
readbacks: collectReadbacks(
|
|
@@ -409,7 +409,7 @@ if (
|
|
|
409
409
|
process.argv[1] &&
|
|
410
410
|
import.meta.url === pathToFileURL(process.argv[1]).href
|
|
411
411
|
) {
|
|
412
|
-
|
|
412
|
+
runTailResealCli().catch((error) => {
|
|
413
413
|
console.error(`tail-reseal: ${error.message}`);
|
|
414
414
|
process.exitCode = 1;
|
|
415
415
|
});
|
|
@@ -5,7 +5,7 @@ import { execFileSync } from "node:child_process";
|
|
|
5
5
|
function loadUniversalFacadeMigration(root) {
|
|
6
6
|
const contract = JSON.parse(
|
|
7
7
|
fs.readFileSync(
|
|
8
|
-
path.join(root, "architecture/
|
|
8
|
+
path.join(root, "architecture/universal-workflow-bootstrap.json"),
|
|
9
9
|
"utf8",
|
|
10
10
|
),
|
|
11
11
|
);
|
|
@@ -20,13 +20,17 @@ function loadUniversalFacadeMigration(root) {
|
|
|
20
20
|
"universal facade migration requires an exact facadeSourceRevision",
|
|
21
21
|
);
|
|
22
22
|
}
|
|
23
|
-
return {
|
|
23
|
+
return {
|
|
24
|
+
paths: new Set(paths),
|
|
25
|
+
sourceRevision,
|
|
26
|
+
postMigration: new Set(contract.migration?.postMigrationWorkflows || []),
|
|
27
|
+
};
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
function verifyUniversalFacadeMigration(root) {
|
|
27
31
|
execFileSync(
|
|
28
32
|
process.execPath,
|
|
29
|
-
["scripts/generate-
|
|
33
|
+
["scripts/generate-universal-workflow-facades.mjs", "--check"],
|
|
30
34
|
{ cwd: root, stdio: "pipe" },
|
|
31
35
|
);
|
|
32
36
|
}
|
|
@@ -40,6 +44,11 @@ function governUniversalFacadeWorkflowMetrics({
|
|
|
40
44
|
verifyUniversalFacadeMigration(root);
|
|
41
45
|
const frozen = workflowMetricsAtRevision(root, migration.sourceRevision);
|
|
42
46
|
const governed = { ...current, workflows: { ...current.workflows } };
|
|
47
|
+
for (const file of migration.postMigration) {
|
|
48
|
+
if (frozen[file] || !migration.paths.has(file))
|
|
49
|
+
throw new Error(`invalid post-migration workflow declaration ${file}`);
|
|
50
|
+
migration.paths.delete(file);
|
|
51
|
+
}
|
|
43
52
|
for (const file of migration.paths) {
|
|
44
53
|
if (!frozen[file])
|
|
45
54
|
throw new Error(`frozen universal facade source is missing ${file}`);
|
|
@@ -3,9 +3,9 @@ import crypto from "node:crypto";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "../packages/core/
|
|
6
|
+
validateUniversalWorkflowRequest,
|
|
7
|
+
universalWorkflowRequestRoot,
|
|
8
|
+
} from "../packages/core/universal-workflow-bootstrap.js";
|
|
9
9
|
const SHA = /^[0-9a-f]{40}$/u;
|
|
10
10
|
const ROOT = /^sha256:[0-9a-f]{64}$/u;
|
|
11
11
|
|
|
@@ -39,7 +39,7 @@ function validateTerminalReceipt(value, request) {
|
|
|
39
39
|
value.status !== "succeeded" ||
|
|
40
40
|
value.runtime?.repository !== request.candidate.repository ||
|
|
41
41
|
value.runtime?.sha !== request.candidate.expectedSha ||
|
|
42
|
-
value.requestRoot !==
|
|
42
|
+
value.requestRoot !== universalWorkflowRequestRoot(request) ||
|
|
43
43
|
!SHA.test(value.runtime?.sha || "") ||
|
|
44
44
|
!ROOT.test(value.receiptRoot || "")
|
|
45
45
|
)
|
|
@@ -49,11 +49,11 @@ function validateTerminalReceipt(value, request) {
|
|
|
49
49
|
return value;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export function
|
|
52
|
+
export function createUniversalBackflowPlan({
|
|
53
53
|
request: requestValue,
|
|
54
54
|
receipt,
|
|
55
55
|
}) {
|
|
56
|
-
const request =
|
|
56
|
+
const request = validateUniversalWorkflowRequest(requestValue);
|
|
57
57
|
if (request.mode !== "train") fail("only Train delivery can create backflow");
|
|
58
58
|
if (request.capability.id !== "release-candidate-promote")
|
|
59
59
|
fail("only a release-candidate-promote delivery can create backflow");
|
|
@@ -120,13 +120,13 @@ async function githubJson({ path, method = "GET", token, body, fetchImpl }) {
|
|
|
120
120
|
return value;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
export async function
|
|
123
|
+
export async function upsertUniversalBackflow({
|
|
124
124
|
request,
|
|
125
125
|
receipt,
|
|
126
126
|
token,
|
|
127
127
|
fetchImpl = globalThis.fetch,
|
|
128
128
|
}) {
|
|
129
|
-
const admitted =
|
|
129
|
+
const admitted = validateUniversalWorkflowRequest(request);
|
|
130
130
|
if (
|
|
131
131
|
admitted.mode !== "train" ||
|
|
132
132
|
admitted.capability.id !== "release-candidate-promote" ||
|
|
@@ -141,7 +141,7 @@ export async function upsertV4UniversalBackflow({
|
|
|
141
141
|
}
|
|
142
142
|
if (!token) fail("GH_TOKEN is required for protected backflow");
|
|
143
143
|
if (typeof fetchImpl !== "function") fail("fetch is required for backflow");
|
|
144
|
-
const plan =
|
|
144
|
+
const plan = createUniversalBackflowPlan({ request: admitted, receipt });
|
|
145
145
|
const encodedRepository = plan.repository;
|
|
146
146
|
const pull = await githubJson({
|
|
147
147
|
path: `/repos/${encodedRepository}/pulls/${plan.pullRequest}`,
|
|
@@ -198,7 +198,7 @@ async function main() {
|
|
|
198
198
|
process.env.BUILDCHAIN_UNIVERSAL_TERMINAL_RECEIPT_JSON ||
|
|
199
199
|
fail("terminal receipt is required"),
|
|
200
200
|
);
|
|
201
|
-
const result = await
|
|
201
|
+
const result = await upsertUniversalBackflow({
|
|
202
202
|
request,
|
|
203
203
|
receipt,
|
|
204
204
|
token: process.env.GH_TOKEN || process.env.GITHUB_TOKEN,
|