@kungfu-tech/buildchain 4.0.2-alpha.9 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +10 -1
- package/CONTRIBUTING.md +24 -0
- package/README.md +2 -2
- package/actions/promote-buildchain-ref/README.md +1 -1
- package/actions/v4-release-candidate-promote/README.md +28 -0
- package/architecture/agent-change-map.md +64 -7
- package/architecture/ci-lane-change-budget.json +366 -0
- package/architecture/internal-capabilities.json +53 -8
- package/architecture/maintainability-debt.json +147 -93
- package/architecture/maintainability-policy.json +32 -28
- package/architecture/release-tail-contract-inventory.json +6 -6
- package/architecture/v4-architecture-constitution.md +23 -20
- package/architecture/v4-cross-platform-adopter-qualification.json +1 -1
- package/architecture/v4-delivery-authority-parity.json +2 -2
- package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.json +1 -1
- package/architecture/v4-floating-consumer-policy.json +2 -2
- package/architecture/v4-next-development-parity.json +5 -5
- package/architecture/v4-partial-mutation-recovery-qualification.json +4 -1
- package/architecture/v4-platform-stage-checkpoints.json +1 -1
- package/architecture/v4-provider-operation-journal-contract.json +5 -2
- package/architecture/v4-publication-facade-patches.json +64 -0
- package/architecture/v4-release-activation-shadow-domain.json +5 -2
- package/architecture/v4-release-topology.json +74 -39
- package/architecture/v4-rust-wasm-production-authority.json +58 -0
- package/architecture/v4-stable-publication-fence.json +5 -2
- package/architecture/v4-stage-capsule-qualification.json +2 -2
- package/architecture/v4-tail-reseal-parity.json +8 -6
- package/architecture/v4-universal-workflow-bootstrap.json +171 -0
- package/architecture/v4-universal-workflow-fault-campaign.json +72 -0
- package/architecture/v4-universal-workflow-train-admission.json +40 -0
- package/architecture/workflow-taxonomy.json +1451 -0
- package/bin/buildchain.mjs +7 -7
- package/contracts/buildchain-v2-residuals-v1.json +57 -48
- package/contracts/dev-delivery-authority-v2.schema.json +16 -2
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
- package/contracts/v4-canonical-contracts-v1.schema.json +1 -0
- package/dist/site/buildchain-contract.json +93 -48
- package/dist/site/buildchain-site.json +222 -69
- package/dist/site/capability-registry.json +4 -4
- package/dist/site/controller-registry.json +50 -13
- package/dist/site/kfd-claims.json +2585 -1000
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +13 -13
- package/dist/site/node-api-registry.json +120 -115
- package/dist/site/page-registry.json +204 -51
- package/dist/site/public-surface-audit.json +3205 -1219
- package/dist/site/publication-authority-registry.json +1124 -362
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/schemas/dev-delivery-authority-v2.schema.json +16 -2
- package/dist/site/site-manifest.json +17 -17
- package/dist/site/workflow-registry.json +5061 -1659
- package/docs/MAP.md +1 -0
- package/docs/auditable-demo.md +1 -1
- package/docs/cli.md +21 -8
- package/docs/dev-delivery-warrant.md +1 -1
- package/docs/engineering-housekeeper.md +3 -3
- package/docs/kfd-support.md +26 -2
- package/docs/next-development-transition.md +2 -2
- package/docs/node-api-reference.md +190 -190
- package/docs/publication-authority.md +2 -2
- package/docs/release-candidate.md +3 -3
- package/docs/release-flow.md +67 -19
- package/docs/release-governance.md +8 -8
- package/docs/release-passport.md +27 -2
- package/docs/reusable-build-surface.md +16 -0
- package/docs/v4-adopter-delivery.md +2 -2
- package/docs/v4-production-release.md +71 -8
- package/docs/v4-rust-wasm-production-authority.md +58 -0
- package/docs/v4-stage-capsule.md +2 -2
- package/docs/v4-tail-reseal.md +1 -1
- package/docs/workflow-catalog.md +154 -0
- package/docs/workflow-path-migration.md +109 -0
- package/package.json +10 -6
- package/packages/core/artifact-verification-envelope.js +5 -5
- package/packages/core/buildchain-contract.js +1 -1
- package/packages/core/buildchain-kfd-claims.js +2 -2
- package/packages/core/buildchain-publication-authority.js +42 -26
- package/packages/core/buildchain-v4-domain.wasm +0 -0
- package/packages/core/ci-lane-change-budget.js +14 -1
- package/packages/core/controller-evidence.js +4 -1
- package/packages/core/dev-delivery-candidate-identity.js +40 -6
- package/packages/core/dev-delivery-warrant-state.js +3 -4
- package/packages/core/dev-delivery-warrant.js +12 -2
- package/packages/core/github-governance-authority.js +4 -4
- package/packages/core/kfd-adopter-manifest.js +46 -47
- package/packages/core/next-development-projection.js +2 -2
- package/packages/core/paper-agent-entry.js +30 -4
- package/packages/core/paper-fleet.js +1 -1
- package/packages/core/paper-runtime-channels.js +348 -0
- package/packages/core/paper-scaffold-content.js +10 -0
- package/packages/core/paper.js +37 -71
- package/packages/core/release-line-dry-run.js +1 -1
- package/packages/core/release-passport-contract.js +5 -5
- package/packages/core/release-passport.js +5 -4
- package/packages/core/release-tail-provider-plane.js +68 -1048
- package/packages/core/v4-canonical-contracts.js +10 -75
- package/packages/core/v4-domain-wasm-artifact.js +7 -0
- package/packages/core/v4-domain-wasm.js +216 -0
- package/packages/core/v4-floating-consumer-evidence.js +1 -1
- package/packages/core/v4-floating-consumer-policy.js +1 -1
- package/packages/core/v4-partial-mutation-recovery-qualification.js +9 -386
- package/packages/core/v4-product-publication.js +19 -349
- package/packages/core/v4-protected-publication-source.js +19 -21
- package/packages/core/v4-provider-operation-journal.js +18 -487
- package/packages/core/v4-provider-readback-idempotency.js +12 -97
- package/packages/core/v4-release-activation-shadow.js +13 -500
- package/packages/core/v4-release-invocation.js +28 -389
- package/packages/core/v4-stable-publication-fence.js +13 -342
- package/packages/core/v4-universal-workflow-bootstrap.js +586 -0
- package/scripts/binary-publication-evidence.mjs +135 -0
- package/scripts/build-contract-core.mjs +1 -14
- package/scripts/build-v4-domain-wasm.mjs +189 -0
- package/scripts/check-action-bundles.mjs +12 -2
- package/scripts/check-ci-lane-change-budget.mjs +4 -1
- package/scripts/check-core-mechanism-inventory.mjs +4 -3
- package/scripts/check-inventory.mjs +35 -44
- package/scripts/check-maintainability.mjs +16 -113
- package/scripts/check-v4-floating-consumer-policy-contract.mjs +2 -2
- package/scripts/check-v4-public-dogfood-contract.mjs +22 -9
- package/scripts/check-v4-release-topology.mjs +90 -33
- package/scripts/check-v4-runtime-semantic-closure.mjs +4 -1
- package/scripts/check-v4-universal-workflow-bootstrap.mjs +266 -0
- package/scripts/check-workflow-taxonomy.mjs +6 -0
- package/scripts/copy-v4-domain-wasm.mjs +14 -0
- package/scripts/dev-delivery-authority-command-adapters.mjs +1 -1
- package/scripts/dev-delivery-authority.mjs +8 -8
- package/scripts/dev-delivery-source-proof-reuse.mjs +2 -1
- package/scripts/dev-delivery-warrant-options.mjs +14 -9
- package/scripts/dev-delivery-warrant-store.mjs +73 -7
- package/scripts/dev-delivery-warrant-transition.mjs +109 -0
- package/scripts/dev-delivery-warrant.mjs +76 -99
- package/scripts/dev-pr-auto-merge.mjs +15 -15
- package/scripts/generate-channel-build-workflow.mjs +7 -2
- package/scripts/generate-channel-promotion-workflow.mjs +7 -5
- package/scripts/generate-site-bundle.mjs +11 -11
- package/scripts/generate-v4-universal-workflow-facades.mjs +458 -0
- package/scripts/generate-workflow-taxonomy.mjs +25 -0
- package/scripts/github-output.mjs +31 -0
- package/scripts/maintainability-metrics.mjs +16 -5
- package/scripts/maintainability-public-surface.mjs +115 -0
- package/scripts/next-development-review.mjs +307 -0
- package/scripts/paper-work-fleet-cli.mjs +2 -0
- package/scripts/release-asset-client.mjs +91 -0
- package/scripts/release-candidate-resolver.mjs +9 -9
- package/scripts/source-verification-evidence.mjs +344 -0
- package/scripts/stable-candidate-qualification.mjs +1 -1
- package/scripts/universal-facade-maintainability.mjs +82 -0
- package/scripts/v4-product-publication-intent.mjs +13 -6
- package/scripts/v4-publication-settlement.mjs +211 -0
- package/scripts/v4-universal-workflow-backflow.mjs +212 -0
- package/scripts/v4-universal-workflow-engine.mjs +618 -0
- package/scripts/v4-universal-workflow-self-dogfood.mjs +205 -0
- package/scripts/verify-version-state-delta.mjs +173 -0
- package/scripts/workflow-taxonomy.mjs +507 -0
- package/templates/native-dev-delivery.yml +4 -7
- package/templates/universal-buildchain-bootstrap-recovery.yml +282 -0
- package/templates/universal-buildchain-bootstrap.yml +28 -0
|
@@ -1,88 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
RELEASE_TAIL_DECLARATION_CONTRACT,
|
|
4
|
-
RELEASE_TAIL_EFFECT_SCHEMA,
|
|
5
|
-
RELEASE_TAIL_OBSERVATION_SCHEMA,
|
|
6
|
-
RELEASE_TAIL_RECEIPT_SCHEMA,
|
|
7
|
-
RELEASE_TAIL_TRANSACTION_POLICY,
|
|
8
|
-
} from "./release-tail-provider-plane.js";
|
|
9
|
-
import { RELEASE_TAIL_PRODUCT_CAPABILITIES } from "./release-tail-product-capabilities.js";
|
|
1
|
+
import { invokeV4DomainWasm } from "./v4-domain-wasm.js";
|
|
10
2
|
|
|
11
3
|
export const V4_PRODUCT_PUBLICATION_INTENT_CONTRACT =
|
|
12
4
|
"kungfu-buildchain-v4-product-publication-intent/v1";
|
|
13
5
|
export const V4_PRODUCT_PUBLICATION_PLAN_CONTRACT =
|
|
14
6
|
"kungfu-buildchain-v4-product-publication-plan/v1";
|
|
15
7
|
|
|
16
|
-
const VERSION = /^(\d+)\.(\d+)\.(\d+)(?:-alpha\.(\d+))?$/u;
|
|
17
|
-
const SHA = /^[0-9a-f]{40}$/u;
|
|
18
|
-
const ROOT = /^sha256:[0-9a-f]{64}$/u;
|
|
19
|
-
const REPOSITORY = /^[^/\s]+\/[^/\s]+$/u;
|
|
20
|
-
|
|
21
|
-
function fail(message) {
|
|
22
|
-
throw new Error(`invalid v4 product publication: ${message}`);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function parseVersion(value, label) {
|
|
26
|
-
const normalized = String(value || "").trim();
|
|
27
|
-
const match = normalized.match(VERSION);
|
|
28
|
-
if (!match) fail(`${label} must be an exact stable or alpha version`);
|
|
29
|
-
return {
|
|
30
|
-
value: normalized,
|
|
31
|
-
major: Number(match[1]),
|
|
32
|
-
minor: Number(match[2]),
|
|
33
|
-
patch: Number(match[3]),
|
|
34
|
-
alpha: match[4] === undefined ? null : Number(match[4]),
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function channelName(value) {
|
|
39
|
-
if (value === "alpha") return "alpha";
|
|
40
|
-
if (["release", "stable", "major"].includes(value)) return "stable";
|
|
41
|
-
fail(`unsupported channel '${value}'`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function assertLane({ channel, targetRef, version }) {
|
|
45
|
-
const expression =
|
|
46
|
-
channel === "alpha"
|
|
47
|
-
? /^alpha\/v(\d+)\/v(\d+)\.(\d+)$/u
|
|
48
|
-
: /^release\/v(\d+)\/v(\d+)\.(\d+)$/u;
|
|
49
|
-
const match = String(targetRef || "").match(expression);
|
|
50
|
-
if (!match) fail(`target ref '${targetRef}' is not a ${channel} lane`);
|
|
51
|
-
if (
|
|
52
|
-
Number(match[1]) !== version.major ||
|
|
53
|
-
Number(match[2]) !== version.major ||
|
|
54
|
-
Number(match[3]) !== version.minor
|
|
55
|
-
)
|
|
56
|
-
fail("target ref does not match the publication version line");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function observedAlphaNumber(version, expected) {
|
|
60
|
-
const parsed = parseVersion(version, "observed version");
|
|
61
|
-
return parsed.major === expected.major &&
|
|
62
|
-
parsed.minor === expected.minor &&
|
|
63
|
-
parsed.patch === expected.patch
|
|
64
|
-
? parsed.alpha
|
|
65
|
-
: null;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function requiredString(value, label) {
|
|
69
|
-
const normalized = String(value || "").trim();
|
|
70
|
-
if (!normalized) fail(`${label} must be a non-empty string`);
|
|
71
|
-
return normalized;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function requiredRoot(value, label) {
|
|
75
|
-
const normalized = requiredString(value, label).toLowerCase();
|
|
76
|
-
if (!ROOT.test(normalized)) fail(`${label} must be a sha256 content root`);
|
|
77
|
-
return normalized;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
8
|
export function selectV4ProductPublicationIntent({
|
|
81
9
|
channel,
|
|
82
10
|
targetRef,
|
|
83
11
|
sourceSha,
|
|
84
12
|
sourceTimestamp,
|
|
85
13
|
repository,
|
|
14
|
+
artifactKind = "npm",
|
|
86
15
|
packageName,
|
|
87
16
|
distTag,
|
|
88
17
|
sealedBundleRoot,
|
|
@@ -91,102 +20,21 @@ export function selectV4ProductPublicationIntent({
|
|
|
91
20
|
recoveredVersion = "",
|
|
92
21
|
observedVersions = [],
|
|
93
22
|
}) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
fail("sourceSha must be an exact Git SHA");
|
|
97
|
-
if (!REPOSITORY.test(String(repository || "")))
|
|
98
|
-
fail("repository must be owner/repo");
|
|
99
|
-
const normalizedTimestamp = requiredString(
|
|
100
|
-
sourceTimestamp,
|
|
101
|
-
"sourceTimestamp",
|
|
102
|
-
);
|
|
103
|
-
if (Number.isNaN(Date.parse(normalizedTimestamp)))
|
|
104
|
-
fail("sourceTimestamp must be an ISO timestamp");
|
|
105
|
-
const normalizedPackageName = requiredString(packageName, "packageName");
|
|
106
|
-
const normalizedDistTag = requiredString(distTag, "distTag");
|
|
107
|
-
if (!/^[a-z0-9][a-z0-9._-]*$/u.test(normalizedDistTag))
|
|
108
|
-
fail("distTag must be an npm dist-tag");
|
|
109
|
-
if (!Array.isArray(observedVersions))
|
|
110
|
-
fail("observedVersions must be an array");
|
|
111
|
-
const candidate = parseVersion(candidateVersion, "candidateVersion");
|
|
112
|
-
assertLane({ channel: normalizedChannel, targetRef, version: candidate });
|
|
113
|
-
const observed = [...new Set(observedVersions.map(String))].sort();
|
|
114
|
-
let version;
|
|
115
|
-
let mode = "fresh";
|
|
116
|
-
if (String(recoveredVersion || "").trim()) {
|
|
117
|
-
const recovered = parseVersion(recoveredVersion, "recoveredVersion");
|
|
118
|
-
if (
|
|
119
|
-
recovered.major !== candidate.major ||
|
|
120
|
-
recovered.minor !== candidate.minor ||
|
|
121
|
-
recovered.patch !== candidate.patch ||
|
|
122
|
-
(normalizedChannel === "alpha" && recovered.alpha === null) ||
|
|
123
|
-
(normalizedChannel === "stable" && recovered.alpha !== null)
|
|
124
|
-
)
|
|
125
|
-
fail("recoveredVersion is incompatible with the candidate release line");
|
|
126
|
-
version = recovered.value;
|
|
127
|
-
mode = "resume";
|
|
128
|
-
} else if (normalizedChannel === "alpha") {
|
|
129
|
-
if (candidate.alpha === null)
|
|
130
|
-
fail("fresh alpha publication requires an alpha candidate version");
|
|
131
|
-
const highest = observed.reduce(
|
|
132
|
-
(current, entry) =>
|
|
133
|
-
Math.max(current, observedAlphaNumber(entry, candidate) ?? -1),
|
|
134
|
-
candidate.alpha,
|
|
135
|
-
);
|
|
136
|
-
version = `${candidate.major}.${candidate.minor}.${candidate.patch}-alpha.${highest + 1}`;
|
|
137
|
-
} else {
|
|
138
|
-
version = `${candidate.major}.${candidate.minor}.${candidate.patch}`;
|
|
139
|
-
}
|
|
140
|
-
const intent = {
|
|
141
|
-
schema: V4_PRODUCT_PUBLICATION_INTENT_CONTRACT,
|
|
142
|
-
mode,
|
|
143
|
-
channel: normalizedChannel,
|
|
23
|
+
return invokeV4DomainWasm("product-publication-intent", {
|
|
24
|
+
channel,
|
|
144
25
|
targetRef,
|
|
145
26
|
sourceSha,
|
|
146
|
-
sourceTimestamp
|
|
27
|
+
sourceTimestamp,
|
|
147
28
|
repository,
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
exactTag: `v${version}`,
|
|
158
|
-
observedVersions: observed,
|
|
159
|
-
};
|
|
160
|
-
return {
|
|
161
|
-
...intent,
|
|
162
|
-
intentRoot: v4ContentRoot("v4-product-publication-intent", intent),
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function alphaReferences(intent, version) {
|
|
167
|
-
const line = `v${version.major}.${version.minor}`;
|
|
168
|
-
return [
|
|
169
|
-
{ ref: `refs/tags/${intent.exactTag}`, target: "source" },
|
|
170
|
-
{ ref: `refs/heads/${intent.targetRef}`, target: "version-state" },
|
|
171
|
-
{
|
|
172
|
-
ref: `refs/heads/dev/v${version.major}/${line}`,
|
|
173
|
-
target: "version-state",
|
|
174
|
-
},
|
|
175
|
-
{ ref: `refs/tags/${line}-alpha`, target: "version-state" },
|
|
176
|
-
{ ref: `refs/tags/v${version.major}-alpha`, target: "version-state" },
|
|
177
|
-
];
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function stableReferences(intent, version) {
|
|
181
|
-
return [
|
|
182
|
-
{ ref: `refs/tags/${intent.exactTag}`, target: "source" },
|
|
183
|
-
{ ref: `refs/heads/${intent.targetRef}`, target: "version-state" },
|
|
184
|
-
{
|
|
185
|
-
ref: `refs/tags/v${version.major}.${version.minor}`,
|
|
186
|
-
target: "version-state",
|
|
187
|
-
},
|
|
188
|
-
{ ref: `refs/tags/v${version.major}`, target: "version-state" },
|
|
189
|
-
];
|
|
29
|
+
artifactKind,
|
|
30
|
+
...(packageName === undefined ? {} : { packageName }),
|
|
31
|
+
...(distTag === undefined ? {} : { distTag }),
|
|
32
|
+
...(sealedBundleRoot === undefined ? {} : { sealedBundleRoot }),
|
|
33
|
+
requiredArtifactsRoot,
|
|
34
|
+
candidateVersion,
|
|
35
|
+
recoveredVersion,
|
|
36
|
+
observedVersions,
|
|
37
|
+
});
|
|
190
38
|
}
|
|
191
39
|
|
|
192
40
|
export function createV4ProductPublicationPlan({
|
|
@@ -194,194 +42,16 @@ export function createV4ProductPublicationPlan({
|
|
|
194
42
|
invocationRoot,
|
|
195
43
|
transactionRoot,
|
|
196
44
|
}) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const selected = selectV4ProductPublicationIntent({
|
|
200
|
-
channel: intent.channel,
|
|
201
|
-
targetRef: intent.targetRef,
|
|
202
|
-
sourceSha: intent.sourceSha,
|
|
203
|
-
sourceTimestamp: intent.sourceTimestamp,
|
|
204
|
-
repository: intent.repository,
|
|
205
|
-
packageName: intent.packageName,
|
|
206
|
-
distTag: intent.distTag,
|
|
207
|
-
sealedBundleRoot: intent.sealedBundleRoot,
|
|
208
|
-
requiredArtifactsRoot: intent.requiredArtifactsRoot,
|
|
209
|
-
candidateVersion: intent.candidateVersion,
|
|
210
|
-
recoveredVersion: intent.mode === "resume" ? intent.version : "",
|
|
211
|
-
observedVersions: intent.observedVersions,
|
|
212
|
-
});
|
|
213
|
-
if (selected.intentRoot !== intent.intentRoot)
|
|
214
|
-
fail("intentRoot does not match the canonical publication intent");
|
|
215
|
-
const parsed = parseVersion(intent.version, "intent.version");
|
|
216
|
-
const references =
|
|
217
|
-
intent.channel === "alpha"
|
|
218
|
-
? alphaReferences(intent, parsed)
|
|
219
|
-
: stableReferences(intent, parsed);
|
|
220
|
-
const stateRef = `refs/heads/buildchain/v4-product-state/${intent.sourceSha}-${intent.version.replaceAll(".", "-")}`;
|
|
221
|
-
const operations = [
|
|
222
|
-
{
|
|
223
|
-
id: "product.version-state.materialize",
|
|
224
|
-
adapter: "github-version-state",
|
|
225
|
-
authority: "contents-write",
|
|
226
|
-
target: {
|
|
227
|
-
repository: intent.repository,
|
|
228
|
-
version: intent.version,
|
|
229
|
-
sourceSha: intent.sourceSha,
|
|
230
|
-
sourceTimestamp: intent.sourceTimestamp,
|
|
231
|
-
stateRef,
|
|
232
|
-
},
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
id: "product.package.publish",
|
|
236
|
-
adapter: "npm-trusted-publishing",
|
|
237
|
-
authority: "oidc-provider-mutation",
|
|
238
|
-
target: {
|
|
239
|
-
packageName: intent.packageName,
|
|
240
|
-
version: intent.version,
|
|
241
|
-
distTag: intent.distTag,
|
|
242
|
-
sealedBundleRoot: intent.sealedBundleRoot,
|
|
243
|
-
requiredArtifactsRoot: intent.requiredArtifactsRoot,
|
|
244
|
-
},
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
id: "product.release-refs.converge",
|
|
248
|
-
adapter: "github-release-refs",
|
|
249
|
-
authority: "contents-write",
|
|
250
|
-
target: {
|
|
251
|
-
repository: intent.repository,
|
|
252
|
-
sourceSha: intent.sourceSha,
|
|
253
|
-
stateRef,
|
|
254
|
-
references,
|
|
255
|
-
},
|
|
256
|
-
},
|
|
257
|
-
].map((operation) => ({
|
|
258
|
-
...operation,
|
|
259
|
-
operationRoot: v4ContentRoot("v4-product-publication-operation", operation),
|
|
260
|
-
}));
|
|
261
|
-
const plan = {
|
|
262
|
-
schema: V4_PRODUCT_PUBLICATION_PLAN_CONTRACT,
|
|
263
|
-
intentRoot: intent.intentRoot,
|
|
45
|
+
return invokeV4DomainWasm("product-publication-plan", {
|
|
46
|
+
intent,
|
|
264
47
|
invocationRoot,
|
|
265
48
|
transactionRoot,
|
|
266
|
-
|
|
267
|
-
operations,
|
|
268
|
-
};
|
|
269
|
-
return {
|
|
270
|
-
...plan,
|
|
271
|
-
planRoot: v4ContentRoot("v4-product-publication-plan", plan),
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const PRODUCT_CAPABILITIES = Object.fromEntries(
|
|
276
|
-
RELEASE_TAIL_PRODUCT_CAPABILITIES.map((capability) => [
|
|
277
|
-
capability.id,
|
|
278
|
-
{
|
|
279
|
-
...capability,
|
|
280
|
-
destinationKind:
|
|
281
|
-
capability.id === "product.package.publish"
|
|
282
|
-
? "npm-package"
|
|
283
|
-
: capability.adapter,
|
|
284
|
-
},
|
|
285
|
-
]),
|
|
286
|
-
);
|
|
287
|
-
|
|
288
|
-
function exactTagPattern(tag) {
|
|
289
|
-
return `^${tag.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}$`;
|
|
49
|
+
});
|
|
290
50
|
}
|
|
291
51
|
|
|
292
52
|
export function createV4ProductPublicationDeclaration({ intent, plan }) {
|
|
293
|
-
|
|
53
|
+
return invokeV4DomainWasm("product-publication-declaration", {
|
|
294
54
|
intent,
|
|
295
|
-
|
|
296
|
-
transactionRoot: plan.transactionRoot,
|
|
55
|
+
plan,
|
|
297
56
|
});
|
|
298
|
-
if (rebuilt.planRoot !== plan.planRoot)
|
|
299
|
-
fail("planRoot does not match the canonical publication plan");
|
|
300
|
-
const operationById = new Map(
|
|
301
|
-
plan.operations.map((operation) => [operation.id, operation]),
|
|
302
|
-
);
|
|
303
|
-
return {
|
|
304
|
-
contract: RELEASE_TAIL_DECLARATION_CONTRACT,
|
|
305
|
-
schemaVersion: 1,
|
|
306
|
-
transactionPolicy: RELEASE_TAIL_TRANSACTION_POLICY,
|
|
307
|
-
subject: {
|
|
308
|
-
repository: intent.repository,
|
|
309
|
-
sourceSha: intent.sourceSha,
|
|
310
|
-
version: intent.version,
|
|
311
|
-
tag: intent.exactTag,
|
|
312
|
-
channel: intent.channel,
|
|
313
|
-
},
|
|
314
|
-
capabilities: plan.operationOrder.map((id) => {
|
|
315
|
-
const operation = operationById.get(id);
|
|
316
|
-
const descriptor = PRODUCT_CAPABILITIES[id];
|
|
317
|
-
if (!operation || !descriptor)
|
|
318
|
-
fail(`unsupported product publication operation '${id}'`);
|
|
319
|
-
return {
|
|
320
|
-
id,
|
|
321
|
-
executor: "provider-adapter",
|
|
322
|
-
adapter: operation.adapter,
|
|
323
|
-
artifactRoles: [
|
|
324
|
-
{ role: "publication-intent", root: intent.intentRoot },
|
|
325
|
-
...(id === "product.package.publish"
|
|
326
|
-
? [
|
|
327
|
-
{ role: "sealed-bundle", root: intent.sealedBundleRoot },
|
|
328
|
-
{
|
|
329
|
-
role: "required-artifacts",
|
|
330
|
-
root: intent.requiredArtifactsRoot,
|
|
331
|
-
},
|
|
332
|
-
]
|
|
333
|
-
: []),
|
|
334
|
-
],
|
|
335
|
-
destination: {
|
|
336
|
-
kind: descriptor.destinationKind,
|
|
337
|
-
locator: `${operation.adapter}:${operation.operationRoot}`,
|
|
338
|
-
},
|
|
339
|
-
channelPolicy: {
|
|
340
|
-
channel: intent.channel,
|
|
341
|
-
tagPattern: exactTagPattern(intent.exactTag),
|
|
342
|
-
authorityMove:
|
|
343
|
-
id === "product.package.publish" ? "none" : "verified-ref",
|
|
344
|
-
},
|
|
345
|
-
activationPolicy: { mode: "none", environment: "none" },
|
|
346
|
-
readbackPredicates: [
|
|
347
|
-
{
|
|
348
|
-
id: `${id}.target-root`,
|
|
349
|
-
kind: "exact-root",
|
|
350
|
-
expected: operation.operationRoot,
|
|
351
|
-
},
|
|
352
|
-
],
|
|
353
|
-
effect: {
|
|
354
|
-
schema: RELEASE_TAIL_EFFECT_SCHEMA,
|
|
355
|
-
kind: descriptor.effectKind,
|
|
356
|
-
},
|
|
357
|
-
observation: {
|
|
358
|
-
schema: RELEASE_TAIL_OBSERVATION_SCHEMA,
|
|
359
|
-
kind: descriptor.observationKind,
|
|
360
|
-
},
|
|
361
|
-
receipt: {
|
|
362
|
-
schema: RELEASE_TAIL_RECEIPT_SCHEMA,
|
|
363
|
-
kind: descriptor.receiptKind,
|
|
364
|
-
},
|
|
365
|
-
operationIdentity: {
|
|
366
|
-
transactionRoot: plan.transactionRoot,
|
|
367
|
-
capabilityId: id,
|
|
368
|
-
subjectRoot: intent.intentRoot,
|
|
369
|
-
targetRoot: operation.operationRoot,
|
|
370
|
-
attemptKey: `${plan.planRoot}:${id}`,
|
|
371
|
-
},
|
|
372
|
-
idempotency: {
|
|
373
|
-
scope: "subject-target",
|
|
374
|
-
duplicate: "readback-before-retry",
|
|
375
|
-
},
|
|
376
|
-
retry: {
|
|
377
|
-
class: "provider-transient",
|
|
378
|
-
localAttempts: 1,
|
|
379
|
-
exhausted: "blocked",
|
|
380
|
-
},
|
|
381
|
-
evidenceRequirements: [
|
|
382
|
-
"provider readback must match the rooted publication operation",
|
|
383
|
-
],
|
|
384
|
-
};
|
|
385
|
-
}),
|
|
386
|
-
};
|
|
387
57
|
}
|
|
@@ -4,10 +4,8 @@ const SHA_PATTERN = /^[0-9a-f]{40}$/u;
|
|
|
4
4
|
|
|
5
5
|
function exactSha(value, label) {
|
|
6
6
|
const normalized = String(value || "").toLowerCase();
|
|
7
|
-
if (
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
return normalized;
|
|
7
|
+
if (SHA_PATTERN.test(normalized)) return normalized;
|
|
8
|
+
throw new Error(`${label} must be an exact Git SHA`);
|
|
11
9
|
}
|
|
12
10
|
|
|
13
11
|
function exactParents(value, label) {
|
|
@@ -26,16 +24,14 @@ export function bindV4ProtectedPublicationSource({
|
|
|
26
24
|
if (!/^[^/\s]+\/[^/\s]+$/u.test(String(repository || ""))) {
|
|
27
25
|
throw new Error("protected publication source requires owner/repository");
|
|
28
26
|
}
|
|
29
|
-
const protectedSource =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
parents: exactParents(candidateCommit?.parents, "candidate source parents"),
|
|
38
|
-
};
|
|
27
|
+
const [protectedSource, candidateSource] = [
|
|
28
|
+
["protected", protectedCommit],
|
|
29
|
+
["candidate", candidateCommit],
|
|
30
|
+
].map(([kind, commit]) => ({
|
|
31
|
+
sha: exactSha(commit?.sha, `${kind} source SHA`),
|
|
32
|
+
tree: exactSha(commit?.tree, `${kind} source tree`),
|
|
33
|
+
parents: exactParents(commit?.parents, `${kind} source parents`),
|
|
34
|
+
}));
|
|
39
35
|
if (protectedSource.tree !== candidateSource.tree) {
|
|
40
36
|
throw new Error(
|
|
41
37
|
"protected publication source tree does not match the qualified candidate tree",
|
|
@@ -45,13 +41,13 @@ export function bindV4ProtectedPublicationSource({
|
|
|
45
41
|
let mode = "exact-commit";
|
|
46
42
|
let pullRequestNumber = null;
|
|
47
43
|
if (protectedSource.sha !== candidateSource.sha) {
|
|
48
|
-
mode = "merge-equivalent";
|
|
49
44
|
const sameParents =
|
|
50
|
-
protectedSource.parents.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
45
|
+
protectedSource.parents.join(",") === candidateSource.parents.join(",");
|
|
46
|
+
const squashParents =
|
|
47
|
+
protectedSource.parents.length === 1 &&
|
|
48
|
+
candidateSource.parents.length === 2 &&
|
|
49
|
+
protectedSource.parents[0] === candidateSource.parents[0];
|
|
50
|
+
if (!sameParents && !squashParents) {
|
|
55
51
|
throw new Error(
|
|
56
52
|
"protected publication source is not parent-equivalent to the qualified merge candidate",
|
|
57
53
|
);
|
|
@@ -70,12 +66,14 @@ export function bindV4ProtectedPublicationSource({
|
|
|
70
66
|
pullRequestNumber <= 0 ||
|
|
71
67
|
pullRequest?.merged !== true ||
|
|
72
68
|
pullRequestMerge !== protectedSource.sha ||
|
|
73
|
-
!candidateSource.parents.includes(pullRequestHead)
|
|
69
|
+
!candidateSource.parents.includes(pullRequestHead) ||
|
|
70
|
+
(squashParents && candidateSource.parents[1] !== pullRequestHead)
|
|
74
71
|
) {
|
|
75
72
|
throw new Error(
|
|
76
73
|
"protected publication source does not match the merged pull request and qualified merge candidate",
|
|
77
74
|
);
|
|
78
75
|
}
|
|
76
|
+
mode = sameParents ? "merge-equivalent" : "squash-equivalent";
|
|
79
77
|
}
|
|
80
78
|
|
|
81
79
|
const binding = {
|