Skip to content

fix(release): patch the correct Homebrew cask checksum stanza - #88

Merged
yvonnedevlinrh merged 5 commits into
unbound-force:mainfrom
mpeter:opsx/fix-cask-sha-stanza-targeting
Aug 24, 2026
Merged

fix(release): patch the correct Homebrew cask checksum stanza#88
yvonnedevlinrh merged 5 commits into
unbound-force:mainfrom
mpeter:opsx/fix-cask-sha-stanza-targeting

Conversation

@mpeter

@mpeter mpeter commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • replace the inline cask-patching awk with one checked-in integrity script used by the release workflow and PR CI
  • require exactly one darwin URL immediately preceded by its sha256, then compare the patched value literally
  • cross-check the downloaded darwin archive against the regenerated release manifest before touching the cask
  • add the real v0.5.0 GoReleaser template and failure fixtures for layout drift, comments, stale candidates, and malformed manifests

Root cause

GoReleaser emits each cask stanza as sha256 followed by url. The old workflow started scanning when it saw darwin_arm64 on the URL line, then replaced the next sha256 — the following linux_amd64 stanza.

In v0.5.0 this left darwin's stale pre-notarization SHA on the darwin stanza and wrote darwin's actual SHA onto the linux_amd64 stanza. brew install therefore failed on both macOS arm64 and Linux amd64. The old file-wide grep still passed because the darwin SHA appeared somewhere in the file.

The v0.5.0 tap remains broken until a subsequent release republishes the cask (or the tap is corrected separately). This PR makes subsequent releases self-heal from the clean GoReleaser cask asset.

Fixes #87

Verification

  • .github/scripts/patch-homebrew-cask_test.sh
    • exact expected cask on success; both Linux SHAs unchanged
    • missing/duplicate darwin URL
    • URL-before-SHA reordering
    • stray and trailing darwin_arm64 comments
    • stale checksum candidate from another stanza
    • missing/duplicate/mismatched manifest entry
    • original cask preserved and ::error:: emitted on every failure
  • actionlint v1.7.7 with ShellCheck v0.10.0: pass
  • direct ShellCheck of both scripts: pass
  • make check: pass
  • make check-coverage: pass (all ratchets)
  • go build ./cmd/replicator: pass
  • govulncheck ./...: no vulnerabilities
  • local review council: APPROVE from adversary, architecture, intent, testing, and operations reviewers

Process

  • OpenSpec: openspec/changes/fix-cask-sha-stanza-targeting/
  • finalized spec commit was pushed before implementation
  • actions/checkout remains pinned to verified v7.0.1 commit 3d3c42e5aac5ba805825da76410c181273ba90b1

mpeter added 5 commits August 22, 2026 15:54
Specify strict darwin stanza targeting, independent release-manifest
validation, and fixture-based regression tests executed by pull-request CI.
The production integrity logic will live in one checked-in script used by
both the release workflow and its tests.

Fixes: unbound-force#87
Replace the inline awk with one checked-in integrity script that computes
the downloaded darwin archive SHA, requires one matching release-manifest
entry, patches exactly one strictly-adjacent darwin stanza, and verifies
the result before replacing the cask.

Add the v0.5.0 cask template as a regression fixture and exercise malformed
stanzas, comments, stale candidates, and manifest failures in pull-request
CI. Invalid inputs leave the original cask unchanged.

Fixes: unbound-force#87
Separate the TOCTOU fix from the wrong-stanza checksum defect and record
that v0.5.0 remained broken on macOS arm64 and Linux amd64.
Compare the extracted SHA with awk string equality rather than a dynamic
regular expression, matching the specification's literal-comparison MUST.
Assert every negative fixture emits an error annotation and compare the
successful result against the complete expected cask.

Correct the OpenSpec impact and verification descriptions to match the
final CI and script surface.

@yvonnedevlinrh yvonnedevlinrh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: APPROVE

Bug Verification: CONFIRMED

Reproduced locally by running both old and new AWK scripts against the actual v0.5.0 replicator.rb cask template.

Cask stanza structuresha256 comes before url:

on_arm do
  sha256 "ea3278e..."      # line 7
  url "...darwin_arm64..."  # line 8 — marker is AFTER sha256
end
  • Old AWK: Forward-scan sets found_arm64=1 on the url line, then the next /sha256/ match belongs to linux_amd64wrong stanza patched.
  • New AWK: Two-pass records all lines, tracks most-recently-seen sha_line, snapshots it as darwin_sha_line when /darwin_arm64/ hits, patches only that line in END block → correct stanza patched.

Confirmed: old script produces linux_amd64 with darwin's hash; new script correctly patches only darwin_arm64.

@yvonnedevlinrh
yvonnedevlinrh merged commit 0ae387a into unbound-force:main Aug 24, 2026
1 check passed
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.

bug: publish-cask patches the wrong stanza's sha256, corrupting the Homebrew cask

3 participants