Skip to content

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

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 known-good versions instead
of floating on whatever the runner happens to have, and SHA-pin the
three actions this workflow uses so a compromised tag can't swap in
different code under the same version label.

Pass the workflow_dispatch version input through the environment
instead of interpolating it into the PowerShell script body, so a
crafted dispatch input is read as data rather than executed.

After the installer is built, hash it with SHA256 and carry that hash
through: into the dry-run artifact alongside the exe, and into the
published release notes under a "Verify the download" section, so a
download can be checked without having to trust the hosting alone.
Release notes are regenerated from scratch on every run so a re-run
never appends a second checksum block to notes that already have one.

installer/agent-audit.iss now templates the app name via the existing
{#AppName} define on the three lines that previously hardcoded it, so
the installer filename, install icon, and packaged source name track
a single source of truth.
@joepetjr
joepetjr merged commit efd7958 into main Aug 4, 2026
4 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