diff --git a/.github/verify-windows-signature.py b/.github/verify-windows-signature.py index bf8158f7d3..0fedff4a81 100644 --- a/.github/verify-windows-signature.py +++ b/.github/verify-windows-signature.py @@ -1,15 +1,12 @@ """Report whether every executable in the Windows release zip is signed. -The signing chain is silent when it breaks, and it broke two different ways in -a row under a green run: v0.69.0's signing request failed outright, and -v0.69.1's completed while the signed file never reached the release. This reads -the shipped zip itself, so nothing but the published bytes can satisfy it. - -Reports rather than blocks — the caller runs it with continue-on-error, since -SignPath is on a self-signed test certificate while the project's OSS -application is under review and publishing must not depend on it. For the same -reason this checks that a certificate is present, not that it chains to a -trusted root. +The signing chain breaks silently — v0.69.0 and v0.69.1 both shipped unsigned +under a green run, two different ways — so this reads the zip itself and +nothing but the published bytes can satisfy it. + +It checks that a certificate is present, not that it chains to a trusted root: +SignPath is on a self-signed test certificate pending the project's OSS +application, which is also why the caller runs this with continue-on-error. Usage: python .github/verify-windows-signature.py """ diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0ae0a487fb..5e9ef87dbe 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -159,15 +159,11 @@ jobs: continue-on-error: true uses: actions/upload-artifact@v7 with: - # actions/upload-artifact always wraps the upload in its own - # storage zip unless archive: false — since the file we're - # uploading is already a zip, the default produced a zip-of-a-zip - # that SignPath saw as "the artifact", so the configured - # paths never matched (confirmed via a real - # signing-request failure: "Expected path to match exactly 1 - # item, but found 0", processing unsigned-windows-zip.zip). - # archive: false uploads the file as-is; the artifact name then - # becomes the file's own name, so `name:` here is ignored. + # The file is already a zip, and upload-artifact wraps its uploads + # in a storage zip unless told not to — SignPath would then look + # for the PE files one level too deep. archive: false also makes + # the artifact take the file's own name (ignoring `name:`), which + # is what the signing step's output directory has to work around. archive: false path: target/distrib/worktrunk-x86_64-pc-windows-msvc.zip - name: Submit SignPath signing request @@ -183,14 +179,12 @@ jobs: github-artifact-id: '${{ steps.upload-unsigned-windows-artifact.outputs.artifact-id }}' wait-for-completion: true # A scratch directory, not target/distrib: SignPath names the - # download after the GitHub artifact, which is already - # worktrunk-x86_64-pc-windows-msvc.zip, so writing it alongside the - # unsigned build would land it at …zip.zip and leave the unsigned - # original in place (how v0.69.1 shipped unsigned). The next step - # takes whatever lands here, so SignPath's naming doesn't matter. + # download after the artifact, so it would land beside the build as + # …zip.zip and leave the unsigned original in place — how v0.69.1 + # shipped unsigned. The next step takes whatever lands here. output-artifact-directory: 'target/signpath' - # Without this, the action extracts the returned zip's contents as - # loose files instead of saving back the signed zip. + # Without this the action unpacks the returned zip into loose files + # instead of saving it back whole. skip-decompress: true - name: Replace the Windows artifact with the signed one if: contains(matrix.targets, 'x86_64-pc-windows-msvc') && steps.signpath.outcome == 'success' @@ -209,6 +203,10 @@ jobs: # shipping a corrupt one never is. python .github/verify-windows-signature.py "${signed[0]}" mv "${signed[0]}" target/distrib/worktrunk-x86_64-pc-windows-msvc.zip + # Deliberately not continue-on-error, unlike the signing steps: shipping + # unsigned is tolerable while the certificate is a test one, shipping a + # checksum that doesn't match the zip is not. That is also why this + # doesn't fold into the step above. - name: Recompute checksum for signed Windows artifact if: contains(matrix.targets, 'x86_64-pc-windows-msvc') shell: bash