@kungfu-tech/buildchain 4.1.3-alpha.1 → 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 +239 -2
- 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 +331 -2
- 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 +245 -11
- package/architecture/universal-workflow-bootstrap.json +10 -0
- package/architecture/universal-workflow-capability-policy.json +1 -1
- package/architecture/workflow-taxonomy.json +55 -0
- package/dist/readers/business-attempt.cjs +805 -0
- package/dist/site/buildchain-contract.json +7 -5
- package/dist/site/buildchain-site.json +18 -13
- 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 +7 -7
- package/dist/site/page-registry.json +13 -8
- 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 +11 -11
- 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 +7 -2
- 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/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
|