From ebdf52453f15de42ecfb803823979b3f899c4430 Mon Sep 17 00:00:00 2001 From: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Date: Mon, 27 Jul 2026 15:45:49 -0700 Subject: [PATCH] fix(release): preserve 7za resolver failures --- .github/workflows/release-cut.yml | 12 +++++--- .../workflows/windows-signing-rehearsal.yml | 11 ++++++-- .../windows-signing-gate-toolset.test.mjs | 28 ++++++++++++++----- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release-cut.yml b/.github/workflows/release-cut.yml index 25fe58d08aa..3848f15e861 100644 --- a/.github/workflows/release-cut.yml +++ b/.github/workflows/release-cut.yml @@ -1499,7 +1499,6 @@ jobs: Write-Warning 'Restored pre-rebuild installer; this release ships with unsigned inner binaries.' } # ── End Windows inner-binary signing ─────────────────────────────── - - name: Upload unsigned Windows installer for SignPath if: matrix.platform == 'win' id: upload-unsigned-windows-installer @@ -1700,9 +1699,14 @@ jobs: # tree — 7z parses the NSIS exe directly as its embedded payload. # Resolve 7za via app-builder-lib; electron-builder 26.9+ dropped the # bundled 7zip-bin package the old hardcoded path relied on (#6487). - $7za = (node config/scripts/resolve-7za-path.mjs).Trim() - if ($LASTEXITCODE -ne 0 -or -not (Test-Path $7za)) { - throw "Could not resolve a 7za executable for the inner-binary evidence gate: $7za" + $7zaOutput = node config/scripts/resolve-7za-path.mjs + $7zaExitCode = $LASTEXITCODE + if ($7zaExitCode -ne 0) { + throw "The 7za resolver exited with code $7zaExitCode for the inner-binary evidence gate." + } + $7za = ($7zaOutput | Out-String).Trim() + if ([string]::IsNullOrWhiteSpace($7za) -or -not (Test-Path -LiteralPath $7za -PathType Leaf)) { + throw "The 7za resolver returned an invalid path for the inner-binary evidence gate: $7za" } New-Item -ItemType Directory -Path inner-evidence-extract -Force | Out-Null & $7za x 'dist/orca-windows-setup.exe' '-oinner-evidence-extract' -y | Out-Null diff --git a/.github/workflows/windows-signing-rehearsal.yml b/.github/workflows/windows-signing-rehearsal.yml index 8ffa9441f4f..73d66e466ec 100644 --- a/.github/workflows/windows-signing-rehearsal.yml +++ b/.github/workflows/windows-signing-rehearsal.yml @@ -326,9 +326,14 @@ jobs: # Extract the signed installer and verify the files a user actually # gets on disk — including the exact file from issue #7785. # electron-builder 26.9+ removed the bundled 7zip-bin package (#6487). - $7za = (node config/scripts/resolve-7za-path.mjs).Trim() - if ($LASTEXITCODE -ne 0 -or -not (Test-Path $7za)) { - throw "Could not resolve a 7za executable for the signing rehearsal: $7za" + $7zaOutput = node config/scripts/resolve-7za-path.mjs + $7zaExitCode = $LASTEXITCODE + if ($7zaExitCode -ne 0) { + throw "The 7za resolver exited with code $7zaExitCode for the signing rehearsal." + } + $7za = ($7zaOutput | Out-String).Trim() + if ([string]::IsNullOrWhiteSpace($7za) -or -not (Test-Path -LiteralPath $7za -PathType Leaf)) { + throw "The 7za resolver returned an invalid path for the signing rehearsal: $7za" } New-Item -ItemType Directory -Path extracted-app -Force | Out-Null & $7za x 'dist/orca-windows-setup.exe' '-oextracted-app' -y | Out-Null diff --git a/config/scripts/windows-signing-gate-toolset.test.mjs b/config/scripts/windows-signing-gate-toolset.test.mjs index 28dfeac646d..8e83534421e 100644 --- a/config/scripts/windows-signing-gate-toolset.test.mjs +++ b/config/scripts/windows-signing-gate-toolset.test.mjs @@ -75,7 +75,7 @@ function scanSpans(source) { /** `source` with the named span kinds blanked to spaces — same length, so indices still line up. */ function blank(source, spans, kinds) { - const chars = [...source] + const chars = source.split('') for (const span of spans) { if (!kinds.includes(span.kind)) { continue @@ -186,13 +186,27 @@ describe('Windows signing gates resolve 7za through the toolset resolver (#6487) expect(workflowSource(name)).toContain('node config/scripts/resolve-7za-path.mjs') }) - // Why scope-checked: downgrading this `throw` to a `Write-Host` warning - // restores the original silent fail-open — the gate extracts nothing, finds - // no files, and reports success. A `toContain` on the guard condition alone - // does not notice. - it(`${name} aborts the gate when 7za cannot be resolved`, () => { + it(`${name} checks resolver failure before trimming its output`, () => { const source = workflowSource(name) - const guard = blockAfter(source, '$LASTEXITCODE -ne 0 -or -not (Test-Path $7za)') + const code = codeOf(source) + const resolveIndex = code.indexOf('$7zaOutput = node config/scripts/resolve-7za-path.mjs') + const exitCodeIndex = code.indexOf('$7zaExitCode = $LASTEXITCODE') + const exitGuard = blockAfter(source, 'if ($7zaExitCode -ne 0)') + const trimIndex = code.indexOf('$7za = ($7zaOutput | Out-String).Trim()') + + expect(resolveIndex).toBeGreaterThan(-1) + expect(exitCodeIndex).toBeGreaterThan(resolveIndex) + expect(exitGuard.start).toBeGreaterThan(exitCodeIndex) + expect(exitGuard.code).toMatch(/\bthrow\b/) + expect(trimIndex).toBeGreaterThan(exitGuard.end) + }) + + it(`${name} rejects an empty or non-file 7za path`, () => { + const source = workflowSource(name) + const guard = blockAfter( + source, + 'if ([string]::IsNullOrWhiteSpace($7za) -or -not (Test-Path -LiteralPath $7za -PathType Leaf))' + ) expect(guard.code).toMatch(/\bthrow\b/) }) }