@kungfu-tech/buildchain 4.0.2-alpha.44 → 4.0.2-alpha.45
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/maintainability-debt.json +18 -19
- package/architecture/maintainability-policy.json +4 -4
- package/architecture/v4-release-topology.json +9 -6
- package/architecture/v4-universal-workflow-train-admission.json +1 -1
- package/dist/site/buildchain-contract.json +7 -7
- package/dist/site/buildchain-site.json +47 -11
- package/dist/site/capability-registry.json +2 -2
- package/dist/site/kfd-claims.json +29 -5
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +2 -2
- package/dist/site/node-api-registry.json +142 -1
- package/dist/site/page-registry.json +41 -5
- package/dist/site/public-surface-audit.json +7 -3
- package/dist/site/publication-authority-registry.json +5 -17
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-provenance.json +2 -1
- package/dist/site/site-manifest.json +6 -6
- package/dist/site/workflow-registry.json +5 -5
- package/docs/MAP.md +1 -0
- package/docs/node-api-reference.md +11 -0
- package/docs/oci-publication.md +82 -0
- package/package.json +3 -2
- package/packages/core/buildchain-v4-domain.wasm +0 -0
- package/packages/core/oci-publication-bundle.js +241 -0
- package/packages/core/release-tail-product-capabilities.js +9 -0
- package/packages/core/v4-canonical-contracts.js +1 -0
- package/packages/core/v4-domain-wasm-artifact.js +2 -2
- package/scripts/check-v4-release-topology.mjs +14 -4
- package/scripts/generate-channel-promotion-workflow.mjs +2 -19
- package/scripts/generate-v4-universal-workflow-facades.mjs +8 -2
- package/scripts/publication-candidate-kind.mjs +92 -0
- package/scripts/publication-candidate-sealer.mjs +9 -0
- package/scripts/release-candidate-resolver.mjs +6 -17
- package/scripts/resume-from-candidate-run.mjs +10 -17
- package/scripts/site-capability-metadata.mjs +1 -0
- package/scripts/v4-product-publication-intent.mjs +1 -1
- package/scripts/v4-universal-workflow-engine.mjs +2 -0
|
@@ -316,16 +316,7 @@ ${secrets.trimEnd()}
|
|
|
316
316
|
outputs:
|
|
317
317
|
${publicOutputs(outputs)}
|
|
318
318
|
|
|
319
|
-
|
|
320
|
-
actions: write
|
|
321
|
-
artifact-metadata: write
|
|
322
|
-
attestations: write
|
|
323
|
-
checks: write
|
|
324
|
-
contents: write
|
|
325
|
-
id-token: write
|
|
326
|
-
issues: write
|
|
327
|
-
pull-requests: write
|
|
328
|
-
|
|
319
|
+
# Provider authority is inherited from the explicit caller envelope.
|
|
329
320
|
jobs:
|
|
330
321
|
resolve-promotion:
|
|
331
322
|
name: Resolve promotion workflow shell and runtime
|
|
@@ -503,15 +494,7 @@ ${consumerAdmissionJob()}
|
|
|
503
494
|
name: Invoke the single v4 publisher adapter
|
|
504
495
|
needs: [resolve-promotion, consumer-admission]
|
|
505
496
|
uses: kungfu-systems/buildchain/${alphaRoute.workflowPath}@${alphaRoute.callRef}
|
|
506
|
-
|
|
507
|
-
actions: write
|
|
508
|
-
artifact-metadata: write
|
|
509
|
-
attestations: write
|
|
510
|
-
checks: write
|
|
511
|
-
contents: write
|
|
512
|
-
id-token: write
|
|
513
|
-
issues: write
|
|
514
|
-
pull-requests: write
|
|
497
|
+
# Provider authority is inherited from the explicit caller envelope.
|
|
515
498
|
with:
|
|
516
499
|
${invokeForwarded}
|
|
517
500
|
secrets: inherit
|
|
@@ -216,11 +216,17 @@ function applyPublicationFacadePatches(source, relative) {
|
|
|
216
216
|
return source;
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
+
function inheritPublicationProviderAuthority(source, relative) {
|
|
220
|
+
if (relative !== ".github/workflows/.release-candidate-promote.yml") return source;
|
|
221
|
+
return source.replace("permissions:\n contents: read\n", "# Provider authority is inherited from the explicit caller envelope.\n")
|
|
222
|
+
.replace(" permissions:\n actions: read\n checks: write\n contents: write\n id-token: write\n pull-requests: write\n", " # Provider authority is inherited from the explicit caller envelope.\n");
|
|
223
|
+
}
|
|
224
|
+
|
|
219
225
|
export function migrateV4UniversalWorkflowFacade(source, relative) {
|
|
220
|
-
return rewriteRepositoryWorkflowPaths(root, applyPublicationFacadePatches(guardCompatibilityJobs(
|
|
226
|
+
return rewriteRepositoryWorkflowPaths(root, inheritPublicationProviderAuthority(applyPublicationFacadePatches(guardCompatibilityJobs(
|
|
221
227
|
addUniversalInput(addRuntimeBootstrapDependencies(source, relative), relative),
|
|
222
228
|
relative,
|
|
223
|
-
), relative));
|
|
229
|
+
), relative), relative));
|
|
224
230
|
}
|
|
225
231
|
|
|
226
232
|
function verify(source, relative) {
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { verifyOciPublicationBundle } from "../packages/core/oci-publication-bundle.js";
|
|
4
|
+
|
|
5
|
+
export function resolveOciCandidate({ payloadRoot, passport }) {
|
|
6
|
+
const matches = [];
|
|
7
|
+
function visit(directory) {
|
|
8
|
+
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
9
|
+
if (entry.isSymbolicLink())
|
|
10
|
+
throw new Error("OCI candidate cannot contain symlinks");
|
|
11
|
+
const file = path.join(directory, entry.name);
|
|
12
|
+
if (entry.isDirectory()) visit(file);
|
|
13
|
+
else if (entry.name === "oci-family.json") matches.push(file);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
visit(payloadRoot);
|
|
17
|
+
if (matches.length !== 1)
|
|
18
|
+
throw new Error("OCI candidate requires exactly one sealed image family");
|
|
19
|
+
const manifest = JSON.parse(fs.readFileSync(matches[0]));
|
|
20
|
+
const bundleRoot = path.dirname(matches[0]);
|
|
21
|
+
const verified = verifyOciPublicationBundle({
|
|
22
|
+
bundleRoot,
|
|
23
|
+
manifest,
|
|
24
|
+
repository: passport.repository,
|
|
25
|
+
sourceSha: passport.source.headSha,
|
|
26
|
+
version: passport.target.version,
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
root: bundleRoot,
|
|
30
|
+
manifest: verified.manifest,
|
|
31
|
+
requiredArtifacts: manifest.images.map((image) => ({
|
|
32
|
+
kind: "oci",
|
|
33
|
+
name: image.repository,
|
|
34
|
+
ref: `v${manifest.version}`,
|
|
35
|
+
digest: image.digest,
|
|
36
|
+
platform: image.platform,
|
|
37
|
+
required: true,
|
|
38
|
+
})),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function resolveRecoveredPublicationVersion({
|
|
43
|
+
artifactVersion,
|
|
44
|
+
channel,
|
|
45
|
+
rematerializeOnResume = false,
|
|
46
|
+
} = {}) {
|
|
47
|
+
const version = String(artifactVersion || "").trim(),
|
|
48
|
+
match = version.match(
|
|
49
|
+
/^(\d+\.\d+\.\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u,
|
|
50
|
+
);
|
|
51
|
+
if (!match)
|
|
52
|
+
throw new Error(
|
|
53
|
+
`recovered npm artifact has invalid publication version: ${version || "<empty>"}`,
|
|
54
|
+
);
|
|
55
|
+
return channel === "release" && rematerializeOnResume ? match[1] : version;
|
|
56
|
+
}
|
|
57
|
+
export function resolveRecoveredCandidateVersion({
|
|
58
|
+
artifactVersion,
|
|
59
|
+
publicationVersion,
|
|
60
|
+
channel,
|
|
61
|
+
rematerializeOnResume = false,
|
|
62
|
+
targetRef = "",
|
|
63
|
+
candidateRef = "",
|
|
64
|
+
} = {}) {
|
|
65
|
+
const version = String(artifactVersion || "").trim(),
|
|
66
|
+
target = String(targetRef || "").replace(/^refs\/heads\//u, ""),
|
|
67
|
+
candidate = String(candidateRef || "").replace(/^refs\/heads\//u, "");
|
|
68
|
+
if (channel !== "release" || !rematerializeOnResume) return version;
|
|
69
|
+
const prefix = `publish-gate/${target}/`;
|
|
70
|
+
if (!target || !candidate.startsWith(prefix))
|
|
71
|
+
throw new Error(
|
|
72
|
+
`stable recovery candidate ref must descend from ${prefix || "publish-gate/<target>/"}`,
|
|
73
|
+
);
|
|
74
|
+
const candidateVersion = candidate.slice(prefix.length);
|
|
75
|
+
if (!/^\d+\.\d+\.\d+-alpha\.\d+$/u.test(candidateVersion))
|
|
76
|
+
throw new Error(
|
|
77
|
+
`stable recovery candidate ref must bind an exact alpha version, got ${candidateVersion || "<empty>"}`,
|
|
78
|
+
);
|
|
79
|
+
if (candidateVersion.replace(/-alpha\.\d+$/u, "") !== publicationVersion)
|
|
80
|
+
throw new Error(
|
|
81
|
+
`stable recovery candidate ${candidateVersion} does not match publication ${publicationVersion || "<empty>"}`,
|
|
82
|
+
);
|
|
83
|
+
if (
|
|
84
|
+
(version.match(
|
|
85
|
+
/^(\d+\.\d+\.\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u,
|
|
86
|
+
)?.[1] || "") !== publicationVersion
|
|
87
|
+
)
|
|
88
|
+
throw new Error(
|
|
89
|
+
`recovered npm artifact version ${version || "<empty>"} does not match publication ${publicationVersion}`,
|
|
90
|
+
);
|
|
91
|
+
return candidateVersion;
|
|
92
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveOciCandidate } from "./publication-candidate-kind.mjs";
|
|
1
2
|
import crypto from "node:crypto";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
@@ -102,3 +103,11 @@ export function createResolvedPublicationSealedBundle({
|
|
|
102
103
|
});
|
|
103
104
|
return { root: resolvedRoot, manifest, npmArtifacts: resolvedNpmArtifacts, files };
|
|
104
105
|
}
|
|
106
|
+
|
|
107
|
+
export function resolveCandidatePublicationBundle({ kind, payloadDir, passport, runtimeSha, npmArtifacts, releaseAssetPaths }) {
|
|
108
|
+
if (kind === "oci") return resolveOciCandidate({ payloadRoot: payloadDir, passport });
|
|
109
|
+
if (kind !== "npm") return undefined;
|
|
110
|
+
return createResolvedPublicationSealedBundle({ bundleRoot: payloadDir, repository: passport.repository,
|
|
111
|
+
sourceSha: passport.source?.headSha, sourceTreeSha: passport.source?.treeHash,
|
|
112
|
+
runtimeSha, releaseCandidateRoot: passport.candidateHash, npmArtifacts, releaseAssetPaths });
|
|
113
|
+
}
|
|
@@ -7,7 +7,7 @@ import { execFileSync } from "node:child_process";
|
|
|
7
7
|
import { Readable } from "node:stream";
|
|
8
8
|
import { pipeline } from "node:stream/promises";
|
|
9
9
|
import { pathToFileURL } from "node:url";
|
|
10
|
-
import {
|
|
10
|
+
import { resolveCandidatePublicationBundle } from "./publication-candidate-sealer.mjs";
|
|
11
11
|
import { writeGitHubOutputs } from "./build-contract-core.mjs";
|
|
12
12
|
import { v4ContentRoot } from "../packages/core/v4-canonical-contracts.js";
|
|
13
13
|
import { v4PublicationQualificationRoot, validateV4PublicationQualificationReceipt } from "../packages/core/v4-publication-qualification.js";
|
|
@@ -725,23 +725,12 @@ export async function resolveReleaseCandidateArtifacts({
|
|
|
725
725
|
const noun = publishArtifactKind === "npm" ? "npm package tarballs" : "platform manifests";
|
|
726
726
|
throw new Error(`expected at least ${minimumPayloadCount} downloaded ${noun}, found ${downloadedRequiredArtifactCount}`);
|
|
727
727
|
}
|
|
728
|
-
const sealedBundle = publishArtifactKind
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
sourceSha: passport.source?.headSha,
|
|
733
|
-
sourceTreeSha: passport.source?.treeHash,
|
|
734
|
-
runtimeSha: releaseCandidateRuntimeSha(passport),
|
|
735
|
-
releaseCandidateRoot: passport.candidateHash,
|
|
736
|
-
npmArtifacts: npmTarballPaths.map((tarballPath) => ({
|
|
737
|
-
path: tarballPath,
|
|
738
|
-
...readNpmPackageArtifact({ tarballPath, mainPackage: publishPackageMain }),
|
|
739
|
-
})),
|
|
740
|
-
releaseAssetPaths,
|
|
741
|
-
})
|
|
742
|
-
: undefined;
|
|
728
|
+
const sealedBundle = resolveCandidatePublicationBundle({ kind: publishArtifactKind, payloadDir, passport,
|
|
729
|
+
runtimeSha: releaseCandidateRuntimeSha(passport), releaseAssetPaths,
|
|
730
|
+
npmArtifacts: npmTarballPaths.map((tarballPath) => ({ path: tarballPath,
|
|
731
|
+
...readNpmPackageArtifact({ tarballPath, mainPackage: publishPackageMain }) })) });
|
|
743
732
|
const manifests = platformManifestPaths.map((manifestPath) => JSON.parse(fs.readFileSync(manifestPath, "utf8"))), publicationVersion = resolveFreshPublicationVersion({ sealedBundle, candidateVersion: passport.target?.version });
|
|
744
|
-
const generatedRequiredArtifacts = generatePublishRequiredArtifacts({
|
|
733
|
+
const generatedRequiredArtifacts = sealedBundle?.requiredArtifacts || generatePublishRequiredArtifacts({
|
|
745
734
|
manifests,
|
|
746
735
|
version: publicationVersion,
|
|
747
736
|
kind: publishArtifactKind,
|
|
@@ -6,6 +6,8 @@ import path from "node:path";
|
|
|
6
6
|
import { execFileSync } from "node:child_process";
|
|
7
7
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
8
8
|
|
|
9
|
+
import { resolveOciCandidate, resolveRecoveredPublicationVersion, resolveRecoveredCandidateVersion } from "./publication-candidate-kind.mjs";
|
|
10
|
+
export { resolveRecoveredPublicationVersion, resolveRecoveredCandidateVersion } from "./publication-candidate-kind.mjs";
|
|
9
11
|
import { writeGitHubOutputs } from "./build-contract-core.mjs";
|
|
10
12
|
import { compareSemver } from "./publication-registry-hydrate.mjs";
|
|
11
13
|
import { normalizeAnchorProvenance, normalizeCandidateRun, recoverCandidateProvenance } from "./release-candidate-anchor-provenance.mjs";
|
|
@@ -695,22 +697,6 @@ export function createRecoveredPublicationCandidate({
|
|
|
695
697
|
};
|
|
696
698
|
return { ...payload, candidateDigest: publicationArtifactCandidateDigest(payload) };
|
|
697
699
|
}
|
|
698
|
-
export function resolveRecoveredPublicationVersion({ artifactVersion, channel, rematerializeOnResume = false } = {}) {
|
|
699
|
-
const version = String(artifactVersion || "").trim(), match = version.match(/^(\d+\.\d+\.\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u);
|
|
700
|
-
if (!match) throw new Error(`recovered npm artifact has invalid publication version: ${version || "<empty>"}`);
|
|
701
|
-
return channel === "release" && rematerializeOnResume ? match[1] : version;
|
|
702
|
-
}
|
|
703
|
-
export function resolveRecoveredCandidateVersion({ artifactVersion, publicationVersion, channel, rematerializeOnResume = false, targetRef = "", candidateRef = "" } = {}) {
|
|
704
|
-
const version = String(artifactVersion || "").trim(), target = String(targetRef || "").replace(/^refs\/heads\//u, ""), candidate = String(candidateRef || "").replace(/^refs\/heads\//u, "");
|
|
705
|
-
if (channel !== "release" || !rematerializeOnResume) return version;
|
|
706
|
-
const prefix = `publish-gate/${target}/`;
|
|
707
|
-
if (!target || !candidate.startsWith(prefix)) throw new Error(`stable recovery candidate ref must descend from ${prefix || "publish-gate/<target>/"}`);
|
|
708
|
-
const candidateVersion = candidate.slice(prefix.length);
|
|
709
|
-
if (!/^\d+\.\d+\.\d+-alpha\.\d+$/u.test(candidateVersion)) throw new Error(`stable recovery candidate ref must bind an exact alpha version, got ${candidateVersion || "<empty>"}`);
|
|
710
|
-
if (candidateVersion.replace(/-alpha\.\d+$/u, "") !== publicationVersion) throw new Error(`stable recovery candidate ${candidateVersion} does not match publication ${publicationVersion || "<empty>"}`);
|
|
711
|
-
if ((version.match(/^(\d+\.\d+\.\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u)?.[1] || "") !== publicationVersion) throw new Error(`recovered npm artifact version ${version || "<empty>"} does not match publication ${publicationVersion}`);
|
|
712
|
-
return candidateVersion;
|
|
713
|
-
}
|
|
714
700
|
export function createRecoveredPublication({ downloads, bundleRoot, repository, passport, candidateRuntimeSha, publishArtifactKind, publishPackageMain, releasePatterns, platformManifests, channel, targetRef = "", candidateRef = "", rematerializeOnResume = false }) {
|
|
715
701
|
const allFiles = downloads.flatMap((download) => download.files.map((file) => ({ path: path.relative(bundleRoot, file.absolutePath).split(path.sep).join("/"),
|
|
716
702
|
size: file.size, sha256: file.sha256.replace(/^sha256:/, ""), absolutePath: file.absolutePath })))
|
|
@@ -718,6 +704,13 @@ export function createRecoveredPublication({ downloads, bundleRoot, repository,
|
|
|
718
704
|
const kind = String(publishArtifactKind || "npm");
|
|
719
705
|
const releaseMatchers = splitPatterns(releasePatterns).map(patternMatcher);
|
|
720
706
|
const releaseAssets = allFiles.filter((file) => releaseMatchers.some((matcher) => matcher.test(path.basename(file.path))));
|
|
707
|
+
if (kind === "oci") {
|
|
708
|
+
createRecoveredPublicationCandidate({ allFiles, repository, passport, candidateRuntimeSha });
|
|
709
|
+
const sealed = resolveOciCandidate({ payloadRoot: bundleRoot, passport });
|
|
710
|
+
return { manifest: sealed.manifest, bundleRoot: sealed.root, npmArtifacts: [], allFiles, releaseAssets,
|
|
711
|
+
version: sealed.manifest.version, candidateVersion: sealed.manifest.version,
|
|
712
|
+
publishRequiredArtifacts: sealed.requiredArtifacts };
|
|
713
|
+
}
|
|
721
714
|
if (kind !== "npm") {
|
|
722
715
|
createRecoveredPublicationCandidate({ allFiles, repository, passport, candidateRuntimeSha });
|
|
723
716
|
const version = String(passport.target?.version || "").trim();
|
|
@@ -1019,7 +1012,7 @@ export async function resumeFromCandidateRun({
|
|
|
1019
1012
|
npmTarballs: tarballs,
|
|
1020
1013
|
releaseAssets: publication.releaseAssets.map((asset) => outputPath(asset.absolutePath)),
|
|
1021
1014
|
publishRequiredArtifacts: outputPath(requiredArtifactsPath),
|
|
1022
|
-
sealedBundleRoot: publication.manifest ? outputPath(bundleRoot) : "",
|
|
1015
|
+
sealedBundleRoot: publication.manifest ? outputPath(publication.bundleRoot || bundleRoot) : "",
|
|
1023
1016
|
sealedBundleManifest: publication.manifest ? outputPath(sealedManifestPath) : "",
|
|
1024
1017
|
recoveryReceipt: outputPath(recoveryReceiptPath),
|
|
1025
1018
|
stageCapsules: stageCapsuleFile ? outputPath(stageCapsuleFile.absolutePath) : "",
|
|
@@ -206,6 +206,7 @@ export function nodeApiMeta(exportName) {
|
|
|
206
206
|
"./publication-artifact": { group: "reusable-build", summary: "Publication artifact manifest, source bundle, and publication passport APIs." },
|
|
207
207
|
"./publication-package": { group: "reusable-build", summary: "Publication npm package synthesis APIs for Buildchain-managed paper release presets." },
|
|
208
208
|
"./publication-reproducibility": { group: "reusable-build", summary: "Two-clean-build publication byte reproducibility receipt APIs." },
|
|
209
|
+
"./oci-publication": { group: "reusable-build", summary: "Sealed OCI image family verification, provenance, and smoke evidence APIs." },
|
|
209
210
|
"./publication-sealed-bundle": { group: "reusable-build", summary: "Build-once publication bundle manifests and exact-byte resume verification APIs." },
|
|
210
211
|
"./paper": { group: "reusable-build", summary: "Unified Paper work, fleet, scaffold, preflight, npm bootstrap, build, Alpha, status, and resume planning APIs." },
|
|
211
212
|
"./publication-authority": { group: "release-passport-trust", summary: "Sealed publication authority registry, runner provenance, control-plane audit, admission, and independent verification APIs." },
|
|
@@ -65,7 +65,7 @@ export function resolveV4ProductPublicationIntent() {
|
|
|
65
65
|
const sourceSha = env("BUILDCHAIN_SOURCE_SHA", true);
|
|
66
66
|
const manifestPath = env(
|
|
67
67
|
"BUILDCHAIN_SEALED_BUNDLE_MANIFEST",
|
|
68
|
-
artifactKind
|
|
68
|
+
artifactKind !== "custom",
|
|
69
69
|
);
|
|
70
70
|
const manifest = manifestPath ? readJson(manifestPath) : null;
|
|
71
71
|
const requiredArtifacts = readJson(
|
|
@@ -306,6 +306,7 @@ async function materializeProductPublicationIntent({
|
|
|
306
306
|
BUILDCHAIN_SEALED_BUNDLE_MANIFEST: candidate.paths.sealedBundleManifest,
|
|
307
307
|
BUILDCHAIN_REQUIRED_ARTIFACTS_PATH:
|
|
308
308
|
candidate.paths.publishRequiredArtifacts,
|
|
309
|
+
BUILDCHAIN_PUBLISH_ARTIFACT_KIND: inputs["publish-artifact-kind"] || "npm",
|
|
309
310
|
BUILDCHAIN_PUBLISH_PACKAGE_MAIN: inputs["publish-package-main"] || "",
|
|
310
311
|
BUILDCHAIN_PUBLISH_DIST_TAG: inputs["publish-dist-tag"] || "",
|
|
311
312
|
BUILDCHAIN_PRODUCT_PUBLICATION_INTENT_PATH: intentPath,
|
|
@@ -449,6 +450,7 @@ async function executeReleasePromotion(request, admission) {
|
|
|
449
450
|
"candidate-build-summary-path": candidate.paths.buildSummary,
|
|
450
451
|
"stage-capsules-path": candidate.paths.stageCapsules,
|
|
451
452
|
"publication-qualification-path": candidate.paths.publicationQualification,
|
|
453
|
+
"publish-artifact-kind": payload.inputs["publish-artifact-kind"] || "npm",
|
|
452
454
|
"sealed-bundle-root": candidate.paths.sealedBundleRoot,
|
|
453
455
|
"sealed-bundle-manifest": candidate.paths.sealedBundleManifest,
|
|
454
456
|
"required-artifacts-path": candidate.paths.publishRequiredArtifacts,
|