ci(windows): rehearse the orcad template reseal over SignPath-signed binaries (#34316)

* ci(windows): rehearse the orcad template reseal over SignPath-signed binaries

* ci(windows): keep rehearsal template jobs on GitHub-hosted runners
This commit is contained in:
Neil
2026-10-27 01:27:59 -07:00
committed by GitHub
parent 755bbfaa13
commit 0cff8e0fb7
2 changed files with 75 additions and 0 deletions
@@ -17,7 +17,19 @@ on:
default: windows-inner-binaries-zip
jobs:
# Ship the same qualified template as release-cut so the reseal over SignPath-rewritten binaries is rehearsed too.
orcad-template:
permissions:
contents: read
actions: read
uses: ./.github/workflows/qualified-orcad-template.yml
with:
ref: ${{ github.sha }}
# SignPath origin verification covers reusable-workflow jobs, so they stay GitHub-hosted.
fast_runners: false
rehearse:
needs: orcad-template
# Why: SignPath origin verification requires GitHub-hosted runners, and
# windows-2022 matches the real release job's build environment.
runs-on: windows-2022
@@ -25,6 +37,8 @@ jobs:
permissions:
actions: read
contents: read
env:
ORCA_REQUIRE_ORCAD_TEMPLATE: '1'
steps:
- name: Checkout
@@ -79,6 +93,13 @@ jobs:
env:
NODE_OPTIONS: --max-old-space-size=4096
# After the app build so nothing that cleans out/ can drop it; electron-builder ships it.
- name: Download the orcad deployment template
uses: actions/download-artifact@v8
with:
name: orcad-template
path: out/orcad-template
# Build full --win: --dir never creates the NSIS uninstaller needed for MDE evidence.
- name: Package Windows app and export the NSIS uninstaller
shell: pwsh
@@ -111,6 +132,11 @@ jobs:
Where-Object { $_.Extension -in '.exe', '.dll', '.node' } |
ForEach-Object {
$relative = [System.IO.Path]::GetRelativePath($root, $_.FullName)
# The orcad template's Linux/macOS addons are data for SSH hosts, not PE files.
if ($relative -match '^resources[\\/]orcad-template[\\/]targets[\\/](?!win32-)') {
$skipped.Add("$relative <non-Windows orcad template payload>")
return
}
$signature = Get-AuthenticodeSignature -FilePath $_.FullName
if ($signature.Status -eq 'Valid') {
$skipped.Add("$relative <already signed: $($signature.SignerCertificate.Subject)>")
@@ -214,6 +240,10 @@ jobs:
throw "Signed inner artifact did not round-trip cleanly ($($failures.Count) failures)."
}
# Recompute template checksums over the signed bytes, then verify the template as release-cut does.
- name: Reseal the orcad template over its signed binaries
run: node config/scripts/packaged-orcad-template.cjs --reseal-signed dist/win-unpacked inner-signing-list.txt
- name: Restore signed uninstaller for the installer rebuild
shell: pwsh
env:
@@ -0,0 +1,45 @@
import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
import { parse } from 'yaml'
// The rehearsal must sign and reseal the same template payload release-cut ships, or Windows reseal regressions only surface in a real release.
function readWorkflow(name) {
return parse(readFileSync(new URL(`../../.github/workflows/${name}`, import.meta.url), 'utf8'))
}
const RESEAL_STEP = 'Reseal the orcad template over its signed binaries'
const release = readWorkflow('release-cut.yml').jobs.build
const { jobs } = readWorkflow('windows-signing-rehearsal.yml')
const rehearse = jobs.rehearse
const stepIndex = (name) => rehearse.steps.findIndex((step) => step.name === name)
describe('Windows signing rehearsal ships the orcad template', () => {
it('packages the qualified template built from the dispatched commit', () => {
expect(jobs['orcad-template'].uses).toBe('./.github/workflows/qualified-orcad-template.yml')
expect(jobs['orcad-template'].with).toEqual({ ref: '${{ github.sha }}', fast_runners: false })
expect(rehearse.needs).toBe('orcad-template')
expect(rehearse.env.ORCA_REQUIRE_ORCAD_TEMPLATE).toBe('1')
const download = stepIndex('Download the orcad deployment template')
expect(download).toBeGreaterThan(stepIndex('Build app'))
expect(download).toBeLessThan(stepIndex('Package Windows app and export the NSIS uninstaller'))
expect(rehearse.steps[download].with).toEqual({
name: 'orcad-template',
path: 'out/orcad-template'
})
})
it('reseals the signed template exactly like release-cut, before the installer rebuild', () => {
const releaseReseal = release.steps.find((step) => step.name === RESEAL_STEP)
const reseal = stepIndex(RESEAL_STEP)
expect(rehearse.steps[reseal].run).toBe(releaseReseal.run)
expect(reseal).toBeGreaterThan(stepIndex('Restore signed inner binaries into unpacked app'))
expect(reseal).toBeLessThan(stepIndex('Build NSIS installer from signed unpacked app'))
})
it('keeps non-Windows template addons out of SignPath staging', () => {
const filter = "'^resources[\\\\/]orcad-template[\\\\/]targets[\\\\/](?!win32-)'"
const staging = (job) => job.steps.find((step) => step.id === 'stage-inner').run
expect(staging(release)).toContain(filter)
expect(staging(rehearse)).toContain(filter)
})
})