Skip to content

ci(release): the published installer can be verified, and its build is pinned - #7

Merged
joepetjr merged 1 commit into
mainfrom
chore/release-supply-chain
Aug 4, 2026
Merged

joepetjr merged 1 commit into
mainfrom
chore/release-supply-chain

Conversation

@joepetjr

@joepetjr joepetjr commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Release supply-chain hardening, applied identically across keycut, redactcam, agent-audit and claude-batch-runner so the four installers stay one shape.

  • The published installer can be verified. The build now hashes the exe with SHA256, ships SHA256SUMS as a release asset, and repeats the hash in the release notes under "Verify the download". Until now a downloader had nothing to check the binary against.
  • The build is pinned. pyinstaller==6.21.0 and choco install innosetup --version=6.7.1 instead of floating on whatever the runner resolves that day, and the three actions/* are SHA-pinned so a retagged action cannot swap in different code under the same label.
  • The dispatch input is data, not template text. ${{ inputs.version }} was expanded into the PowerShell script body before PowerShell parsed it; it now arrives through the environment as $env:DISPATCH_VERSION. This workflow holds contents: write.
  • Release notes are rebuilt from scratch each run, so re-running a release cannot append a second checksum block to notes that already carry one.
  • .iss templating. The three lines that hardcoded the app name (UninstallDisplayIcon, OutputBaseFilename, Source:) now use the {#AppName} define the file already declared, matching what claude-batch-runner already did. The pure-ASCII warning comment agent-audit carried is now in all four.

Test plan

This workflow only runs on Windows, on a v* tag push, so CI here cannot exercise it. What was checked:

  • yaml.safe_load parses the edited release.yml.
  • The .iss still decodes as pure ASCII — the property its own comment asks for.
  • git status confirms only .github/workflows/release.yml and installer/<name>.iss changed.
  • The four repos' added lines were diffed against each other after normalizing the app name: identical in all four, so no repo drifted from the shared shape.

The first real proof is a workflow_dispatch dry run, which builds everything and deliberately publishes nothing — worth doing on one repo before the next tagged release.

Note

The version pins were resolved live against PyPI and the Chocolatey package page on 2026-08-04. They will need bumping like any other pin; that is the tradeoff being bought.

…s pinned

Pin PyInstaller and Inno Setup to specific versions so the build is
reproducible instead of drifting to whatever chocolatey and pip happen
to resolve on a given day. Pass the workflow_dispatch version through
the environment rather than interpolating it into the PowerShell script
body, so a crafted dispatch input is read as data instead of executed.
SHA-pin the three third-party actions instead of trusting a mutable
version tag.

Hash the installer after it is built, ship the SHA256SUMS file as a
release asset, and repeat the checksum in the release notes so a
download can be verified without fetching anything else. Release notes
are now generated fresh on every run instead of accreted with
--generate-notes, so re-running a release cannot append a second
checksum block to notes that already have one.
@joepetjr
joepetjr merged commit 15625d6 into main Aug 4, 2026
3 checks passed
@joepetjr
joepetjr deleted the chore/release-supply-chain branch August 4, 2026 13:24
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.

1 participant