@rightkit/git 0.2.22 → 0.2.24
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/cli/right-git.mjs +0 -0
- package/install.mjs +1 -1
- package/manifest.mjs +286 -52
- package/manifest.schema.json +19 -3
- package/manifest.test.mjs +108 -1
- package/package.json +6 -5
- package/render.test.mjs +258 -25
- package/sync.test.mjs +3 -0
- package/templates/profiles/rust-hybrid/ci.yml +10 -4
- package/templates/profiles/rust-hybrid/release-candidate.yml +105 -7
- package/uninstall.test.mjs +2 -2
package/cli/right-git.mjs
CHANGED
|
File without changes
|
package/install.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import { applyPlan, planSync } from "./sync.mjs";
|
|
|
13
13
|
|
|
14
14
|
export const DEFAULT_MATRIX = { os: ["ubuntu-latest", "macos-latest", "windows-latest"], node: ["22.13", "24"] };
|
|
15
15
|
export const DEFAULT_PACKAGE_MANAGER = "pnpm@11.24.0";
|
|
16
|
-
export const DEFAULT_TEMPLATE_VERSION = "1.
|
|
16
|
+
export const DEFAULT_TEMPLATE_VERSION = "1.8.0";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* opts: { lanes: string[], matrix?, packageManager?, templateVersion?,
|
package/manifest.mjs
CHANGED
|
@@ -167,7 +167,7 @@ export function validateManifest(manifest) {
|
|
|
167
167
|
errors.push("rustCache must be an object");
|
|
168
168
|
} else {
|
|
169
169
|
for (const key of Object.keys(rustCache)) {
|
|
170
|
-
if (key !== "workspaces") errors.push(`unknown rustCache field: ${key}`);
|
|
170
|
+
if (key !== "workspaces" && key !== "requiredForGate") errors.push(`unknown rustCache field: ${key}`);
|
|
171
171
|
}
|
|
172
172
|
if (!Array.isArray(rustCache.workspaces) || rustCache.workspaces.length === 0) {
|
|
173
173
|
errors.push("rustCache.workspaces must be a non-empty array");
|
|
@@ -176,6 +176,9 @@ export function validateManifest(manifest) {
|
|
|
176
176
|
} else if (new Set(rustCache.workspaces).size !== rustCache.workspaces.length) {
|
|
177
177
|
errors.push("rustCache.workspaces entries must be unique");
|
|
178
178
|
}
|
|
179
|
+
if (rustCache.requiredForGate !== undefined && typeof rustCache.requiredForGate !== "boolean") {
|
|
180
|
+
errors.push("rustCache.requiredForGate must be a boolean");
|
|
181
|
+
}
|
|
179
182
|
}
|
|
180
183
|
}
|
|
181
184
|
|
|
@@ -185,9 +188,17 @@ export function validateManifest(manifest) {
|
|
|
185
188
|
errors.push("candidate must be an object");
|
|
186
189
|
} else {
|
|
187
190
|
for (const key of Object.keys(candidate)) {
|
|
188
|
-
if (!["buildScript", "checkScript", "artifactRoot", "os", "targets", "signWindows", "signMacos", "releaseChain"].includes(key)) errors.push(`unknown candidate field: ${key}`);
|
|
191
|
+
if (!["buildScript", "checkScript", "admissionScript", "stageSummaryScript", "artifactRoot", "os", "targets", "signWindows", "signMacos", "releaseChain"].includes(key)) errors.push(`unknown candidate field: ${key}`);
|
|
189
192
|
}
|
|
190
|
-
|
|
193
|
+
// admissionScript & stageSummaryScript are required for EVERY release-candidate
|
|
194
|
+
// lane, not just signed/full-releaseChain ones: the tag-last workflow's
|
|
195
|
+
// `admission` job (dispatch-envelope validation) and the `candidate` job's
|
|
196
|
+
// stage-summary init/finalize steps are unconditional parts of the rendered
|
|
197
|
+
// template, independent of candidate.signWindows/signMacos/releaseChain. If
|
|
198
|
+
// either script were only required inside the optional releaseChain object,
|
|
199
|
+
// an unsigned release-candidate manifest (no releaseChain at all) would still
|
|
200
|
+
// render those unconditional steps with an unresolved script name.
|
|
201
|
+
for (const key of ["buildScript", "checkScript", "admissionScript", "stageSummaryScript"]) {
|
|
191
202
|
if (typeof candidate[key] !== "string" || !PACKAGE_SCRIPT_RE.test(candidate[key])) {
|
|
192
203
|
errors.push(`candidate.${key} must be one safe package script name`);
|
|
193
204
|
}
|
|
@@ -249,14 +260,18 @@ export function validateManifest(manifest) {
|
|
|
249
260
|
}
|
|
250
261
|
if (candidate.releaseChain !== undefined) {
|
|
251
262
|
const chain = candidate.releaseChain;
|
|
252
|
-
|
|
263
|
+
// admissionScript & stageSummaryScript live on candidate directly (see
|
|
264
|
+
// above) — the full signed release chain adds evidenceVerificationScript
|
|
265
|
+
// (runs before publish, verifying aggregated same-run evidence) plus the
|
|
266
|
+
// finalize/qualify/publish scripts.
|
|
267
|
+
const allowedChainKeys = ["evidenceVerificationScript", "windowsFinalizeScript", "macosFinalizeScript", "installedQualificationScript", "publishScript", "qualificationRunnerVariable", "publishSecrets"];
|
|
253
268
|
if (chain === null || typeof chain !== "object" || Array.isArray(chain)) {
|
|
254
269
|
errors.push("candidate.releaseChain must be an object");
|
|
255
270
|
} else {
|
|
256
271
|
for (const key of Object.keys(chain)) {
|
|
257
272
|
if (!allowedChainKeys.includes(key)) errors.push(`unknown candidate.releaseChain field: ${key}`);
|
|
258
273
|
}
|
|
259
|
-
for (const key of ["windowsFinalizeScript", "installedQualificationScript", "publishScript"]) {
|
|
274
|
+
for (const key of ["evidenceVerificationScript", "windowsFinalizeScript", "installedQualificationScript", "publishScript"]) {
|
|
260
275
|
if (typeof chain[key] !== "string" || !PACKAGE_SCRIPT_RE.test(chain[key])) {
|
|
261
276
|
errors.push(`candidate.releaseChain.${key} must be one safe package script name`);
|
|
262
277
|
}
|
|
@@ -459,7 +474,7 @@ function windowsSigningJob(manifest, pm, artifactPrefix) {
|
|
|
459
474
|
const finalizeEnvironment = releaseChain
|
|
460
475
|
? ` RIGHT_GIT_UNSIGNED_CANDIDATE_ROOT: \${{ runner.temp }}/unsigned-windows-candidate
|
|
461
476
|
RIGHT_GIT_FINALIZED_WINDOWS_ROOT: \${{ runner.temp }}/finalized-windows
|
|
462
|
-
RIGHT_GIT_SOURCE_REVISION: \${{
|
|
477
|
+
RIGHT_GIT_SOURCE_REVISION: \${{ needs.admission.outputs.source_revision }}`
|
|
463
478
|
: ` LEGION_UNSIGNED_CANDIDATE_ROOT: \${{ runner.temp }}/unsigned-windows-candidate
|
|
464
479
|
LEGION_SOURCE_REVISION: \${{ env.RIGHT_GIT_SOURCE_REVISION }}`;
|
|
465
480
|
const uploadPath = releaseChain
|
|
@@ -467,8 +482,8 @@ function windowsSigningJob(manifest, pm, artifactPrefix) {
|
|
|
467
482
|
: " dist/releases/windows/**\n .right-release/receipts/windows-*.json";
|
|
468
483
|
return `
|
|
469
484
|
windows-sign:
|
|
470
|
-
needs: [candidate]
|
|
471
|
-
if: \${{
|
|
485
|
+
needs: [admission, candidate]
|
|
486
|
+
if: \${{ needs.admission.outputs.signed_qualification == 'true' }}
|
|
472
487
|
environment: release
|
|
473
488
|
strategy:
|
|
474
489
|
fail-fast: false
|
|
@@ -480,9 +495,9 @@ ${signingMatrix(manifest, "windows")}
|
|
|
480
495
|
id-token: write
|
|
481
496
|
steps:
|
|
482
497
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
498
|
+
with:
|
|
499
|
+
ref: \${{ needs.admission.outputs.source_revision }}
|
|
500
|
+
persist-credentials: false
|
|
486
501
|
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
487
502
|
with:
|
|
488
503
|
node-version: ${nodeVersion}
|
|
@@ -492,10 +507,24 @@ ${pm.setup}
|
|
|
492
507
|
with:
|
|
493
508
|
targets: \${{ matrix.targetTriple }}
|
|
494
509
|
- run: ${pm.installCommand}
|
|
510
|
+
- name: Initialize Windows signing stage summary
|
|
511
|
+
run: ${pm.runPrefix} ${manifest.candidate.stageSummaryScript}
|
|
512
|
+
env:
|
|
513
|
+
RIGHT_GIT_STAGE_ACTION: init
|
|
514
|
+
RIGHT_GIT_STAGE_ROOT: \${{ runner.temp }}/right-git-stage-summary
|
|
515
|
+
RIGHT_GIT_STAGE_EVIDENCE_ROOT: \${{ runner.temp }}/finalized-windows
|
|
516
|
+
RIGHT_GIT_STAGE: windows-sign
|
|
517
|
+
RIGHT_GIT_STAGE_PRODUCER: windows-sign-\${{ matrix.architecture }}
|
|
518
|
+
RIGHT_GIT_RELEASE_VERSION: \${{ needs.admission.outputs.version }}
|
|
519
|
+
RIGHT_GIT_SOURCE_REVISION: \${{ needs.admission.outputs.source_revision }}
|
|
520
|
+
RIGHT_GIT_RELEASE_PLATFORM: \${{ matrix.platform }}
|
|
521
|
+
RIGHT_GIT_RELEASE_ARCHITECTURE: \${{ matrix.architecture }}
|
|
522
|
+
RIGHT_GIT_RUN_ID: \${{ github.run_id }}
|
|
523
|
+
RIGHT_GIT_RUN_ATTEMPT: \${{ github.run_attempt }}
|
|
495
524
|
- name: Download exact unsigned Windows candidate
|
|
496
525
|
uses: actions/download-artifact@${DOWNLOAD_ARTIFACT_SHA} # v4.3.0
|
|
497
526
|
with:
|
|
498
|
-
name: ${artifactPrefix}-
|
|
527
|
+
name: ${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-candidate-\${{ matrix.platform }}-\${{ matrix.architecture }}-\${{ needs.admission.outputs.version }}-\${{ needs.admission.outputs.source_revision }}
|
|
499
528
|
path: \${{ runner.temp }}/unsigned-windows-candidate
|
|
500
529
|
- name: Authenticate to Azure with GitHub OIDC
|
|
501
530
|
uses: azure/login@${AZURE_LOGIN_SHA} # v3
|
|
@@ -528,13 +557,38 @@ ${finalizeEnvironment}
|
|
|
528
557
|
AZURE_ARTIFACT_SIGNING_ENDPOINT: \${{ vars.AZURE_ARTIFACT_SIGNING_ENDPOINT }}
|
|
529
558
|
AZURE_ARTIFACT_SIGNING_ACCOUNT: \${{ vars.AZURE_ARTIFACT_SIGNING_ACCOUNT }}
|
|
530
559
|
AZURE_ARTIFACT_SIGNING_PROFILE: \${{ vars.AZURE_ARTIFACT_SIGNING_PROFILE }}
|
|
560
|
+
- name: Finalize Windows signing stage summary
|
|
561
|
+
if: \${{ always() }}
|
|
562
|
+
run: ${pm.runPrefix} ${manifest.candidate.stageSummaryScript}
|
|
563
|
+
env:
|
|
564
|
+
RIGHT_GIT_STAGE_ACTION: finalize
|
|
565
|
+
RIGHT_GIT_STAGE_ROOT: \${{ runner.temp }}/right-git-stage-summary
|
|
566
|
+
RIGHT_GIT_STAGE_EVIDENCE_ROOT: \${{ runner.temp }}/finalized-windows
|
|
567
|
+
RIGHT_GIT_STAGE: windows-sign
|
|
568
|
+
RIGHT_GIT_STAGE_PRODUCER: windows-sign-\${{ matrix.architecture }}
|
|
569
|
+
RIGHT_GIT_STAGE_STATUS: \${{ job.status == 'success' && 'SUCCEEDED' || 'FAILED' }}
|
|
570
|
+
RIGHT_GIT_STAGE_EXIT_CODE: \${{ job.status == 'success' && '0' || '1' }}
|
|
571
|
+
RIGHT_GIT_RELEASE_VERSION: \${{ needs.admission.outputs.version }}
|
|
572
|
+
RIGHT_GIT_SOURCE_REVISION: \${{ needs.admission.outputs.source_revision }}
|
|
573
|
+
RIGHT_GIT_RELEASE_PLATFORM: \${{ matrix.platform }}
|
|
574
|
+
RIGHT_GIT_RELEASE_ARCHITECTURE: \${{ matrix.architecture }}
|
|
575
|
+
RIGHT_GIT_RUN_ID: \${{ github.run_id }}
|
|
576
|
+
RIGHT_GIT_RUN_ATTEMPT: \${{ github.run_attempt }}
|
|
531
577
|
- name: Upload signed Windows candidate
|
|
578
|
+
if: \${{ always() }}
|
|
532
579
|
uses: actions/upload-artifact@${UPLOAD_ARTIFACT_SHA} # v4
|
|
533
580
|
with:
|
|
534
|
-
name: ${artifactPrefix}-signed-windows-\${{ matrix.architecture }}
|
|
581
|
+
name: ${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-signed-windows-\${{ matrix.architecture }}-\${{ needs.admission.outputs.version }}-\${{ needs.admission.outputs.source_revision }}
|
|
535
582
|
path: |
|
|
536
583
|
${uploadPath}
|
|
537
584
|
if-no-files-found: error
|
|
585
|
+
- name: Upload Windows signing stage summary
|
|
586
|
+
if: \${{ always() }}
|
|
587
|
+
uses: actions/upload-artifact@${UPLOAD_ARTIFACT_SHA} # v4
|
|
588
|
+
with:
|
|
589
|
+
name: ${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-summary-windows-sign-\${{ matrix.architecture }}-\${{ needs.admission.outputs.version }}-\${{ needs.admission.outputs.source_revision }}
|
|
590
|
+
path: \${{ runner.temp }}/right-git-stage-summary/stage-summary.json
|
|
591
|
+
if-no-files-found: error
|
|
538
592
|
`.trimEnd();
|
|
539
593
|
}
|
|
540
594
|
|
|
@@ -548,7 +602,7 @@ function macosSigningJob(manifest, pm, artifactPrefix) {
|
|
|
548
602
|
const finalizeEnvironment = releaseChain
|
|
549
603
|
? ` RIGHT_GIT_UNSIGNED_CANDIDATE_ROOT: \${{ runner.temp }}/unsigned-macos-candidate
|
|
550
604
|
RIGHT_GIT_FINALIZED_MACOS_ROOT: \${{ runner.temp }}/finalized-macos
|
|
551
|
-
RIGHT_GIT_SOURCE_REVISION: \${{
|
|
605
|
+
RIGHT_GIT_SOURCE_REVISION: \${{ needs.admission.outputs.source_revision }}`
|
|
552
606
|
: ` LEGION_UNSIGNED_CANDIDATE_ROOT: \${{ runner.temp }}/unsigned-macos-candidate
|
|
553
607
|
LEGION_SOURCE_REVISION: \${{ env.RIGHT_GIT_SOURCE_REVISION }}`;
|
|
554
608
|
const uploadPath = releaseChain
|
|
@@ -556,8 +610,8 @@ function macosSigningJob(manifest, pm, artifactPrefix) {
|
|
|
556
610
|
: " dist/releases/mac/**\n .right-release/receipts/macos-*.json";
|
|
557
611
|
return `
|
|
558
612
|
macos-sign:
|
|
559
|
-
needs: [candidate]
|
|
560
|
-
if: \${{
|
|
613
|
+
needs: [admission, candidate]
|
|
614
|
+
if: \${{ needs.admission.outputs.signed_qualification == 'true' }}
|
|
561
615
|
environment: release
|
|
562
616
|
strategy:
|
|
563
617
|
fail-fast: false
|
|
@@ -568,9 +622,9 @@ ${signingMatrix(manifest, "macos")}
|
|
|
568
622
|
contents: read
|
|
569
623
|
steps:
|
|
570
624
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
625
|
+
with:
|
|
626
|
+
ref: \${{ needs.admission.outputs.source_revision }}
|
|
627
|
+
persist-credentials: false
|
|
574
628
|
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
575
629
|
with:
|
|
576
630
|
node-version: ${nodeVersion}
|
|
@@ -580,10 +634,24 @@ ${pm.setup}
|
|
|
580
634
|
with:
|
|
581
635
|
targets: \${{ matrix.targetTriple }}
|
|
582
636
|
- run: ${pm.installCommand}
|
|
637
|
+
- name: Initialize macOS signing stage summary
|
|
638
|
+
run: ${pm.runPrefix} ${manifest.candidate.stageSummaryScript}
|
|
639
|
+
env:
|
|
640
|
+
RIGHT_GIT_STAGE_ACTION: init
|
|
641
|
+
RIGHT_GIT_STAGE_ROOT: \${{ runner.temp }}/right-git-stage-summary
|
|
642
|
+
RIGHT_GIT_STAGE_EVIDENCE_ROOT: \${{ runner.temp }}/finalized-macos
|
|
643
|
+
RIGHT_GIT_STAGE: macos-sign
|
|
644
|
+
RIGHT_GIT_STAGE_PRODUCER: macos-sign-\${{ matrix.architecture }}
|
|
645
|
+
RIGHT_GIT_RELEASE_VERSION: \${{ needs.admission.outputs.version }}
|
|
646
|
+
RIGHT_GIT_SOURCE_REVISION: \${{ needs.admission.outputs.source_revision }}
|
|
647
|
+
RIGHT_GIT_RELEASE_PLATFORM: \${{ matrix.platform }}
|
|
648
|
+
RIGHT_GIT_RELEASE_ARCHITECTURE: \${{ matrix.architecture }}
|
|
649
|
+
RIGHT_GIT_RUN_ID: \${{ github.run_id }}
|
|
650
|
+
RIGHT_GIT_RUN_ATTEMPT: \${{ github.run_attempt }}
|
|
583
651
|
- name: Download exact unsigned macOS candidate
|
|
584
652
|
uses: actions/download-artifact@${DOWNLOAD_ARTIFACT_SHA} # v4.3.0
|
|
585
653
|
with:
|
|
586
|
-
name: ${artifactPrefix}-
|
|
654
|
+
name: ${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-candidate-\${{ matrix.platform }}-\${{ matrix.architecture }}-\${{ needs.admission.outputs.version }}-\${{ needs.admission.outputs.source_revision }}
|
|
587
655
|
path: \${{ runner.temp }}/unsigned-macos-candidate
|
|
588
656
|
- name: Install Apple signing identity in temporary keychain
|
|
589
657
|
shell: bash
|
|
@@ -615,13 +683,38 @@ ${finalizeEnvironment}
|
|
|
615
683
|
APPLE_DEVELOPER_ID: \${{ vars.APPLE_DEVELOPER_ID }}
|
|
616
684
|
APPLE_API_KEY: \${{ secrets.APPLE_API_KEY }}
|
|
617
685
|
APPLE_API_ISSUER: \${{ secrets.APPLE_API_ISSUER }}
|
|
686
|
+
- name: Finalize macOS signing stage summary
|
|
687
|
+
if: \${{ always() }}
|
|
688
|
+
run: ${pm.runPrefix} ${manifest.candidate.stageSummaryScript}
|
|
689
|
+
env:
|
|
690
|
+
RIGHT_GIT_STAGE_ACTION: finalize
|
|
691
|
+
RIGHT_GIT_STAGE_ROOT: \${{ runner.temp }}/right-git-stage-summary
|
|
692
|
+
RIGHT_GIT_STAGE_EVIDENCE_ROOT: \${{ runner.temp }}/finalized-macos
|
|
693
|
+
RIGHT_GIT_STAGE: macos-sign
|
|
694
|
+
RIGHT_GIT_STAGE_PRODUCER: macos-sign-\${{ matrix.architecture }}
|
|
695
|
+
RIGHT_GIT_STAGE_STATUS: \${{ job.status == 'success' && 'SUCCEEDED' || 'FAILED' }}
|
|
696
|
+
RIGHT_GIT_STAGE_EXIT_CODE: \${{ job.status == 'success' && '0' || '1' }}
|
|
697
|
+
RIGHT_GIT_RELEASE_VERSION: \${{ needs.admission.outputs.version }}
|
|
698
|
+
RIGHT_GIT_SOURCE_REVISION: \${{ needs.admission.outputs.source_revision }}
|
|
699
|
+
RIGHT_GIT_RELEASE_PLATFORM: \${{ matrix.platform }}
|
|
700
|
+
RIGHT_GIT_RELEASE_ARCHITECTURE: \${{ matrix.architecture }}
|
|
701
|
+
RIGHT_GIT_RUN_ID: \${{ github.run_id }}
|
|
702
|
+
RIGHT_GIT_RUN_ATTEMPT: \${{ github.run_attempt }}
|
|
618
703
|
- name: Upload signed & notarized macOS candidate
|
|
704
|
+
if: \${{ always() }}
|
|
619
705
|
uses: actions/upload-artifact@${UPLOAD_ARTIFACT_SHA} # v4
|
|
620
706
|
with:
|
|
621
|
-
name: ${artifactPrefix}-signed-macos-\${{ matrix.architecture }}
|
|
707
|
+
name: ${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-signed-macos-\${{ matrix.architecture }}-\${{ needs.admission.outputs.version }}-\${{ needs.admission.outputs.source_revision }}
|
|
622
708
|
path: |
|
|
623
709
|
${uploadPath}
|
|
624
710
|
if-no-files-found: error
|
|
711
|
+
- name: Upload macOS signing stage summary
|
|
712
|
+
if: \${{ always() }}
|
|
713
|
+
uses: actions/upload-artifact@${UPLOAD_ARTIFACT_SHA} # v4
|
|
714
|
+
with:
|
|
715
|
+
name: ${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-summary-macos-sign-\${{ matrix.architecture }}-\${{ needs.admission.outputs.version }}-\${{ needs.admission.outputs.source_revision }}
|
|
716
|
+
path: \${{ runner.temp }}/right-git-stage-summary/stage-summary.json
|
|
717
|
+
if-no-files-found: error
|
|
625
718
|
- name: Remove Apple signing material
|
|
626
719
|
if: \${{ always() }}
|
|
627
720
|
shell: bash
|
|
@@ -638,30 +731,71 @@ function releaseChainJobs(manifest, pm, artifactPrefix) {
|
|
|
638
731
|
const windowsRunner = windowsTarget.os;
|
|
639
732
|
const windowsArchitecture = windowsTarget.architecture;
|
|
640
733
|
const macosTarget = candidateTargets(manifest.candidate).find((target) => target.platform === "macos");
|
|
641
|
-
const
|
|
642
|
-
const macosDependency =
|
|
643
|
-
const macosSuccess =
|
|
644
|
-
|
|
734
|
+
const signMacos = manifest.candidate.signMacos === true;
|
|
735
|
+
const macosDependency = signMacos ? ", macos-sign" : "";
|
|
736
|
+
const macosSuccess = signMacos ? " && needs.macos-sign.result == 'success'" : "";
|
|
737
|
+
// Run- and identity-bound: matches exactly what windows-sign/macos-sign
|
|
738
|
+
// uploaded (see windowsSigningJob/macosSigningJob) — no matrix context is
|
|
739
|
+
// available in these non-matrixed jobs, so the platform architecture is a
|
|
740
|
+
// literal derived from the manifest's single windows/macos target.
|
|
741
|
+
const VERSION = "${{ needs.admission.outputs.version }}";
|
|
742
|
+
const SOURCE_REVISION = "${{ needs.admission.outputs.source_revision }}";
|
|
743
|
+
const windowsSignedArtifact = `${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-signed-windows-${windowsArchitecture}-${VERSION}-${SOURCE_REVISION}`;
|
|
744
|
+
const windowsSummaryArtifact = `${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-summary-windows-sign-${windowsArchitecture}-${VERSION}-${SOURCE_REVISION}`;
|
|
745
|
+
const macosSignedArtifact = signMacos ? `${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-signed-macos-${macosTarget.architecture}-${VERSION}-${SOURCE_REVISION}` : "";
|
|
746
|
+
const macosSummaryArtifact = signMacos ? `${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-summary-macos-sign-${macosTarget.architecture}-${VERSION}-${SOURCE_REVISION}` : "";
|
|
747
|
+
// Candidate stage summaries are per (platform, architecture) — see the
|
|
748
|
+
// `Upload candidate stage summary` step in the template. releaseChain
|
|
749
|
+
// requires at most one target per signing platform (validateManifest), so
|
|
750
|
+
// exactly one candidate-windows summary and at most one candidate-macos
|
|
751
|
+
// summary exist for this manifest.
|
|
752
|
+
const candidateWindowsSummaryArtifact = `${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-summary-candidate-windows-${windowsArchitecture}-${VERSION}-${SOURCE_REVISION}`;
|
|
753
|
+
const candidateMacosSummaryArtifact = signMacos ? `${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-summary-candidate-macos-${macosTarget.architecture}-${VERSION}-${SOURCE_REVISION}` : "";
|
|
754
|
+
const qualificationArtifact = `${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-installed-qualification-${VERSION}-${SOURCE_REVISION}`;
|
|
755
|
+
const qualificationSummaryArtifact = `${artifactPrefix}-\${{ github.run_id }}-\${{ github.run_attempt }}-summary-installed-qualification-${VERSION}-${SOURCE_REVISION}`;
|
|
756
|
+
const macosDownload = signMacos
|
|
645
757
|
? ` - name: Download same-run signed & notarized macOS release
|
|
646
758
|
uses: actions/download-artifact@${DOWNLOAD_ARTIFACT_SHA} # v4.3.0
|
|
647
759
|
with:
|
|
648
|
-
name: ${
|
|
760
|
+
name: ${macosSignedArtifact}
|
|
649
761
|
path: \${{ runner.temp }}/right-git-release/macos`
|
|
650
762
|
: "";
|
|
763
|
+
const macosSummaryDownload = signMacos
|
|
764
|
+
? ` - name: Download same-run macOS signing stage summary
|
|
765
|
+
uses: actions/download-artifact@${DOWNLOAD_ARTIFACT_SHA} # v4.3.0
|
|
766
|
+
with:
|
|
767
|
+
name: ${macosSummaryArtifact}
|
|
768
|
+
path: \${{ runner.temp }}/right-git-release/stage-summaries/macos-sign`
|
|
769
|
+
: "";
|
|
770
|
+
const candidateMacosSummaryDownload = signMacos
|
|
771
|
+
? ` - name: Download same-run candidate (macOS) stage summary
|
|
772
|
+
uses: actions/download-artifact@${DOWNLOAD_ARTIFACT_SHA} # v4.3.0
|
|
773
|
+
with:
|
|
774
|
+
name: ${candidateMacosSummaryArtifact}
|
|
775
|
+
path: \${{ runner.temp }}/right-git-release/stage-summaries/candidate-macos`
|
|
776
|
+
: "";
|
|
777
|
+
const finalizedMacosEnv = signMacos ? `\n RIGHT_GIT_FINALIZED_MACOS_ROOT: \${{ runner.temp }}/right-git-release/macos` : "";
|
|
778
|
+
// Evidence must be bound to this exact run — not merely this
|
|
779
|
+
// version+source_revision — so a stale artifact from a different run
|
|
780
|
+
// cannot satisfy verification. Every job/step from installed-qualification
|
|
781
|
+
// onward carries RIGHT_GIT_RUN_ID/RIGHT_GIT_RUN_ATTEMPT alongside version
|
|
782
|
+
// and source_revision.
|
|
783
|
+
const runIdentityEnv = ` RIGHT_GIT_RUN_ID: \${{ github.run_id }}
|
|
784
|
+
RIGHT_GIT_RUN_ATTEMPT: \${{ github.run_attempt }}`;
|
|
651
785
|
const publishSecretEnvironment = (chain.publishSecrets ?? [])
|
|
652
786
|
.map((name) => ` ${name}: \${{ secrets.${name} }}`)
|
|
653
787
|
.join("\n");
|
|
654
788
|
return `
|
|
655
789
|
installed-qualification:
|
|
656
|
-
needs: [candidate, windows-sign]
|
|
657
|
-
if: \${{ always() &&
|
|
790
|
+
needs: [admission, candidate, windows-sign]
|
|
791
|
+
if: \${{ always() && needs.admission.outputs.signed_qualification == 'true' && needs.candidate.result == 'success' }}
|
|
658
792
|
environment: release
|
|
659
793
|
runs-on: \${{ vars.${chain.qualificationRunnerVariable} || '${windowsRunner}' }}
|
|
660
794
|
steps:
|
|
661
795
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
796
|
+
with:
|
|
797
|
+
ref: \${{ needs.admission.outputs.source_revision }}
|
|
798
|
+
persist-credentials: false
|
|
665
799
|
- name: Fail closed when protected finalization is absent
|
|
666
800
|
if: \${{ needs.windows-sign.result != 'success' }}
|
|
667
801
|
shell: pwsh
|
|
@@ -670,64 +804,127 @@ function releaseChainJobs(manifest, pm, artifactPrefix) {
|
|
|
670
804
|
- name: Download same-run finalized Windows release
|
|
671
805
|
uses: actions/download-artifact@${DOWNLOAD_ARTIFACT_SHA} # v4.3.0
|
|
672
806
|
with:
|
|
673
|
-
name: ${
|
|
807
|
+
name: ${windowsSignedArtifact}
|
|
674
808
|
path: \${{ runner.temp }}/right-git-release/windows
|
|
675
809
|
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
676
810
|
with:
|
|
677
|
-
node-version: ${
|
|
811
|
+
node-version: ${String(manifest.matrix.node[0])}
|
|
678
812
|
package-manager-cache: false
|
|
679
813
|
${pm.setup}
|
|
680
814
|
- run: ${pm.installCommand}
|
|
815
|
+
- name: Initialize installed-qualification stage summary
|
|
816
|
+
run: ${pm.runPrefix} ${manifest.candidate.stageSummaryScript}
|
|
817
|
+
env:
|
|
818
|
+
RIGHT_GIT_STAGE_ACTION: init
|
|
819
|
+
RIGHT_GIT_STAGE_ROOT: \${{ runner.temp }}/right-git-stage-summary
|
|
820
|
+
RIGHT_GIT_STAGE_EVIDENCE_ROOT: \${{ runner.temp }}/right-git-release/qualification
|
|
821
|
+
RIGHT_GIT_STAGE: installed-qualification
|
|
822
|
+
RIGHT_GIT_STAGE_PRODUCER: installed-qualification
|
|
823
|
+
RIGHT_GIT_RELEASE_VERSION: \${{ needs.admission.outputs.version }}
|
|
824
|
+
RIGHT_GIT_SOURCE_REVISION: \${{ needs.admission.outputs.source_revision }}
|
|
825
|
+
${runIdentityEnv}
|
|
681
826
|
- name: Run installed-artifact qualification
|
|
682
827
|
run: ${pm.runPrefix} ${chain.installedQualificationScript}
|
|
683
828
|
env:
|
|
684
829
|
GH_TOKEN: \${{ github.token }}
|
|
685
830
|
RIGHT_GIT_FINALIZED_WINDOWS_ROOT: \${{ runner.temp }}/right-git-release/windows
|
|
686
831
|
RIGHT_GIT_QUALIFICATION_EVIDENCE_ROOT: \${{ runner.temp }}/right-git-release/qualification
|
|
687
|
-
|
|
832
|
+
RIGHT_GIT_RELEASE_VERSION: \${{ needs.admission.outputs.version }}
|
|
833
|
+
RIGHT_GIT_SOURCE_REVISION: \${{ needs.admission.outputs.source_revision }}
|
|
834
|
+
- name: Finalize installed-qualification stage summary
|
|
835
|
+
if: \${{ always() }}
|
|
836
|
+
run: ${pm.runPrefix} ${manifest.candidate.stageSummaryScript}
|
|
837
|
+
env:
|
|
838
|
+
RIGHT_GIT_STAGE_ACTION: finalize
|
|
839
|
+
RIGHT_GIT_STAGE_ROOT: \${{ runner.temp }}/right-git-stage-summary
|
|
840
|
+
RIGHT_GIT_STAGE_EVIDENCE_ROOT: \${{ runner.temp }}/right-git-release/qualification
|
|
841
|
+
RIGHT_GIT_STAGE: installed-qualification
|
|
842
|
+
RIGHT_GIT_STAGE_PRODUCER: installed-qualification
|
|
843
|
+
RIGHT_GIT_STAGE_STATUS: \${{ job.status == 'success' && 'SUCCEEDED' || 'FAILED' }}
|
|
844
|
+
RIGHT_GIT_STAGE_EXIT_CODE: \${{ job.status == 'success' && '0' || '1' }}
|
|
845
|
+
RIGHT_GIT_RELEASE_VERSION: \${{ needs.admission.outputs.version }}
|
|
846
|
+
RIGHT_GIT_SOURCE_REVISION: \${{ needs.admission.outputs.source_revision }}
|
|
847
|
+
${runIdentityEnv}
|
|
688
848
|
- name: Upload installed qualification evidence
|
|
849
|
+
if: \${{ always() }}
|
|
689
850
|
uses: actions/upload-artifact@${UPLOAD_ARTIFACT_SHA} # v4
|
|
690
851
|
with:
|
|
691
|
-
name: ${
|
|
852
|
+
name: ${qualificationArtifact}
|
|
692
853
|
path: \${{ runner.temp }}/right-git-release/qualification/**
|
|
693
854
|
if-no-files-found: error
|
|
855
|
+
- name: Upload installed-qualification stage summary
|
|
856
|
+
if: \${{ always() }}
|
|
857
|
+
uses: actions/upload-artifact@${UPLOAD_ARTIFACT_SHA} # v4
|
|
858
|
+
with:
|
|
859
|
+
name: ${qualificationSummaryArtifact}
|
|
860
|
+
path: \${{ runner.temp }}/right-git-stage-summary/stage-summary.json
|
|
861
|
+
if-no-files-found: error
|
|
694
862
|
publish:
|
|
695
|
-
needs: [installed-qualification${macosDependency}]
|
|
696
|
-
if: \${{
|
|
863
|
+
needs: [admission, installed-qualification${macosDependency}]
|
|
864
|
+
if: \${{ needs.admission.outputs.publish == 'true' && needs.installed-qualification.result == 'success'${macosSuccess} }}
|
|
697
865
|
environment: release
|
|
698
866
|
runs-on: \${{ vars.${chain.qualificationRunnerVariable} || '${windowsRunner}' }}
|
|
699
867
|
permissions:
|
|
700
868
|
contents: write
|
|
701
869
|
steps:
|
|
702
870
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
871
|
+
with:
|
|
872
|
+
ref: \${{ needs.admission.outputs.source_revision }}
|
|
873
|
+
persist-credentials: false
|
|
706
874
|
- name: Download same-run finalized Windows release
|
|
707
875
|
uses: actions/download-artifact@${DOWNLOAD_ARTIFACT_SHA} # v4.3.0
|
|
708
876
|
with:
|
|
709
|
-
name: ${
|
|
877
|
+
name: ${windowsSignedArtifact}
|
|
710
878
|
path: \${{ runner.temp }}/right-git-release/windows
|
|
711
879
|
${macosDownload}
|
|
712
880
|
- name: Download same-run installed qualification evidence
|
|
713
881
|
uses: actions/download-artifact@${DOWNLOAD_ARTIFACT_SHA} # v4.3.0
|
|
714
882
|
with:
|
|
715
|
-
name: ${
|
|
883
|
+
name: ${qualificationArtifact}
|
|
716
884
|
path: \${{ runner.temp }}/right-git-release/qualification
|
|
885
|
+
- name: Download same-run candidate (Windows) stage summary
|
|
886
|
+
uses: actions/download-artifact@${DOWNLOAD_ARTIFACT_SHA} # v4.3.0
|
|
887
|
+
with:
|
|
888
|
+
name: ${candidateWindowsSummaryArtifact}
|
|
889
|
+
path: \${{ runner.temp }}/right-git-release/stage-summaries/candidate-windows
|
|
890
|
+
${candidateMacosSummaryDownload}
|
|
891
|
+
- name: Download same-run Windows signing stage summary
|
|
892
|
+
uses: actions/download-artifact@${DOWNLOAD_ARTIFACT_SHA} # v4.3.0
|
|
893
|
+
with:
|
|
894
|
+
name: ${windowsSummaryArtifact}
|
|
895
|
+
path: \${{ runner.temp }}/right-git-release/stage-summaries/windows-sign
|
|
896
|
+
${macosSummaryDownload}
|
|
897
|
+
- name: Download same-run installed-qualification stage summary
|
|
898
|
+
uses: actions/download-artifact@${DOWNLOAD_ARTIFACT_SHA} # v4.3.0
|
|
899
|
+
with:
|
|
900
|
+
name: ${qualificationSummaryArtifact}
|
|
901
|
+
path: \${{ runner.temp }}/right-git-release/stage-summaries/installed-qualification
|
|
717
902
|
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
718
903
|
with:
|
|
719
|
-
node-version: ${
|
|
904
|
+
node-version: ${String(manifest.matrix.node[0])}
|
|
720
905
|
package-manager-cache: false
|
|
721
906
|
${pm.setup}
|
|
722
907
|
- run: ${pm.installCommand}
|
|
908
|
+
- name: Verify aggregated release evidence
|
|
909
|
+
run: ${pm.runPrefix} ${chain.evidenceVerificationScript}
|
|
910
|
+
env:
|
|
911
|
+
GH_TOKEN: \${{ github.token }}
|
|
912
|
+
RIGHT_GIT_FINALIZED_WINDOWS_ROOT: \${{ runner.temp }}/right-git-release/windows${finalizedMacosEnv}
|
|
913
|
+
RIGHT_GIT_QUALIFICATION_EVIDENCE_ROOT: \${{ runner.temp }}/right-git-release/qualification
|
|
914
|
+
RIGHT_GIT_STAGE_SUMMARY_ROOT: \${{ runner.temp }}/right-git-release/stage-summaries
|
|
915
|
+
RIGHT_GIT_RELEASE_VERSION: \${{ needs.admission.outputs.version }}
|
|
916
|
+
RIGHT_GIT_SOURCE_REVISION: \${{ needs.admission.outputs.source_revision }}
|
|
917
|
+
${runIdentityEnv}
|
|
723
918
|
- name: Publish qualified signed release
|
|
724
919
|
run: ${pm.runPrefix} ${chain.publishScript}
|
|
725
920
|
env:
|
|
726
921
|
GH_TOKEN: \${{ github.token }}
|
|
727
|
-
RIGHT_GIT_FINALIZED_WINDOWS_ROOT: \${{ runner.temp }}/right-git-release/windows
|
|
728
|
-
RIGHT_GIT_FINALIZED_MACOS_ROOT: \${{ runner.temp }}/right-git-release/macos
|
|
922
|
+
RIGHT_GIT_FINALIZED_WINDOWS_ROOT: \${{ runner.temp }}/right-git-release/windows${finalizedMacosEnv}
|
|
729
923
|
RIGHT_GIT_QUALIFICATION_EVIDENCE_ROOT: \${{ runner.temp }}/right-git-release/qualification
|
|
730
|
-
|
|
924
|
+
RIGHT_GIT_STAGE_SUMMARY_ROOT: \${{ runner.temp }}/right-git-release/stage-summaries
|
|
925
|
+
RIGHT_GIT_RELEASE_VERSION: \${{ needs.admission.outputs.version }}
|
|
926
|
+
RIGHT_GIT_SOURCE_REVISION: \${{ needs.admission.outputs.source_revision }}
|
|
927
|
+
${runIdentityEnv}
|
|
731
928
|
${publishSecretEnvironment}
|
|
732
929
|
`.trimEnd();
|
|
733
930
|
}
|
|
@@ -774,18 +971,39 @@ export function buildRenderContext(manifest, repoPath) {
|
|
|
774
971
|
PACKAGE_MANAGER_SETUP: pm.setup,
|
|
775
972
|
ARTIFACT_PREFIX: artifactPrefix,
|
|
776
973
|
TEMPLATE_VERSION: manifest.templateVersion,
|
|
777
|
-
GATE_PATH: manifest.gate?.path,
|
|
778
974
|
RUST_CACHE_WORKSPACES: rustWorkspaces.map((workspace) => ` ${workspace} -> target`).join("\n"),
|
|
779
|
-
|
|
780
|
-
CANDIDATE_CHECK_SCRIPT: manifest.candidate?.checkScript,
|
|
781
|
-
CANDIDATE_ARTIFACT_ROOT: manifest.candidate?.artifactRoot,
|
|
782
|
-
CANDIDATE_OS_MATRIX: yamlFlowStringList(manifest.candidate?.os ?? manifest.matrix.os),
|
|
783
|
-
CANDIDATE_MATRIX: candidateMatrix(manifest),
|
|
975
|
+
RUST_REQUIRED_FOR_GATE: manifest.rustCache?.requiredForGate === true ? "true" : "false",
|
|
784
976
|
WINDOWS_SIGNING_JOB: windowsSigningJob(manifest, pm, artifactPrefix),
|
|
785
977
|
MACOS_SIGNING_JOB: macosSigningJob(manifest, pm, artifactPrefix),
|
|
786
978
|
RELEASE_CHAIN_JOBS: releaseChainJobs(manifest, pm, artifactPrefix),
|
|
787
979
|
};
|
|
788
980
|
|
|
981
|
+
// Every key below is populated ONLY when its source manifest section is
|
|
982
|
+
// actually present — mirroring the publish.npm/homebrew/winget pattern.
|
|
983
|
+
// This keeps the fail-closed check just below honest: a key that is
|
|
984
|
+
// legitimately inapplicable to this manifest (e.g. CANDIDATE_* for a
|
|
985
|
+
// non-rust-hybrid manifest, GATE_PATH for a non-rust-hybrid profile) is
|
|
986
|
+
// simply ABSENT from the context rather than present-with-undefined, so
|
|
987
|
+
// render.mjs's own `Object.hasOwn` check does the right thing if a
|
|
988
|
+
// template ever references a token this manifest didn't opt into.
|
|
989
|
+
if (manifest.gate) {
|
|
990
|
+
context.GATE_PATH = manifest.gate.path;
|
|
991
|
+
}
|
|
992
|
+
if (manifest.candidate) {
|
|
993
|
+
context.CANDIDATE_BUILD_SCRIPT = manifest.candidate.buildScript;
|
|
994
|
+
context.CANDIDATE_CHECK_SCRIPT = manifest.candidate.checkScript;
|
|
995
|
+
context.CANDIDATE_ARTIFACT_ROOT = manifest.candidate.artifactRoot;
|
|
996
|
+
context.CANDIDATE_OS_MATRIX = yamlFlowStringList(manifest.candidate.os ?? manifest.matrix.os);
|
|
997
|
+
context.CANDIDATE_MATRIX = candidateMatrix(manifest);
|
|
998
|
+
// admissionScript & stageSummaryScript are required candidate fields
|
|
999
|
+
// (see validateManifest) whenever release-candidate is configured at
|
|
1000
|
+
// all — the admission job and the candidate job's stage-summary steps
|
|
1001
|
+
// are unconditional parts of the rendered template, independent of
|
|
1002
|
+
// signing/releaseChain.
|
|
1003
|
+
context.RELEASE_ADMISSION_SCRIPT = manifest.candidate.admissionScript;
|
|
1004
|
+
context.RELEASE_STAGE_SUMMARY_SCRIPT = manifest.candidate.stageSummaryScript;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
789
1007
|
if (manifest.publish?.npm) {
|
|
790
1008
|
context.NPM_PROVENANCE_FLAG = manifest.publish.npm.provenance ? " --provenance" : "";
|
|
791
1009
|
}
|
|
@@ -797,5 +1015,21 @@ export function buildRenderContext(manifest, repoPath) {
|
|
|
797
1015
|
context.WINGET_PACKAGE_IDENTIFIER = manifest.publish.winget.packageIdentifier;
|
|
798
1016
|
}
|
|
799
1017
|
|
|
1018
|
+
// F-undefined-script fix: render.mjs's `Object.hasOwn` check only proves a
|
|
1019
|
+
// key EXISTS in the context — it does not prove the key resolved to a real
|
|
1020
|
+
// value. Every field above that is sourced from an optional manifest path
|
|
1021
|
+
// (candidate.*, candidate.releaseChain.* via the job-builder functions,
|
|
1022
|
+
// gate.path) must resolve to a real string once its guarding `if` above
|
|
1023
|
+
// decided the section applies; a bug in one of those guards (or a
|
|
1024
|
+
// mis-nested manifest field) must fail the render loudly here rather than
|
|
1025
|
+
// silently emit a literal "undefined" into a workflow file that GitHub
|
|
1026
|
+
// Actions will then try to execute as a real step (e.g. `run: pnpm run
|
|
1027
|
+
// undefined`).
|
|
1028
|
+
for (const [key, value] of Object.entries(context)) {
|
|
1029
|
+
if (value === undefined || value === null) {
|
|
1030
|
+
throw new Error(`buildRenderContext: placeholder \${${key}} resolved to ${value} — check the manifest's candidate/releaseChain/gate/publish configuration`);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
800
1034
|
return context;
|
|
801
1035
|
}
|
package/manifest.schema.json
CHANGED
|
@@ -95,7 +95,8 @@
|
|
|
95
95
|
"minItems": 1,
|
|
96
96
|
"uniqueItems": true,
|
|
97
97
|
"items": { "type": "string", "pattern": "^(?:\\.|(?!.*\\.\\.)(?!.*\\s)[A-Za-z0-9][A-Za-z0-9._/-]*)$" }
|
|
98
|
-
}
|
|
98
|
+
},
|
|
99
|
+
"requiredForGate": { "type": "boolean" }
|
|
99
100
|
}
|
|
100
101
|
},
|
|
101
102
|
"gate": {
|
|
@@ -104,11 +105,21 @@
|
|
|
104
105
|
},
|
|
105
106
|
"candidate": {
|
|
106
107
|
"type": "object",
|
|
107
|
-
"required": ["buildScript", "checkScript", "artifactRoot", "os"],
|
|
108
|
+
"required": ["buildScript", "checkScript", "admissionScript", "stageSummaryScript", "artifactRoot", "os"],
|
|
108
109
|
"additionalProperties": false,
|
|
109
110
|
"properties": {
|
|
110
111
|
"buildScript": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9:_-]*$" },
|
|
111
112
|
"checkScript": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9:_-]*$" },
|
|
113
|
+
"admissionScript": {
|
|
114
|
+
"type": "string",
|
|
115
|
+
"pattern": "^[A-Za-z0-9][A-Za-z0-9:_-]*$",
|
|
116
|
+
"description": "Runs in the unconditional `admission` job (workflow_dispatch envelope validation). Required for every release-candidate lane, signed or not."
|
|
117
|
+
},
|
|
118
|
+
"stageSummaryScript": {
|
|
119
|
+
"type": "string",
|
|
120
|
+
"pattern": "^[A-Za-z0-9][A-Za-z0-9:_-]*$",
|
|
121
|
+
"description": "Runs (init/finalize) in the `candidate` job and, when configured, the windows-sign/macos-sign jobs. Required for every release-candidate lane, signed or not."
|
|
122
|
+
},
|
|
112
123
|
"artifactRoot": { "type": "string", "pattern": "^(?!.*\\.\\.)(?!.*\\s)[A-Za-z0-9][A-Za-z0-9._/-]*$" },
|
|
113
124
|
"os": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
|
|
114
125
|
"targets": {
|
|
@@ -129,9 +140,14 @@
|
|
|
129
140
|
"signMacos": { "type": "boolean" },
|
|
130
141
|
"releaseChain": {
|
|
131
142
|
"type": "object",
|
|
132
|
-
"required": ["windowsFinalizeScript", "installedQualificationScript", "publishScript", "qualificationRunnerVariable"],
|
|
143
|
+
"required": ["evidenceVerificationScript", "windowsFinalizeScript", "installedQualificationScript", "publishScript", "qualificationRunnerVariable"],
|
|
133
144
|
"additionalProperties": false,
|
|
134
145
|
"properties": {
|
|
146
|
+
"evidenceVerificationScript": {
|
|
147
|
+
"type": "string",
|
|
148
|
+
"pattern": "^[A-Za-z0-9][A-Za-z0-9:_-]*$",
|
|
149
|
+
"description": "Runs in the `publish` job before the publish step, verifying the aggregated same-run signed/qualification evidence."
|
|
150
|
+
},
|
|
135
151
|
"windowsFinalizeScript": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9:_-]*$" },
|
|
136
152
|
"macosFinalizeScript": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9:_-]*$" },
|
|
137
153
|
"installedQualificationScript": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9:_-]*$" },
|