@kungfu-tech/buildchain 4.1.3-alpha.0 → 4.1.3-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/architecture/action-taxonomy.json +16 -0
- package/architecture/agent-change-map.md +245 -4
- package/architecture/ci-lane-change-budget.json +289 -0
- package/architecture/decisions/0005-minimal-consumer-contract.md +122 -0
- package/architecture/decisions/0006-business-attempt-journal.md +89 -0
- package/architecture/decisions/0007-hosted-pipeline-controller.md +106 -0
- package/architecture/decisions/0008-pipeline-product-publication.md +99 -0
- package/architecture/internal-capabilities.json +340 -4
- package/architecture/maintainability-debt.json +3 -1
- package/architecture/maintainability-policy.json +8 -8
- package/architecture/minimal-consumer-migration.json +7558 -0
- package/architecture/release-topology.json +248 -11
- package/architecture/universal-workflow-bootstrap.json +10 -0
- package/architecture/universal-workflow-capability-policy.json +6 -6
- package/architecture/workflow-taxonomy.json +55 -0
- package/contracts/release-discussion-v1.schema.json +3 -0
- package/dist/readers/business-attempt.cjs +805 -0
- package/dist/readers/release-discussion.cjs +4 -0
- package/dist/site/buildchain-contract.json +7 -5
- package/dist/site/buildchain-site.json +25 -15
- package/dist/site/capability-registry.json +3 -3
- package/dist/site/kfd-claims.json +311 -10
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +1 -1
- package/dist/site/node-api-registry.json +9 -9
- package/dist/site/page-registry.json +20 -10
- package/dist/site/public-surface-audit.json +201 -7
- package/dist/site/publication-authority-registry.json +121 -1
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/site-manifest.json +5 -5
- package/dist/site/workflow-registry.json +416 -7
- package/docs/node-api-reference.md +12 -12
- package/docs/release-discussions.md +44 -5
- package/docs/runtime-entry.md +45 -5
- package/docs/workflow-catalog.md +5 -0
- package/package.json +4 -3
- package/packages/core/consumer/contract/entries.js +85 -0
- package/packages/core/consumer/contract/examples.js +96 -0
- package/packages/core/consumer/contract/identity.js +65 -0
- package/packages/core/consumer/contract/inspection.js +45 -0
- package/packages/core/consumer/contract/plan.js +99 -0
- package/packages/core/consumer/contract/products.js +101 -0
- package/packages/core/consumer/contract/shape.js +46 -0
- package/packages/core/dev-delivery/candidate/admission.js +9 -5
- package/packages/core/dev-delivery/candidate/reservation.js +11 -0
- package/packages/core/dev-delivery/candidate/source-paths.js +12 -4
- package/packages/core/dev-delivery/native/actions.js +7 -1
- package/packages/core/dev-delivery/native/heartbeat-action.js +16 -0
- package/packages/core/dev-delivery/native/heartbeat.js +6 -4
- package/packages/core/dev-delivery/queue/landing-action.js +5 -0
- package/packages/core/governance/buildchain-publication-authority.js +5 -0
- package/packages/core/paper/operations/bootstrap.js +2 -0
- package/packages/core/paper/paper-npm-bootstrap.js +2 -2
- package/packages/core/providers/github/attempt-index.js +60 -0
- package/packages/core/providers/github/attempt-journal.js +154 -0
- package/packages/core/providers/github/discussions/materials.js +23 -7
- package/packages/core/providers/github/discussions/transport.js +16 -5
- package/packages/core/providers/github/pipeline-checkout.js +49 -0
- package/packages/core/providers/github/pipeline-events.js +52 -0
- package/packages/core/providers/github/pipeline-integration.js +95 -0
- package/packages/core/providers/github/pipeline-policy.js +213 -0
- package/packages/core/providers/github/pipeline-product-payload.js +50 -0
- package/packages/core/providers/github/pipeline-product-release.js +191 -0
- package/packages/core/providers/github/pipeline-publication-artifacts.js +153 -0
- package/packages/core/providers/github/pipeline-run-entry.js +86 -0
- package/packages/core/providers/github/pipeline-runs.js +132 -0
- package/packages/core/providers/github/pipeline-source.js +178 -0
- package/packages/core/providers/github/pipeline-version.js +201 -0
- package/packages/core/providers/github/pipeline-worker.js +108 -0
- package/packages/core/publication/candidate/registry-hydration.js +2 -2
- package/packages/core/publication/npm/pack-preview.js +2 -2
- package/packages/core/publication/npm/pack-result.js +31 -0
- package/packages/core/publication/npm/package.js +3 -6
- package/packages/core/publication/npm/pipeline-channel.js +87 -0
- package/packages/core/publication/npm/pipeline-provider.js +109 -0
- package/packages/core/publication/npm/registry.js +12 -9
- package/packages/core/publication/pipeline/actions.js +100 -0
- package/packages/core/publication/pipeline/apply.js +182 -0
- package/packages/core/publication/pipeline/build-segments.js +107 -0
- package/packages/core/publication/pipeline/capsules.js +89 -0
- package/packages/core/publication/pipeline/context.js +39 -0
- package/packages/core/publication/pipeline/development-anchor.js +91 -0
- package/packages/core/publication/pipeline/development-current.js +63 -0
- package/packages/core/publication/pipeline/development-pr.js +85 -0
- package/packages/core/publication/pipeline/development-proof.js +76 -0
- package/packages/core/publication/pipeline/development-transition.js +112 -0
- package/packages/core/publication/pipeline/distribution.js +124 -0
- package/packages/core/publication/pipeline/documents.js +156 -0
- package/packages/core/publication/pipeline/effects.js +162 -0
- package/packages/core/publication/pipeline/files.js +66 -0
- package/packages/core/publication/pipeline/imported-materials.js +32 -0
- package/packages/core/publication/pipeline/journal.js +110 -0
- package/packages/core/publication/pipeline/next-development.js +116 -0
- package/packages/core/publication/pipeline/pack.js +151 -0
- package/packages/core/publication/pipeline/package-policy.js +22 -0
- package/packages/core/publication/pipeline/plan.js +114 -0
- package/packages/core/publication/pipeline/prepare.js +151 -0
- package/packages/core/publication/pipeline/qualification.js +170 -0
- package/packages/core/publication/pipeline/qualify.js +104 -0
- package/packages/core/publication/pipeline/recovery-admission.js +122 -0
- package/packages/core/publication/pipeline/recovery-build-download.js +80 -0
- package/packages/core/publication/pipeline/recovery-build-plan.js +122 -0
- package/packages/core/publication/pipeline/recovery-build-readback.js +68 -0
- package/packages/core/publication/pipeline/recovery-capsules.js +54 -0
- package/packages/core/publication/pipeline/recovery-import.js +80 -0
- package/packages/core/publication/pipeline/recovery-inspection.js +218 -0
- package/packages/core/publication/pipeline/recovery-materials.js +104 -0
- package/packages/core/publication/pipeline/recovery-plan.js +46 -0
- package/packages/core/publication/pipeline/recovery-prepare.js +73 -0
- package/packages/core/publication/pipeline/recovery-qualification.js +128 -0
- package/packages/core/publication/pipeline/recovery-readback.js +56 -0
- package/packages/core/publication/pipeline/recovery-signing.js +58 -0
- package/packages/core/publication/pipeline/sealed-products.js +79 -0
- package/packages/core/publication/pipeline/settle.js +43 -0
- package/packages/core/publication/pipeline/signing.js +140 -0
- package/packages/core/publication/pipeline/source-plan.js +83 -0
- package/packages/core/publication/pipeline/version.js +81 -0
- package/packages/core/publication/publication-reproducibility.js +2 -2
- package/packages/core/release/discussion/binary.js +11 -0
- package/packages/core/release/discussion/checkpoints.js +45 -4
- package/packages/core/release/discussion/envelope.js +1 -0
- package/packages/core/release/discussion/evidence.js +51 -0
- package/packages/core/release/discussion/presentation.js +92 -0
- package/packages/core/release/discussion/publication.js +3 -1
- package/packages/core/release/discussion/qualification.js +1 -0
- package/packages/core/release/discussion/reader.js +9 -0
- package/packages/core/release/discussion/session.js +2 -0
- package/packages/core/release/discussion/store.js +28 -31
- package/packages/core/release/discussion/threads.js +83 -0
- package/packages/core/release/promote-candidate/product-provider-adapters.js +4 -3
- package/packages/core/release/promote-ref/internal/npm-existing-evidence.js +2 -1
- package/packages/core/release/promote-ref/internal/publish-command.js +16 -5
- package/packages/core/runtime/buildchain-domain.wasm +0 -0
- package/packages/core/runtime/domain-wasm-artifact.js +2 -2
- package/packages/core/runtime/entry/actions.js +27 -25
- package/packages/core/runtime/entry/attempt.js +25 -0
- package/packages/core/runtime/entry/selection.js +14 -0
- package/packages/core/runtime/entry/source.js +62 -0
- package/packages/core/workflow/attempt/identity.js +165 -0
- package/packages/core/workflow/attempt/journal.js +87 -0
- package/packages/core/workflow/attempt/materials.js +72 -0
- package/packages/core/workflow/attempt/reader-entry.js +12 -0
- package/packages/core/workflow/attempt/reader.js +149 -0
- package/packages/core/workflow/attempt/records.js +153 -0
- package/packages/core/workflow/attempt/store.js +75 -0
- package/packages/core/workflow/commands/pipeline-build.mjs +23 -0
- package/packages/core/workflow/pipeline/action-output.js +11 -0
- package/packages/core/workflow/pipeline/actions.js +62 -0
- package/packages/core/workflow/pipeline/build-control.js +140 -0
- package/packages/core/workflow/pipeline/build-evidence.js +92 -0
- package/packages/core/workflow/pipeline/build-qualification.js +145 -0
- package/packages/core/workflow/pipeline/build-result.js +69 -0
- package/packages/core/workflow/pipeline/build.js +95 -0
- package/packages/core/workflow/pipeline/cancellation.js +169 -0
- package/packages/core/workflow/pipeline/channel-control.js +127 -0
- package/packages/core/workflow/pipeline/controller.js +133 -0
- package/packages/core/workflow/pipeline/delivery-control.js +204 -0
- package/packages/core/workflow/pipeline/delivery-observation.js +118 -0
- package/packages/core/workflow/pipeline/delivery-request.js +198 -0
- package/packages/core/workflow/pipeline/events.js +84 -0
- package/packages/core/workflow/pipeline/fence.js +42 -0
- package/packages/core/workflow/pipeline/group-control.js +56 -0
- package/packages/core/workflow/pipeline/guard-build.js +37 -0
- package/packages/core/workflow/pipeline/guard.js +156 -0
- package/packages/core/workflow/pipeline/host.js +114 -0
- package/packages/core/workflow/pipeline/materials.js +58 -0
- package/packages/core/workflow/pipeline/notifications.js +36 -0
- package/packages/core/workflow/pipeline/parent-notification.js +27 -0
- package/packages/core/workflow/pipeline/platforms.js +21 -0
- package/packages/core/workflow/pipeline/progress.js +108 -0
- package/packages/core/workflow/pipeline/projection.js +20 -0
- package/packages/core/workflow/pipeline/reconcile.js +194 -0
- package/packages/core/workflow/pipeline/recovery-action.js +30 -0
- package/packages/core/workflow/pipeline/recovery-admission.js +122 -0
- package/packages/core/workflow/pipeline/recovery-build-control.js +95 -0
- package/packages/core/workflow/pipeline/recovery-build-evidence.js +71 -0
- package/packages/core/workflow/pipeline/recovery-build.js +121 -0
- package/packages/core/workflow/pipeline/recovery-controller.js +91 -0
- package/packages/core/workflow/pipeline/recovery-integration.js +66 -0
- package/packages/core/workflow/pipeline/recovery-merge-proof.js +90 -0
- package/packages/core/workflow/pipeline/recovery-ownership-settlement.js +150 -0
- package/packages/core/workflow/pipeline/recovery-ownership.js +91 -0
- package/packages/core/workflow/pipeline/recovery-plan.js +126 -0
- package/packages/core/workflow/pipeline/recovery-runtime.js +68 -0
- package/packages/core/workflow/pipeline/recovery-session.js +129 -0
- package/packages/core/workflow/pipeline/recovery-transition.js +135 -0
- package/packages/core/workflow/pipeline/recovery-unrecorded-build.js +74 -0
- package/packages/core/workflow/pipeline/runtime-source.js +111 -0
- package/packages/core/workflow/pipeline/selection.js +106 -0
- package/packages/core/workflow/pipeline/session.js +72 -0
- package/packages/core/workflow/pipeline/settlement.js +137 -0
- package/packages/core/workflow/pipeline/wake.js +38 -0
- package/packages/core/workflow/pipeline/web-status.js +108 -0
- package/scripts/build-release-discussion-reader.mjs +11 -7
- package/scripts/check-pipeline-publication-topology.mjs +36 -0
- package/scripts/check-release-topology.mjs +6 -1
- package/scripts/generate-minimal-consumer-contract.mjs +155 -0
- package/scripts/verify-golden-path.mjs +5 -1
- package/templates/minimal-consumer/binary/.buildchain/buildchain.toml +45 -0
- package/templates/minimal-consumer/binary/.github/workflows/buildchain-recover.yml +30 -0
- package/templates/minimal-consumer/binary/.github/workflows/buildchain.yml +28 -0
- package/templates/minimal-consumer/binary/package.json +6 -0
- package/templates/minimal-consumer/binary/src/build.mjs +5 -0
- package/templates/minimal-consumer/binary/src/hello.c +2 -0
- package/templates/minimal-consumer/binary/src/verify.mjs +3 -0
- package/templates/minimal-consumer/npm/.buildchain/buildchain.toml +46 -0
- package/templates/minimal-consumer/npm/.github/workflows/buildchain-recover.yml +30 -0
- package/templates/minimal-consumer/npm/.github/workflows/buildchain.yml +28 -0
- package/templates/minimal-consumer/npm/package.json +6 -0
- package/templates/minimal-consumer/npm/src/build.mjs +5 -0
- package/templates/minimal-consumer/npm/src/verify.mjs +3 -0
- package/templates/minimal-consumer/paper/.buildchain/buildchain.toml +45 -0
- package/templates/minimal-consumer/paper/.github/workflows/buildchain-recover.yml +30 -0
- package/templates/minimal-consumer/paper/.github/workflows/buildchain.yml +28 -0
- package/templates/minimal-consumer/paper/package.json +6 -0
- package/templates/minimal-consumer/paper/src/build.mjs +12 -0
- package/templates/minimal-consumer/paper/src/verify.mjs +3 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createIntegrationDeliveryProof,
|
|
3
|
+
verifyIntegrationDeliveryProof,
|
|
4
|
+
} from "../../dev-delivery/dev-delivery-warrant.js";
|
|
5
|
+
import { readBusinessAttempt } from "../attempt/reader.js";
|
|
6
|
+
import { pipelineCandidate } from "./reconcile.js";
|
|
7
|
+
|
|
8
|
+
async function qualifyWarrant(session, current, queue, materials) {
|
|
9
|
+
if (current.phases.warrant?.payload.state === "success") return;
|
|
10
|
+
if (queue.activeWarrant?.phase !== "qualified")
|
|
11
|
+
throw new Error("Merged pipeline has no qualified active Warrant");
|
|
12
|
+
const reference = await materials.retain(
|
|
13
|
+
`warrant/qualified-${queue.stateRoot.slice(7)}`,
|
|
14
|
+
queue,
|
|
15
|
+
"provider-readback",
|
|
16
|
+
);
|
|
17
|
+
await session.progress.progress({
|
|
18
|
+
attempt: current.identity.id,
|
|
19
|
+
phase: "warrant",
|
|
20
|
+
state: "success",
|
|
21
|
+
eventKey: `qualified:${queue.stateRoot}`,
|
|
22
|
+
materials: [reference],
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function integrationProof(session, fresh, host, materials) {
|
|
27
|
+
const { queue, current } = fresh;
|
|
28
|
+
const candidate = pipelineCandidate(queue, current);
|
|
29
|
+
if (!candidate)
|
|
30
|
+
throw new Error("Merged pipeline candidate authority is missing");
|
|
31
|
+
if (candidate.status === "merged") {
|
|
32
|
+
const reference =
|
|
33
|
+
current.materials[
|
|
34
|
+
`merge/proof-${candidate.terminal.evidenceRoot.slice(7)}`
|
|
35
|
+
];
|
|
36
|
+
if (!reference)
|
|
37
|
+
throw new Error(
|
|
38
|
+
"Merged Warrant has no retained pre-effect integration proof",
|
|
39
|
+
);
|
|
40
|
+
const proof = await materials.read(reference);
|
|
41
|
+
if (
|
|
42
|
+
!verifyIntegrationDeliveryProof(proof, {
|
|
43
|
+
sourceProofRoot: candidate.sourceProofRoot,
|
|
44
|
+
warrantCandidateId: candidate.candidateId,
|
|
45
|
+
}).ok
|
|
46
|
+
)
|
|
47
|
+
throw new Error("Retained integration proof is invalid");
|
|
48
|
+
return { candidate, proof, reference };
|
|
49
|
+
}
|
|
50
|
+
if (candidate.candidateId !== queue.activeWarrant?.candidateId)
|
|
51
|
+
throw new Error("Merged candidate is not the active Warrant");
|
|
52
|
+
await qualifyWarrant(session, current, queue, materials);
|
|
53
|
+
const readback = await host.integration.observe(current);
|
|
54
|
+
const proof = createIntegrationDeliveryProof({
|
|
55
|
+
repository: host.repository,
|
|
56
|
+
protectedBase: session.intent.source.targetBranch,
|
|
57
|
+
sourceProofRoot: candidate.sourceProofRoot,
|
|
58
|
+
warrant: queue.activeWarrant,
|
|
59
|
+
currentBase: readback.mergeCommit,
|
|
60
|
+
replayTree: readback.mergeTree,
|
|
61
|
+
mergeGroupHead: readback.mergeCommit,
|
|
62
|
+
mergeGroupTree: readback.mergeTree,
|
|
63
|
+
requiredContextRoots: [readback.build.root, readback.root],
|
|
64
|
+
verifiedAt: new Date().toISOString(),
|
|
65
|
+
});
|
|
66
|
+
const reference = await materials.retain(
|
|
67
|
+
`merge/proof-${proof.proofRoot.slice(7)}`,
|
|
68
|
+
proof,
|
|
69
|
+
);
|
|
70
|
+
const provider = await materials.retain(
|
|
71
|
+
`merge/provider-${readback.root.slice(7)}`,
|
|
72
|
+
readback,
|
|
73
|
+
"provider-readback",
|
|
74
|
+
);
|
|
75
|
+
await session.progress.progress({
|
|
76
|
+
attempt: current.identity.id,
|
|
77
|
+
phase: "merge",
|
|
78
|
+
state: "waiting",
|
|
79
|
+
eventKey: `merge-request:${proof.proofRoot}`,
|
|
80
|
+
materials: [reference, provider],
|
|
81
|
+
});
|
|
82
|
+
return { candidate, proof, reference };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function settlePipeline(session, fresh, delivery, host) {
|
|
86
|
+
const materials = host.materialStore(session);
|
|
87
|
+
const { candidate, proof, reference } = await integrationProof(
|
|
88
|
+
session,
|
|
89
|
+
fresh,
|
|
90
|
+
host,
|
|
91
|
+
materials,
|
|
92
|
+
);
|
|
93
|
+
const warrant = fresh.queue.activeWarrant;
|
|
94
|
+
const result = await delivery.service.settle({
|
|
95
|
+
expectedOldStateRoot: fresh.queue.stateRoot,
|
|
96
|
+
pullRequestNumber: candidate.pullRequestNumber,
|
|
97
|
+
expectedSourceHead: candidate.sourceHead,
|
|
98
|
+
outcome: "merged",
|
|
99
|
+
reason: "exact-protected-pipeline-integration",
|
|
100
|
+
evidenceRoot: proof.proofRoot,
|
|
101
|
+
execute: true,
|
|
102
|
+
...(warrant?.candidateId === candidate.candidateId
|
|
103
|
+
? {
|
|
104
|
+
fencingToken: warrant.fencingToken,
|
|
105
|
+
leaseGeneration: warrant.generation,
|
|
106
|
+
}
|
|
107
|
+
: {}),
|
|
108
|
+
});
|
|
109
|
+
if (result.observation.activeWarrant?.candidateId === candidate.candidateId)
|
|
110
|
+
throw new Error("Merged settlement retained its active Warrant");
|
|
111
|
+
const receipt = await materials.retain(
|
|
112
|
+
`merge/settlement-${result.receiptRoot.slice(7)}`,
|
|
113
|
+
result,
|
|
114
|
+
);
|
|
115
|
+
await session.progress.progress({
|
|
116
|
+
attempt: fresh.attempt,
|
|
117
|
+
phase: "merge",
|
|
118
|
+
state: "success",
|
|
119
|
+
eventKey: `merged:${result.receiptRoot}`,
|
|
120
|
+
materials: [reference, receipt],
|
|
121
|
+
});
|
|
122
|
+
await host.notifyTerminal?.(session);
|
|
123
|
+
const successor = result.receipt.successorWake;
|
|
124
|
+
if (successor) {
|
|
125
|
+
const next = await host.provider.lookup(
|
|
126
|
+
host.repository,
|
|
127
|
+
successor.pullRequestNumber,
|
|
128
|
+
session.intent.source.targetBranch,
|
|
129
|
+
);
|
|
130
|
+
if (next) await host.wake(readBusinessAttempt(next.snapshot).attempt);
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
operation: "wait",
|
|
134
|
+
reason: "protected-delivery-settled",
|
|
135
|
+
attempt: fresh.attempt,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { githubJsonClient } from "../../providers/github/json-client.js";
|
|
2
|
+
import { githubAttemptJournal } from "../../providers/github/attempt-journal.js";
|
|
3
|
+
import { readBusinessAttempt } from "../attempt/reader.js";
|
|
4
|
+
import { pipelineCandidateRoot } from "./reconcile.js";
|
|
5
|
+
|
|
6
|
+
export async function wakePipelineCandidate(candidate, connection, ports = {}) {
|
|
7
|
+
const repository = connection.repository;
|
|
8
|
+
const request =
|
|
9
|
+
ports.request ||
|
|
10
|
+
githubJsonClient({
|
|
11
|
+
token: connection.token,
|
|
12
|
+
userAgent: "buildchain-pipeline-wake",
|
|
13
|
+
});
|
|
14
|
+
const provider = ports.provider || githubAttemptJournal(request);
|
|
15
|
+
const branch = candidate.protectedBase || connection.branch;
|
|
16
|
+
const loaded = await provider.lookup(
|
|
17
|
+
repository,
|
|
18
|
+
candidate.pullRequestNumber,
|
|
19
|
+
branch,
|
|
20
|
+
);
|
|
21
|
+
if (!loaded)
|
|
22
|
+
throw new Error("Warrant handoff has no admitted business intent");
|
|
23
|
+
const observed = readBusinessAttempt(loaded.snapshot);
|
|
24
|
+
const current = { ...observed.history.at(-1), intent: observed.intent };
|
|
25
|
+
if (
|
|
26
|
+
candidate.sourceHead !== current.generation.source.commit ||
|
|
27
|
+
candidate.sourceRoot !== pipelineCandidateRoot(current)
|
|
28
|
+
)
|
|
29
|
+
throw new Error("Warrant handoff changed its admitted business attempt");
|
|
30
|
+
await request(`/repos/${repository}/dispatches`, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
body: {
|
|
33
|
+
event_type: "buildchain-attempt-wake",
|
|
34
|
+
client_payload: { attempt: observed.attempt },
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
return observed.attempt;
|
|
38
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const labels = {
|
|
2
|
+
admission: "Source admission",
|
|
3
|
+
build: "Product verification",
|
|
4
|
+
review: "Protected review",
|
|
5
|
+
warrant: "Delivery qualification",
|
|
6
|
+
merge: "Protected integration",
|
|
7
|
+
publish: "Product publication",
|
|
8
|
+
distribution: "Distribution",
|
|
9
|
+
"next-development": "Next development version",
|
|
10
|
+
};
|
|
11
|
+
const safe = (value) =>
|
|
12
|
+
String(value || "")
|
|
13
|
+
.replace(/[\r\n|]/gu, " ")
|
|
14
|
+
.replaceAll("&", "&")
|
|
15
|
+
.replaceAll("<", "<")
|
|
16
|
+
.replaceAll(">", ">")
|
|
17
|
+
.replace(/[\\`*_[\]()]/gu, (character) => `\\${character}`)
|
|
18
|
+
.slice(0, 1000);
|
|
19
|
+
|
|
20
|
+
export function pipelineWebStatus(observed, discussionUrl = "") {
|
|
21
|
+
const { intent, attempt } = observed;
|
|
22
|
+
const repositoryUrl = `https://github.com/${intent.repository}`;
|
|
23
|
+
const current = observed.history.at(-1);
|
|
24
|
+
if (!current) throw new Error("Pipeline status requires an admitted attempt");
|
|
25
|
+
const table = [
|
|
26
|
+
"| Step | State |",
|
|
27
|
+
"| --- | --- |",
|
|
28
|
+
...intent.expectedNodes.map(
|
|
29
|
+
(phase) =>
|
|
30
|
+
`| ${labels[phase]} | ${safe(observed.phases[phase]?.payload.state || "pending")} |`,
|
|
31
|
+
),
|
|
32
|
+
].join("\n");
|
|
33
|
+
const lines = [
|
|
34
|
+
`## Buildchain · PR #${intent.source.pullRequest}`,
|
|
35
|
+
`Status: **${safe(observed.status)}**. ${safe(observed.reason)}`,
|
|
36
|
+
`Attempt: \`${attempt}\``,
|
|
37
|
+
`[Pull request](${repositoryUrl}/pull/${intent.source.pullRequest}) · ` +
|
|
38
|
+
`[Source ${current.generation.source.commit.slice(0, 7)}](${repositoryUrl}/commit/${current.generation.source.commit})`,
|
|
39
|
+
table,
|
|
40
|
+
];
|
|
41
|
+
const publisher = [...observed.history]
|
|
42
|
+
.reverse()
|
|
43
|
+
.find(
|
|
44
|
+
(item) =>
|
|
45
|
+
item.generation.id === current.generation.id &&
|
|
46
|
+
item.phases.publish?.payload.state === "success",
|
|
47
|
+
);
|
|
48
|
+
const published = Boolean(publisher);
|
|
49
|
+
if (published && observed.missing.length)
|
|
50
|
+
lines.push(
|
|
51
|
+
`Publication succeeded and its immutable results remain preserved. The whole attempt is incomplete: ${observed.missing.map((phase) => labels[phase]).join(", ")}.`,
|
|
52
|
+
);
|
|
53
|
+
if (publisher && publisher.identity.id !== current.identity.id)
|
|
54
|
+
lines.push(
|
|
55
|
+
`Publication succeeded in predecessor \`${publisher.identity.id}\`. Current qualification and remaining steps are shown separately above.`,
|
|
56
|
+
);
|
|
57
|
+
if (current.identity.predecessor)
|
|
58
|
+
lines.push(
|
|
59
|
+
`Recovered from \`${current.identity.predecessor}\`; its original evidence remains in history.`,
|
|
60
|
+
);
|
|
61
|
+
if (observed.status !== "complete")
|
|
62
|
+
lines.push(
|
|
63
|
+
`[Recover this attempt](${repositoryUrl}/actions/workflows/buildchain-recover.yml): choose Run workflow and enter the exact attempt above. Select a repaired runtime only when needed.`,
|
|
64
|
+
);
|
|
65
|
+
lines.push(
|
|
66
|
+
"Execution links provide the provider's ordinary cancellation control. Cancellation stops remaining work; it does not undo completed publication.",
|
|
67
|
+
);
|
|
68
|
+
const runs = [
|
|
69
|
+
...new Map(
|
|
70
|
+
current.runs.map((run) => [`${run.runId}:${run.runAttempt}`, run]),
|
|
71
|
+
).values(),
|
|
72
|
+
];
|
|
73
|
+
for (const run of runs.slice(-10))
|
|
74
|
+
lines.push(
|
|
75
|
+
`[Execution ${run.runId}, attempt ${run.runAttempt}](${repositoryUrl}/actions/runs/${run.runId}/attempts/${run.runAttempt})`,
|
|
76
|
+
);
|
|
77
|
+
if (discussionUrl) {
|
|
78
|
+
const url = new URL(discussionUrl);
|
|
79
|
+
if (
|
|
80
|
+
url.origin !== "https://github.com" ||
|
|
81
|
+
!url.pathname.startsWith(`/${intent.repository}/discussions/`) ||
|
|
82
|
+
!/\/discussions\/[1-9][0-9]*$/u.test(url.pathname) ||
|
|
83
|
+
url.search ||
|
|
84
|
+
url.hash ||
|
|
85
|
+
url.username ||
|
|
86
|
+
url.password
|
|
87
|
+
)
|
|
88
|
+
throw new Error(
|
|
89
|
+
"Pipeline evidence link belongs to another provider or repository",
|
|
90
|
+
);
|
|
91
|
+
lines.push(`[Retained evidence](${discussionUrl})`);
|
|
92
|
+
}
|
|
93
|
+
return `${lines.join("\n\n")}\n`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function projectPipelineStatus(session, { project, core }) {
|
|
97
|
+
let result;
|
|
98
|
+
try {
|
|
99
|
+
result = await project(session);
|
|
100
|
+
} catch {
|
|
101
|
+
core.warning(
|
|
102
|
+
"Discussion projection unavailable; canonical attempt evidence remains retained.",
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
const observed = await session.journal.read();
|
|
106
|
+
await core.summary.addRaw(pipelineWebStatus(observed, result?.url)).write();
|
|
107
|
+
return result || { url: "", journalHead: observed.head };
|
|
108
|
+
}
|
|
@@ -10,25 +10,29 @@ try {
|
|
|
10
10
|
await build({
|
|
11
11
|
entry: {
|
|
12
12
|
"release-discussion": "packages/core/release/discussion/reader-entry.js",
|
|
13
|
+
"business-attempt": "packages/core/workflow/attempt/reader-entry.js",
|
|
13
14
|
},
|
|
14
15
|
outDir: output,
|
|
15
16
|
format: ["cjs"],
|
|
16
17
|
target: "node24",
|
|
17
18
|
platform: "node",
|
|
18
19
|
splitting: false,
|
|
20
|
+
noExternal: ["smol-toml"],
|
|
19
21
|
sourcemap: false,
|
|
20
22
|
minify: false,
|
|
21
23
|
clean: false,
|
|
22
24
|
outExtension: () => ({ js: ".cjs" }),
|
|
23
25
|
silent: true,
|
|
24
26
|
});
|
|
25
|
-
if (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
if (check)
|
|
28
|
+
for (const name of ["release-discussion", "business-attempt"]) {
|
|
29
|
+
if (
|
|
30
|
+
!fs
|
|
31
|
+
.readFileSync(path.join(output, `${name}.cjs`))
|
|
32
|
+
.equals(fs.readFileSync(`dist/readers/${name}.cjs`))
|
|
33
|
+
)
|
|
34
|
+
throw new Error(`Historical ${name} reader bundle is stale`);
|
|
35
|
+
}
|
|
32
36
|
} finally {
|
|
33
37
|
if (check) fs.rmSync(output, { recursive: true, force: true });
|
|
34
38
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { inspectWorkflowJob } from "./workflow-action-graph.mjs";
|
|
3
|
+
|
|
4
|
+
export function assertPipelinePublicationTopology(
|
|
5
|
+
ledger,
|
|
6
|
+
discoverReleaseTopology,
|
|
7
|
+
root,
|
|
8
|
+
) {
|
|
9
|
+
const pipeline = ledger.pipelinePublicationScope;
|
|
10
|
+
assert.deepEqual(pipeline.workflowPaths, [
|
|
11
|
+
".github/workflows/.release-pipeline-products.yml",
|
|
12
|
+
".github/workflows/public-ops-pipeline.yml",
|
|
13
|
+
".github/workflows/public-ops-recover.yml",
|
|
14
|
+
".github/workflows/.ops-pipeline-execute.yml",
|
|
15
|
+
]);
|
|
16
|
+
const pipelineTopology = discoverReleaseTopology(
|
|
17
|
+
pipeline.workflowPaths,
|
|
18
|
+
pipeline.workflowPaths,
|
|
19
|
+
);
|
|
20
|
+
assert.deepEqual(pipeline.observedTopology, pipelineTopology);
|
|
21
|
+
for (const [name, ceiling] of Object.entries(pipeline.maximumMetrics))
|
|
22
|
+
assert.ok(
|
|
23
|
+
pipelineTopology.metrics[name] <= ceiling,
|
|
24
|
+
`pipeline publication exceeds ${name}`,
|
|
25
|
+
);
|
|
26
|
+
for (const [job, module] of [
|
|
27
|
+
["qualify", "packages/core/publication/pipeline/qualify.js"],
|
|
28
|
+
["apply", "packages/core/publication/pipeline/apply.js"],
|
|
29
|
+
["settle", "packages/core/publication/pipeline/settle.js"],
|
|
30
|
+
])
|
|
31
|
+
assert.ok(
|
|
32
|
+
inspectWorkflowJob(pipeline.workflowPaths[0], job, root).modules.has(
|
|
33
|
+
module,
|
|
34
|
+
),
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import assert from "node:assert/strict";
|
|
4
|
+
import { assertPipelinePublicationTopology } from "./check-pipeline-publication-topology.mjs";
|
|
4
5
|
import { inspectWorkflowJob, readWorkflow } from "./workflow-action-graph.mjs";
|
|
5
6
|
import crypto from "node:crypto";
|
|
6
7
|
import fs from "node:fs";
|
|
@@ -28,6 +29,7 @@ const PRIVILEGED_ENTRYPOINTS = [
|
|
|
28
29
|
"packages/core/release/next-development/actions.js",
|
|
29
30
|
"packages/core/publication/oci/preview-actions.js",
|
|
30
31
|
"packages/core/publication/settlement/actions.js",
|
|
32
|
+
"packages/core/publication/pipeline/actions.js",
|
|
31
33
|
];
|
|
32
34
|
|
|
33
35
|
export function localModuleSpecifiers(source) {
|
|
@@ -150,7 +152,9 @@ export function discoverReleaseAuthorityClosure() {
|
|
|
150
152
|
[".js", ".mjs", ".cjs"],
|
|
151
153
|
/(?:release-tail-provider-(?:adapters|plane)|create(?:GitHubReleaseAssets|SignedStaticChannel|SiteReleaseActivation|ReleasedEvidence)Adapter)/u,
|
|
152
154
|
);
|
|
153
|
-
const runtimeSelectors = productionFiles("packages/core/runtime/entry", [
|
|
155
|
+
const runtimeSelectors = productionFiles("packages/core/runtime/entry", [
|
|
156
|
+
".js",
|
|
157
|
+
]).sort();
|
|
154
158
|
const terminalProjections = matchingProductionFiles(
|
|
155
159
|
[".github/workflows", "actions", "packages/core", "scripts"],
|
|
156
160
|
[".yml", ".yaml", ".js", ".mjs", ".cjs"],
|
|
@@ -523,6 +527,7 @@ export function checkReleaseTopology() {
|
|
|
523
527
|
assert.equal(ledger.contract, "kungfu-buildchain-v4-release-topology/v1");
|
|
524
528
|
assertClosedWorld(ledger.closedWorld.workflowPaths);
|
|
525
529
|
assertAuthorityClosure(ledger);
|
|
530
|
+
assertPipelinePublicationTopology(ledger, discoverReleaseTopology, root);
|
|
526
531
|
const preview = ledger.postPublicationScope;
|
|
527
532
|
assert.deepEqual(preview.workflowPaths, [
|
|
528
533
|
".github/workflows/public-release-oci-compose-preview.yml",
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { parse as yaml } from "yaml";
|
|
5
|
+
import { format } from "prettier";
|
|
6
|
+
import { standardConsumerExample } from "../packages/core/consumer/contract/examples.js";
|
|
7
|
+
import { inspectConsumerContract } from "../packages/core/consumer/contract/inspection.js";
|
|
8
|
+
import { workflowPath } from "../packages/core/workflow/workflow-taxonomy.mjs";
|
|
9
|
+
|
|
10
|
+
const root = process.cwd(),
|
|
11
|
+
check = process.argv.includes("--check");
|
|
12
|
+
const tracked = execFileSync("git", ["ls-files", "-z"], { encoding: "utf8" })
|
|
13
|
+
.split("\0")
|
|
14
|
+
.filter(Boolean);
|
|
15
|
+
|
|
16
|
+
function output(file, value) {
|
|
17
|
+
const target = path.join(root, file);
|
|
18
|
+
if (check) {
|
|
19
|
+
if (!fs.existsSync(target) || fs.readFileSync(target, "utf8") !== value)
|
|
20
|
+
throw new Error(`${file}: generated contract drift`);
|
|
21
|
+
} else {
|
|
22
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
23
|
+
fs.writeFileSync(target, value);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function destination(name) {
|
|
28
|
+
if (name === "config-path") return "normal-entry.config-path";
|
|
29
|
+
if (name === "runtime-ref") return "recovery-entry.runtime-ref";
|
|
30
|
+
if (/token|secret|private-key|app-id/u.test(name))
|
|
31
|
+
return "setup.provider-authority";
|
|
32
|
+
if (/run|resume|recover|transaction|discussion|attempt/u.test(name))
|
|
33
|
+
return "attempt.material-index";
|
|
34
|
+
if (/root|proof|nonce|warrant|fence|generation|candidate/u.test(name))
|
|
35
|
+
return "attempt.internal-authority";
|
|
36
|
+
return "internal.plan-derived-input";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function workflowInventory() {
|
|
40
|
+
const taxonomy = JSON.parse(
|
|
41
|
+
fs.readFileSync("architecture/workflow-taxonomy.json", "utf8"),
|
|
42
|
+
);
|
|
43
|
+
return taxonomy.entries
|
|
44
|
+
.filter((entry) => ["public", "self"].includes(entry.role))
|
|
45
|
+
.map((entry) => {
|
|
46
|
+
const file = workflowPath(entry),
|
|
47
|
+
document = yaml(fs.readFileSync(file, "utf8"));
|
|
48
|
+
return {
|
|
49
|
+
path: file,
|
|
50
|
+
role: entry.role,
|
|
51
|
+
events: Object.keys(document.on || {}).sort(),
|
|
52
|
+
secrets: Object.keys(document.on?.workflow_call?.secrets || {}).sort(),
|
|
53
|
+
outputs: Object.keys(document.on?.workflow_call?.outputs || {}).sort(),
|
|
54
|
+
destination:
|
|
55
|
+
entry.role === "self"
|
|
56
|
+
? "self-dogfood.two-callers-or-internal-component"
|
|
57
|
+
: "internal-component.behind-pipeline-or-recovery",
|
|
58
|
+
interfaces: ["workflow_call", "workflow_dispatch"].flatMap((trigger) =>
|
|
59
|
+
Object.entries(document.on?.[trigger]?.inputs || {}).map(
|
|
60
|
+
([name, definition]) => ({
|
|
61
|
+
trigger,
|
|
62
|
+
name,
|
|
63
|
+
definition,
|
|
64
|
+
destination: destination(name),
|
|
65
|
+
}),
|
|
66
|
+
),
|
|
67
|
+
),
|
|
68
|
+
calls: Object.entries(document.jobs || {})
|
|
69
|
+
.filter(([, job]) => job.uses)
|
|
70
|
+
.map(([id, job]) => ({
|
|
71
|
+
id,
|
|
72
|
+
uses: job.uses,
|
|
73
|
+
inputs: Object.keys(job.with || {}).sort(),
|
|
74
|
+
destination: "internal.workflow-composition",
|
|
75
|
+
})),
|
|
76
|
+
};
|
|
77
|
+
})
|
|
78
|
+
.sort((a, b) => a.path.localeCompare(b.path));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function consumerSourceInventory() {
|
|
82
|
+
return tracked
|
|
83
|
+
.filter(
|
|
84
|
+
(file) =>
|
|
85
|
+
(/^(?:templates|fixtures|\.buildchain)\//u.test(file) ||
|
|
86
|
+
file === "package.json") &&
|
|
87
|
+
/\.(?:ya?ml|toml|json|[cm]?js|sh|py|ps1)$/u.test(file) &&
|
|
88
|
+
!file.startsWith("templates/minimal-consumer/"),
|
|
89
|
+
)
|
|
90
|
+
.map((file) => {
|
|
91
|
+
const bytes = fs.readFileSync(file, "utf8");
|
|
92
|
+
const kind = /\.ya?ml$/u.test(file)
|
|
93
|
+
? "caller"
|
|
94
|
+
: /\.toml$/u.test(file)
|
|
95
|
+
? "config"
|
|
96
|
+
: "consumer-source";
|
|
97
|
+
return {
|
|
98
|
+
path: file,
|
|
99
|
+
kind,
|
|
100
|
+
destination:
|
|
101
|
+
kind === "caller"
|
|
102
|
+
? "replace-with-shared-pair"
|
|
103
|
+
: kind === "config"
|
|
104
|
+
? "closed-toml-plan"
|
|
105
|
+
: "retain-product-source; move-orchestration-into-runtime",
|
|
106
|
+
commandReferences: [
|
|
107
|
+
...new Set(
|
|
108
|
+
bytes.match(
|
|
109
|
+
/(?:packages\/core|scripts)\/[A-Za-z0-9_./-]+\.(?:[cm]?js|sh|py|ps1)/gu,
|
|
110
|
+
) || [],
|
|
111
|
+
),
|
|
112
|
+
].sort(),
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
for (const type of ["npm", "binary", "paper"]) {
|
|
118
|
+
const files = standardConsumerExample(type);
|
|
119
|
+
if (check) {
|
|
120
|
+
const directory = `templates/minimal-consumer/${type}`;
|
|
121
|
+
for (const entry of fs.readdirSync(directory, {
|
|
122
|
+
recursive: true,
|
|
123
|
+
withFileTypes: true,
|
|
124
|
+
})) {
|
|
125
|
+
if (entry.isDirectory()) continue;
|
|
126
|
+
const file = path
|
|
127
|
+
.relative(directory, path.join(entry.parentPath, entry.name))
|
|
128
|
+
.split(path.sep)
|
|
129
|
+
.join("/");
|
|
130
|
+
if (!entry.isFile() || !Object.hasOwn(files, file))
|
|
131
|
+
throw new Error(
|
|
132
|
+
`${directory}/${file}: undeclared generated consumer file`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const inspection = inspectConsumerContract(files);
|
|
137
|
+
if (!inspection.ok) throw new Error(inspection.issues.join("\n"));
|
|
138
|
+
for (const [file, bytes] of Object.entries(files))
|
|
139
|
+
output(`templates/minimal-consumer/${type}/${file}`, bytes);
|
|
140
|
+
}
|
|
141
|
+
output(
|
|
142
|
+
"architecture/minimal-consumer-migration.json",
|
|
143
|
+
await format(
|
|
144
|
+
JSON.stringify({
|
|
145
|
+
schema: "buildchain.consumer-migration/v1",
|
|
146
|
+
stage: "contract-defined; execution-entry-not-yet-published",
|
|
147
|
+
workflows: workflowInventory(),
|
|
148
|
+
consumerSources: consumerSourceInventory(),
|
|
149
|
+
}),
|
|
150
|
+
{ parser: "json" },
|
|
151
|
+
),
|
|
152
|
+
);
|
|
153
|
+
console.log(
|
|
154
|
+
"Minimal consumer contract: three shared-caller examples and complete migration inventory verified.",
|
|
155
|
+
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
+
import { readNpmPackResult } from "../packages/core/publication/npm/pack-result.js";
|
|
3
4
|
import os from "node:os";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
@@ -44,7 +45,10 @@ export function verifyGoldenPath() {
|
|
|
44
45
|
["pack", "--json", "--pack-destination", packDir],
|
|
45
46
|
{ cwd: root, json: true },
|
|
46
47
|
);
|
|
47
|
-
const tarball = path.join(
|
|
48
|
+
const tarball = path.join(
|
|
49
|
+
packDir,
|
|
50
|
+
readNpmPackResult(JSON.stringify(packed)).filename,
|
|
51
|
+
);
|
|
48
52
|
fs.writeFileSync(
|
|
49
53
|
path.join(consumer, "package.json"),
|
|
50
54
|
`${JSON.stringify(
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
schema = 2
|
|
2
|
+
|
|
3
|
+
[[products]]
|
|
4
|
+
id = "main"
|
|
5
|
+
type = "binary"
|
|
6
|
+
platforms = ["linux-x64"]
|
|
7
|
+
build = ["node src/build.mjs"]
|
|
8
|
+
verify = ["node src/verify.mjs"]
|
|
9
|
+
|
|
10
|
+
[[products.artifacts]]
|
|
11
|
+
id = "main"
|
|
12
|
+
path = "dist/hello.tar.gz"
|
|
13
|
+
kind = "archive"
|
|
14
|
+
|
|
15
|
+
[[products.targets]]
|
|
16
|
+
provider = "github-release"
|
|
17
|
+
artifacts = ["main"]
|
|
18
|
+
|
|
19
|
+
[version]
|
|
20
|
+
strategy = "semver"
|
|
21
|
+
|
|
22
|
+
[[version.files]]
|
|
23
|
+
path = "package.json"
|
|
24
|
+
format = "json"
|
|
25
|
+
key = "version"
|
|
26
|
+
|
|
27
|
+
[[channels]]
|
|
28
|
+
from = "feature/*"
|
|
29
|
+
to = "dev/v1/v1.0"
|
|
30
|
+
operation = "develop"
|
|
31
|
+
|
|
32
|
+
[[channels]]
|
|
33
|
+
from = "dev/v1/v1.0"
|
|
34
|
+
to = "alpha/v1/v1.0"
|
|
35
|
+
operation = "alpha"
|
|
36
|
+
|
|
37
|
+
[[channels]]
|
|
38
|
+
from = "alpha/v1/v1.0"
|
|
39
|
+
to = "release/v1/v1.0"
|
|
40
|
+
operation = "stable"
|
|
41
|
+
|
|
42
|
+
[review]
|
|
43
|
+
minimum_approvals = 1
|
|
44
|
+
code_owners = true
|
|
45
|
+
merge_queue = true
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Buildchain recovery
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
inputs:
|
|
5
|
+
attempt:
|
|
6
|
+
description: Exact Buildchain attempt to recover
|
|
7
|
+
required: true
|
|
8
|
+
type: string
|
|
9
|
+
runtime-ref:
|
|
10
|
+
description: Optional repaired runtime
|
|
11
|
+
required: false
|
|
12
|
+
type: string
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
jobs:
|
|
16
|
+
buildchain:
|
|
17
|
+
uses: kungfu-systems/buildchain/.github/workflows/public-ops-recover.yml@v4
|
|
18
|
+
with:
|
|
19
|
+
attempt: ${{ inputs.attempt }}
|
|
20
|
+
runtime-ref: ${{ inputs.runtime-ref }}
|
|
21
|
+
secrets: inherit
|
|
22
|
+
permissions:
|
|
23
|
+
actions: write
|
|
24
|
+
attestations: write
|
|
25
|
+
checks: write
|
|
26
|
+
contents: write
|
|
27
|
+
discussions: write
|
|
28
|
+
id-token: write
|
|
29
|
+
pull-requests: write
|
|
30
|
+
statuses: write
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Buildchain pipeline
|
|
2
|
+
on:
|
|
3
|
+
pull_request:
|
|
4
|
+
types: [opened, reopened, synchronize, ready_for_review, converted_to_draft, closed, labeled, unlabeled, edited, enqueued, dequeued]
|
|
5
|
+
pull_request_review:
|
|
6
|
+
types: [submitted, dismissed]
|
|
7
|
+
pull_request_target:
|
|
8
|
+
types: [closed]
|
|
9
|
+
merge_group:
|
|
10
|
+
types: [checks_requested]
|
|
11
|
+
push:
|
|
12
|
+
repository_dispatch:
|
|
13
|
+
types: [buildchain-attempt-wake]
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
jobs:
|
|
17
|
+
buildchain:
|
|
18
|
+
uses: kungfu-systems/buildchain/.github/workflows/public-ops-pipeline.yml@v4
|
|
19
|
+
secrets: inherit
|
|
20
|
+
permissions:
|
|
21
|
+
actions: write
|
|
22
|
+
attestations: write
|
|
23
|
+
checks: write
|
|
24
|
+
contents: write
|
|
25
|
+
discussions: write
|
|
26
|
+
id-token: write
|
|
27
|
+
pull-requests: write
|
|
28
|
+
statuses: write
|