mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
ci(release): prevent signing on workflow reruns (#17802)
This commit is contained in:
@@ -1193,12 +1193,22 @@ jobs:
|
||||
with:
|
||||
ref: refs/tags/${{ needs.cut.outputs.tag }}
|
||||
|
||||
# GitHub reruns also resume jobs skipped behind a failed gate. Never
|
||||
# recreate Windows signing requests on a rerun; reuse the assets from the
|
||||
# original attempt and require a fresh dispatch if they are missing.
|
||||
- name: Skip Windows artifact rebuild on rerun
|
||||
if: matrix.platform == 'win' && github.run_attempt != 1
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Windows artifact/signing steps are disabled on reruns (attempt $GITHUB_RUN_ATTEMPT)."
|
||||
echo "Existing signed release assets must be reused; dispatch a fresh release only when a rebuild is required." >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
# Why: `uses: ./…` resolves from the checked-out tag, not from the workflow
|
||||
# ref, so cutting from an older/off-main ref whose tree predates a composite
|
||||
# action would fail the step with "Can't find 'action.yml'". Restore the
|
||||
# actions directory from the commit this workflow file itself came from.
|
||||
- name: Restore composite actions from the workflow ref
|
||||
if: matrix.platform == 'win'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1
|
||||
shell: bash
|
||||
env:
|
||||
WORKFLOW_SHA: ${{ github.workflow_sha }}
|
||||
@@ -1405,7 +1415,7 @@ jobs:
|
||||
# Why: SignPath signs GitHub workflow artifacts, so Windows builds must
|
||||
# upload only after the production-signed installer has been returned.
|
||||
- name: Build Windows release artifacts
|
||||
if: matrix.platform == 'win'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1
|
||||
uses: nick-fields/retry@v4
|
||||
with:
|
||||
timeout_minutes: 30
|
||||
@@ -1416,7 +1426,7 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Verify Windows node-pty ConPTY runtime
|
||||
if: matrix.platform == 'win'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1
|
||||
shell: pwsh
|
||||
run: |
|
||||
$runtimeDir = 'dist/win-unpacked/resources/node_modules/node-pty/build/Release'
|
||||
@@ -1433,7 +1443,7 @@ jobs:
|
||||
}
|
||||
|
||||
- name: Install SignPath PowerShell module
|
||||
if: matrix.platform == 'win'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1
|
||||
uses: ./.github/actions/install-signpath-module
|
||||
|
||||
# ── Windows inner-binary signing (issue #7785) ─────────────────────
|
||||
@@ -1450,7 +1460,7 @@ jobs:
|
||||
# valid signature (Microsoft's OpenConsole.exe) must keep their signer.
|
||||
- name: Stage unsigned inner PE files for signing
|
||||
id: stage-inner
|
||||
if: matrix.platform == 'win'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1
|
||||
continue-on-error: true
|
||||
shell: pwsh
|
||||
run: |
|
||||
@@ -1489,7 +1499,7 @@ jobs:
|
||||
|
||||
- name: Upload unsigned inner binaries for SignPath
|
||||
id: upload-unsigned-inner
|
||||
if: matrix.platform == 'win' && steps.stage-inner.outcome == 'success'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1 && steps.stage-inner.outcome == 'success'
|
||||
continue-on-error: true
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
@@ -1499,7 +1509,7 @@ jobs:
|
||||
|
||||
- name: Submit inner binaries signing request
|
||||
id: submit-inner-signing
|
||||
if: matrix.platform == 'win' && steps.upload-unsigned-inner.outcome == 'success'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1 && steps.upload-unsigned-inner.outcome == 'success'
|
||||
continue-on-error: true
|
||||
uses: signpath/github-action-submit-signing-request@v2
|
||||
with:
|
||||
@@ -1513,7 +1523,7 @@ jobs:
|
||||
|
||||
- name: Notify Slack that inner-binary signing is waiting for approval
|
||||
id: notify-inner-signing
|
||||
if: matrix.platform == 'win' && steps.submit-inner-signing.outcome == 'success'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1 && steps.submit-inner-signing.outcome == 'success'
|
||||
continue-on-error: true
|
||||
shell: pwsh
|
||||
env:
|
||||
@@ -1581,7 +1591,7 @@ jobs:
|
||||
# falls through to today's unsigned-inner flow rather than blocking.
|
||||
- name: Download signed inner binaries from SignPath
|
||||
id: download-signed-inner
|
||||
if: matrix.platform == 'win' && steps.submit-inner-signing.outcome == 'success' && steps.notify-inner-signing.outcome == 'success'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1 && steps.submit-inner-signing.outcome == 'success' && steps.notify-inner-signing.outcome == 'success'
|
||||
continue-on-error: true
|
||||
shell: pwsh
|
||||
env:
|
||||
@@ -1604,7 +1614,7 @@ jobs:
|
||||
# shipping a mix of signed and unsigned binaries.
|
||||
- name: Restore signed inner binaries into unpacked app
|
||||
id: restore-signed-inner
|
||||
if: matrix.platform == 'win' && steps.download-signed-inner.outcome == 'success'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1 && steps.download-signed-inner.outcome == 'success'
|
||||
continue-on-error: true
|
||||
shell: pwsh
|
||||
run: |
|
||||
@@ -1645,7 +1655,7 @@ jobs:
|
||||
# unsigned again, which the evidence gate will flag.
|
||||
- name: Replace cached elevate.exe with the signed copy
|
||||
id: sign-elevate-cache
|
||||
if: matrix.platform == 'win' && steps.restore-signed-inner.outcome == 'success'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1 && steps.restore-signed-inner.outcome == 'success'
|
||||
continue-on-error: true
|
||||
shell: pwsh
|
||||
run: |
|
||||
@@ -1672,7 +1682,7 @@ jobs:
|
||||
|
||||
- name: Rebuild NSIS installer from signed unpacked app
|
||||
id: rebuild-nsis-signed
|
||||
if: matrix.platform == 'win' && steps.restore-signed-inner.outcome == 'success'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1 && steps.restore-signed-inner.outcome == 'success'
|
||||
continue-on-error: true
|
||||
shell: pwsh
|
||||
run: |
|
||||
@@ -1689,7 +1699,7 @@ jobs:
|
||||
}
|
||||
|
||||
- name: Roll back to original installer after failed rebuild
|
||||
if: matrix.platform == 'win' && steps.rebuild-nsis-signed.outcome == 'failure'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1 && steps.rebuild-nsis-signed.outcome == 'failure'
|
||||
shell: pwsh
|
||||
run: |
|
||||
if (Test-Path 'prepack-backup/orca-windows-setup.exe') {
|
||||
@@ -1699,7 +1709,7 @@ jobs:
|
||||
}
|
||||
# ── End Windows inner-binary signing ───────────────────────────────
|
||||
- name: Upload unsigned Windows installer for SignPath
|
||||
if: matrix.platform == 'win'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1
|
||||
id: upload-unsigned-windows-installer
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
@@ -1711,7 +1721,7 @@ jobs:
|
||||
# so the release job waits while the signing request is approved in UI.
|
||||
- name: Submit Windows installer signing request
|
||||
id: submit-signing-request
|
||||
if: matrix.platform == 'win'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1
|
||||
uses: signpath/github-action-submit-signing-request@v2
|
||||
with:
|
||||
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
|
||||
@@ -1723,7 +1733,7 @@ jobs:
|
||||
wait-for-completion: false
|
||||
|
||||
- name: Notify Slack that Windows signing is waiting for approval
|
||||
if: matrix.platform == 'win'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1
|
||||
shell: pwsh
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
@@ -1787,7 +1797,7 @@ jobs:
|
||||
Invoke-RestMethod -Method Post -Uri $env:SLACK_WEBHOOK_URL -ContentType 'application/json' -Body $payload
|
||||
|
||||
- name: Download signed Windows installer from SignPath
|
||||
if: matrix.platform == 'win'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1
|
||||
shell: pwsh
|
||||
env:
|
||||
SIGNPATH_API_TOKEN: ${{ secrets.SIGNPATH_API_TOKEN }}
|
||||
@@ -1805,7 +1815,7 @@ jobs:
|
||||
Expand-Archive -Path signed-windows.zip -DestinationPath signed-windows -Force
|
||||
|
||||
- name: Stage signed Windows release assets
|
||||
if: matrix.platform == 'win'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1
|
||||
shell: pwsh
|
||||
run: |
|
||||
$signedInstaller = Get-ChildItem -Path signed-windows -Recurse -File -Filter 'orca-windows-setup.exe' | Select-Object -First 1
|
||||
@@ -1842,7 +1852,7 @@ jobs:
|
||||
Get-Item 'dist/orca-windows-setup.exe', 'dist/orca-windows-setup.exe.blockmap', 'dist/latest.yml'
|
||||
|
||||
- name: Verify signed Windows installer
|
||||
if: matrix.platform == 'win'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1
|
||||
shell: pwsh
|
||||
run: |
|
||||
$signature = Get-AuthenticodeSignature -FilePath 'dist/orca-windows-setup.exe'
|
||||
@@ -1860,7 +1870,7 @@ jobs:
|
||||
# proven on a real release, then flip ORCA_WINDOWS_INNER_SIGNATURE_REQUIRED
|
||||
# to 'true' so unsigned inner binaries block the release.
|
||||
- name: Verify Windows inner binary signatures
|
||||
if: matrix.platform == 'win'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1
|
||||
shell: pwsh
|
||||
env:
|
||||
ORCA_WINDOWS_INNER_SIGNATURE_REQUIRED: 'false'
|
||||
@@ -1992,7 +2002,7 @@ jobs:
|
||||
if ($policyFailure) { throw $policyFailure }
|
||||
|
||||
- name: Upload Windows inner signing evidence
|
||||
if: always() && matrix.platform == 'win'
|
||||
if: always() && matrix.platform == 'win' && github.run_attempt == 1
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: orca-windows-inner-signing-evidence-${{ needs.cut.outputs.tag }}
|
||||
@@ -2003,7 +2013,7 @@ jobs:
|
||||
retention-days: 30
|
||||
|
||||
- name: Publish signed Windows release artifacts
|
||||
if: matrix.platform == 'win'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1
|
||||
uses: nick-fields/retry@v4
|
||||
with:
|
||||
timeout_minutes: 10
|
||||
|
||||
@@ -38,7 +38,7 @@ describe('Windows signing workflow contract', () => {
|
||||
|
||||
const installStep = steps[installStepIndexes[0]]
|
||||
|
||||
expect(installStep.if).toBe("matrix.platform == 'win'")
|
||||
expect(installStep.if).toBe("matrix.platform == 'win' && github.run_attempt == 1")
|
||||
expect(installStep.uses).toBe('./.github/actions/install-signpath-module')
|
||||
expect(installStep.run).toBeUndefined()
|
||||
|
||||
@@ -139,6 +139,34 @@ describe('Windows signing workflow contract', () => {
|
||||
expect(installRun).toContain('throw "SHA-256 mismatch for $source')
|
||||
})
|
||||
|
||||
it('never recreates Windows signing requests on a workflow rerun', () => {
|
||||
const parsedWorkflow = readWorkflow('.github/workflows/release-cut.yml')
|
||||
const steps = parsedWorkflow.jobs.build.steps
|
||||
const stepNames = steps.map((step) => step.name)
|
||||
const skipStep = steps.find((step) => step.name === 'Skip Windows artifact rebuild on rerun')
|
||||
|
||||
expect(skipStep?.if).toBe("matrix.platform == 'win' && github.run_attempt != 1")
|
||||
expect(skipStep?.run).toContain('Existing signed release assets must be reused')
|
||||
|
||||
const signingStepNames = [
|
||||
'Build Windows release artifacts',
|
||||
'Stage unsigned inner PE files for signing',
|
||||
'Upload unsigned inner binaries for SignPath',
|
||||
'Submit inner binaries signing request',
|
||||
'Download signed inner binaries from SignPath',
|
||||
'Upload unsigned Windows installer for SignPath',
|
||||
'Submit Windows installer signing request',
|
||||
'Download signed Windows installer from SignPath',
|
||||
'Stage signed Windows release assets',
|
||||
'Publish signed Windows release artifacts'
|
||||
]
|
||||
|
||||
for (const stepName of signingStepNames) {
|
||||
const step = steps[stepNames.indexOf(stepName)]
|
||||
expect(step?.if, stepName).toContain('github.run_attempt == 1')
|
||||
}
|
||||
})
|
||||
|
||||
it('shares one SignPath module install path between release and rehearsal', () => {
|
||||
const rehearsalWorkflow = readWorkflow('.github/workflows/windows-signing-rehearsal.yml')
|
||||
const stepNames = rehearsalWorkflow.jobs.rehearse.steps.map((step) => step.name)
|
||||
|
||||
Reference in New Issue
Block a user