Skip to content

fix(release): preserve signed Windows zip filename, match checksum format - #3556

Merged
max-sixty merged 1 commit into
mainfrom
signpath-code-signing
Jul 23, 2026
Merged

fix(release): preserve signed Windows zip filename, match checksum format#3556
max-sixty merged 1 commit into
mainfrom
signpath-code-signing

Conversation

@max-sixty

Copy link
Copy Markdown
Owner

Summary

  • The SignPath action's skip-decompress defaults to false, so it would have extracted the returned zip's contents as loose files into target/distrib/ instead of saving back a signed worktrunk-x86_64-pc-windows-msvc.zip. The checksum step would have silently hashed the still-unsigned zip, and the release would have shipped unsigned Windows binaries with no CI failure to flag it.
  • sha256sum without -b omits the * binary-mode marker; cargo-dist's own checksums use <hash> *<filename> (confirmed against a real release asset). Added -b to match.

Confirmed via gh run view on #3553's own CI run that build-local-artifacts is skipped on PRs in this repo, so this code path has never actually executed — this is the first real fix before it runs for real on a tagged release.

Test plan

  • actionlint .github/workflows/release.yaml — no new warnings (same pre-existing shellcheck style notes as before)
  • Verified skip-decompress behavior against the action's own action.yml input spec
  • Verified checksum format against a real downloaded release asset (v0.68.0)

This was written by Claude Code on behalf of Max

…rmat

skip-decompress defaults to false, so the SignPath action was extracting
the returned zip's contents as loose files instead of saving back the
signed worktrunk-x86_64-pc-windows-msvc.zip — the checksum step would
have silently hashed the still-unsigned zip. Also add sha256sum -b to
match cargo-dist's own <hash> *<filename> checksum format.
@max-sixty
max-sixty merged commit 8f55d15 into main Jul 23, 2026
39 checks passed
@max-sixty
max-sixty deleted the signpath-code-signing branch July 23, 2026 23:13
@max-sixty max-sixty mentioned this pull request Jul 23, 2026
@max-sixty max-sixty mentioned this pull request Jul 25, 2026
max-sixty added a commit that referenced this pull request Jul 25, 2026
Cuts v0.69.2, and fixes the Windows code-signing path it depends on.

## The signing fix

v0.69.1 shipped an unsigned `wt.exe` under a green run and a
**Completed** SignPath signing request. `archive: false` (#3566) had
already made the GitHub artifact name
`worktrunk-x86_64-pc-windows-msvc.zip`, and SignPath names its download
after the artifact — so with `output-artifact-directory: target/distrib`
the signed zip landed at `worktrunk-x86_64-pc-windows-msvc.zip.zip`,
beside the untouched unsigned build. The checksum step and the release
upload both kept reading the original. Confirmed by parsing the
published asset's PE certificate table: `size=0`.

The download now goes to a scratch directory and whatever single file
lands there replaces the built zip, so SignPath's naming isn't
load-bearing.

## Verification, because this failure is invisible

Signing is `continue-on-error` by design (self-signed test certificate
pending SignPath's OSS review), so nothing in the logs distinguishes
"signed" from "silently unsigned" — which is how it slipped through
twice, two different ways. `.github/verify-windows-signature.py` reads
the zip's PE certificate tables directly, and runs at two points with
distinct jobs:

- **before the overwrite** — an unsigned release is tolerable while the
certificate is a test one; a corrupt one never is, so the replacement
has to verify before it can clobber a good build.
- **after** — reports what the release actually ships, which is the
question the logs never answered.

## Rehearsed before landing

The signing path only runs on a tag, so each question about it used to
cost a release. This chain was instead run on a Windows runner against
the already-published v0.69.1 zip (identical bytes, no build):

```
saved to …\target\signpath\worktrunk-x86_64-pc-windows-msvc.zip.zip
git-wt.exe: certificate table 8480 bytes
wt.exe:     certificate table 8472 bytes
→ mv → target/distrib/worktrunk-x86_64-pc-windows-msvc.zip
target/distrib/worktrunk-x86_64-pc-windows-msvc.zip: all 2 executables signed
worktrunk-x86_64-pc-windows-msvc.zip: OK   (checksum matches)
```

That also settled the open question behind #3556: SignPath returns the
signed zip itself, not a wrapper, so `skip-decompress: true` is correct
— the extract mode does explode it into loose files.

## Release contents

`wt remove`'s fsmonitor sweep (#3581), the troubleshooting doc trim, and
this fix. The two refactors in range (#3582, #3584) are
behavior-preserving and omitted per convention.

Local gate green (4547 passed). Changelog entries verified against the
diffs by subagent; two claims corrected (the doc entry's rationale, and
an overclaim attributing v0.69.0's unsigned binary to this bug rather
than the separate upload failure #3566 fixed). Data-loss surface
reviewed across the cumulative diff.

> _This was written by Claude Code on behalf of max_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants