fix(release): re-codesign macOS binaries after strip — v0.5.73 - #63
Merged
Conversation
`[profile.release].strip = "symbols"` in Cargo.toml strips the Mach-O
symbol table AFTER the linker has emitted an ad-hoc (linker-signed)
`CodeDirectory`. Strip changes the on-disk hash the CodeDirectory was
computed over, leaving the embedded signature internally inconsistent
with the file. macOS 26+'s hardened taskgated then refuses to launch
the binary at exec time with:
SIGKILL (Code Signature Invalid)
namespace=CODESIGNING
indicator="Taskgated Invalid Signature"
In v0.5.72 this hit `uffsmcp` and `uffsd` deterministically; `uffs`
and `uffs_mft` survived by binary-layout chance — a fragile guarantee
that wouldn't hold on the next rebuild.
Fix: add a `Re-codesign macOS binaries (post-strip)` step to
`.github/workflows/release.yml` that re-stamps the ad-hoc signature
with `codesign --force --sign -` on every shipping `apple-darwin`
binary AFTER `cargo build --release` finishes (and therefore after
strip has run). The step is gated on `contains(matrix.target,
'apple-darwin')` so Windows / Linux artifact paths stay untouched.
Each re-signed binary is then verified with `codesign --verify
--verbose=2` so a regression here fails the workflow loudly instead
of shipping broken artifacts.
We deliberately stay ad-hoc: there is no Apple Developer ID for this
project, so the resulting binaries are still unnotarized and users
will see the standard "open anyway" Gatekeeper prompt on first
launch. But they no longer get killed at exec time.
Workaround for users still on a v0.5.72 download:
codesign --force --sign - ~/bin/uffsmcp ~/bin/uffsd
Re-signs in place; macOS picks up the refreshed `CodeDirectory` on
the next exec and the binaries launch normally.
Bumps workspace version 0.5.72 → 0.5.73. On merge to `main`,
`auto-tag-release.yml` will dispatch `release.yml` to rebuild and
publish properly-signed binaries for x86_64-pc-windows-msvc,
aarch64-apple-darwin, and x86_64-unknown-linux-gnu.
Validation:
* `cargo check --workspace --all-targets` — clean.
* `cargo fmt --all --check` — clean.
* `cargo clippy --workspace --all-targets -- -D warnings` — clean.
No source code changes; release-only fix. Recommended upgrade for
every Mac user on macOS 26+.
githubrobbi
enabled auto-merge (squash)
April 25, 2026 21:05
githubrobbi
added a commit
that referenced
this pull request
Apr 25, 2026
…space root (#66) Phase R2 of `docs/architecture/release-automation-plan.md`. Adds a `git-cliff` configuration template at the workspace root that produces Keep-a-Changelog-compatible output from conventional-commit subjects. Stays purely additive; `CHANGELOG.md` is NOT touched (per plan §R2 step 4). ## What changed - **`cliff.toml`** — new file (~195 lines including documentation). Configures `git-cliff` to: - Render the existing UFFS `CHANGELOG.md` header verbatim (SPDX, Keep-a-Changelog + SemVer cite). - Use a Tera body template that emits `## [X.Y.Z] - YYYY-MM-DD` followed by `### Section` blocks per commit type group. - Map the 11 Conventional Commits types to changelog sections, matching `.github/workflows/commitlint.yml`'s regex AND `CONTRIBUTING.md → Commit message conventions`: - `feat:` → `### Added` - `feat!:` / `fix!:` / `BREAKING CHANGE:` → `### Breaking Changes` - `fix(security):` / `chore(security):` / `security:` → `### Security` (the third tolerates the non-standard `security:` prefix observed in PRs #31, #33, #34 during R1a's observation window) - `fix:` → `### Fixed` - `perf:` → `### Performance` - `refactor`, `docs`, `test`, `build`, `ci`, `chore`, `style`, `revert` → suppressed - `filter_unconventional = true`: drop commits that don't match Conventional Commits format outright (so the malformed `chore(dev + ci): ...` from PR #41 doesn't sneak under `### Changed`). - `tag_pattern = "v[0-9]+\\.[0-9]+\\.[0-9]+"` matching what `auto-tag-release.yml` emits today and what release-plz will emit in R4. Same anchor in both regimes — no migration needed. - `[remote.github]` block points at `skyllc-ai/UltraFastFileSearch` so the footer comparison links resolve correctly. - **`docs/architecture/release-automation-baseline.md`** — new §8 addendum captures R2 validation: - Output statistics (508 lines generated, 18 versions, 18 footer links — vs. 907 lines / 9 versions in the hand-curated original). - Type-mapping spot-checks against real commits in history. - Notes on two iteration issues caught and resolved during template tuning: extra blank line after `## [version]` headers (fixed via Tera whitespace controls), and duplicate PR links from manually rendering `[#NN](URL)` on top of the squash-subject's existing `(#NN)` (fixed by removing the manual link — GFM auto-links). - **`docs/architecture/release-automation-plan.md`** — dashboard flips R2 row to 🟡 with date and pointer to this PR. ## Validation - ✅ `cargo install git-cliff --locked` — installed `git-cliff 2.12.0`. - ✅ `git-cliff --config cliff.toml -o /tmp/uffs-cliff-full.md` — full history renders cleanly; 508 lines covering all 18 tagged releases from `v0.5.1` to `v0.5.73` with correct section grouping. - ✅ `git-cliff --config cliff.toml --unreleased` — produces a clean empty placeholder (every commit since v0.5.73 is `chore:`, all suppressed by parsers). - ✅ Spot-checked type → section mapping for `feat:` (#45), `fix:` (#63), `perf:` (#38), `chore(security):` parser registered, and `security:` non-standard prefix correctly captured under Security (#31, #33, #34). - ✅ Verified `chore(dev + ci):` (PR #41, malformed scope) is dropped by `filter_unconventional = true` — `grep -i "dev + ci"` against the generated output returns no match. - ✅ Footer comparison links: 17 use `compare/{prev}...{ver}`, 1 (the initial release v0.5.1) uses `releases/tag/{ver}` — correct Keep-a-Changelog convention. ## Why this PR is purely additive Per plan §R2 step 4: **R2 does NOT overwrite `CHANGELOG.md`**. The hand-maintained file stays exactly as-is. Phase R3-R4's release-plz will write the **next** release section above the existing `## [0.5.73]` header, leaving all prior entries intact. This means the loss of prose richness (multi-paragraph essays vs. single-line bullets) only applies to entries written by automation FROM NOW ON — historical entries are preserved verbatim. ## What this PR does NOT do - Install `git-cliff` in CI — R2 is a per-developer tool. Phase R3+ release-plz embeds git-cliff natively as a library; no CI install step is added until then. - Touch `CHANGELOG.md` — see above. - Configure `release-plz.toml` — that's R3. ## Rollback `git revert` this PR. `git-cliff` installation is per-developer and orthogonal; nothing in CI depends on `cliff.toml` yet. ## Refs - Plan: `docs/architecture/release-automation-plan.md` Phase R2 - git-cliff docs: https://git-cliff.org/docs/configuration - Tightly-coupled trio: `cliff.toml` + `.github/workflows/commitlint.yml` + `CONTRIBUTING.md` → "Commit message conventions" (adding a type means updating all three in the same PR)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a release-only bug that ships broken macOS arm64 binaries to every user on macOS 26+.
[profile.release].strip = "symbols"inCargo.tomlstrips the Mach-O symbol table after the linker has emitted an ad-hoc (linker-signed)CodeDirectory. Strip changes the on-disk hash theCodeDirectorywas computed over, leaving the embedded signature internally inconsistent with the file. macOS 26+'s hardenedtaskgatedthen refuses to launch the binary at exec time:In v0.5.72 this hits
uffsmcpanduffsddeterministically (downloaded from the GitHub Release ZIP);uffsanduffs_mftsurvive only by binary-layout chance — a fragile guarantee that wouldn't hold on the next rebuild.Fix
Add a
Re-codesign macOS binaries (post-strip)step to.github/workflows/release.ymlthat re-stamps the ad-hoc signature withcodesign --force --sign -on every shippingapple-darwinbinary aftercargo build --releasefinishes. Each re-signed binary is then verified withcodesign --verify --verbose=2so a regression here fails the workflow loudly instead of shipping broken artifacts.The step is gated on
contains(matrix.target, 'apple-darwin')so Windows / Linux artifact paths are untouched.We deliberately stay ad-hoc: there is no Apple Developer ID for this project, so the resulting binaries are still unnotarized and users see the standard "open anyway" Gatekeeper prompt on first launch. But they no longer get killed at exec time.
Workaround for users on v0.5.72
Re-signs in place; macOS picks up the refreshed
CodeDirectoryon the next exec and the binaries launch normally.Validation
cargo check --workspace --all-targets— cleancargo fmt --all --check— cleancargo clippy --workspace --all-targets -- -D warnings— cleanfmt,vet,typos,reuse,cargo-check,lint-prod,lint-tests,lint-ci,rustdoc,doc-tests,tests,smoke,deny,check-windows) — green, 119 scodesign --force --sign -on the v0.5.72 downloaded~/bin/uffsmcpand~/bin/uffsdmakes both launch successfully (uffsmcp 0.5.72).Release flow
After merge to
main:auto-tag-release.ymldetects the[workspace.package]version change0.5.72 → 0.5.73.release.ymlwithversion=v0.5.73.release.ymlbuilds, strips (per[profile.release]), then re-codesigns the four shipping binaries onaarch64-apple-darwin, and verifies the signature.Scope
No source code changes — release-pipeline only. Recommended upgrade for every Mac user on macOS 26+.