diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4b413aa4b..ae6382f14 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -255,6 +255,37 @@ jobs: echo "✅ Build completed for ${{ matrix.target }}" + - name: Re-codesign macOS binaries (post-strip) + if: contains(matrix.target, 'apple-darwin') + shell: bash + run: | + # `[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 signature + # internally inconsistent. macOS 26+'s taskgated then refuses + # to launch the binary with `SIGKILL (Code Signature Invalid)` + # / namespace=CODESIGNING / "Taskgated Invalid Signature". + # + # Re-stamping the ad-hoc signature with `codesign --force + # --sign -` recomputes the CodeDirectory over the post-strip + # bytes so the in-memory hash matches the on-disk file again. + # We deliberately stay ad-hoc: we don't have an Apple Developer + # ID; 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. + # + # Gated on `apple-darwin` so Windows / Linux artifact paths + # stay untouched. + set -euo pipefail + for bin in uffs uffsd uffsmcp uffs_mft; do + path="target/${{ matrix.target }}/release/$bin" + if [[ -f "$path" ]]; then + codesign --force --sign - "$path" + codesign --verify --verbose=2 "$path" + fi + done + - name: Show binary sizes shell: bash run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eaf4f4b9..b2c55a74d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.5.73] - 2026-04-25 + +### Fixed +- **macOS arm64 release binaries SIGKILLed at launch** under macOS 26+ + (`SIGKILL (Code Signature Invalid)` / `namespace=CODESIGNING` / + `"Taskgated Invalid Signature"`). `[profile.release].strip = "symbols"` + in `Cargo.toml` strips the Mach-O symbol table **after** the linker has + emitted an ad-hoc (linker-signed) `CodeDirectory`, leaving the embedded + hash inconsistent with the on-disk file. macOS 26+'s hardened + taskgated then refuses to launch the binary. 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 + `release.yml` that re-stamps the ad-hoc signature with `codesign + --force --sign -` on every shipping `apple-darwin` binary after + `cargo build --release` finishes. The step is gated on + `contains(matrix.target, 'apple-darwin')` so Windows / Linux artifact + paths are 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. + + Workaround for users still on a v0.5.72 download: + + ```bash + 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. + + No code changes; release-only fix. Recommended upgrade for every Mac + user on macOS 26+. + ## [0.5.72] - 2026-04-25 ### Changed diff --git a/Cargo.lock b/Cargo.lock index f16ff3e1d..f14e07f9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4335,7 +4335,7 @@ checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" [[package]] name = "uffs-broker" -version = "0.5.72" +version = "0.5.73" dependencies = [ "anyhow", "tracing", @@ -4346,7 +4346,7 @@ dependencies = [ [[package]] name = "uffs-ci-pipeline" -version = "0.5.72" +version = "0.5.73" dependencies = [ "anyhow", "chrono", @@ -4363,7 +4363,7 @@ dependencies = [ [[package]] name = "uffs-cli" -version = "0.5.72" +version = "0.5.73" dependencies = [ "anyhow", "assert_cmd", @@ -4377,7 +4377,7 @@ dependencies = [ [[package]] name = "uffs-client" -version = "0.5.72" +version = "0.5.73" dependencies = [ "dirs-next", "libc", @@ -4395,7 +4395,7 @@ dependencies = [ [[package]] name = "uffs-core" -version = "0.5.72" +version = "0.5.73" dependencies = [ "aho-corasick", "anyhow", @@ -4425,7 +4425,7 @@ dependencies = [ [[package]] name = "uffs-daemon" -version = "0.5.72" +version = "0.5.73" dependencies = [ "anyhow", "clap", @@ -4451,7 +4451,7 @@ dependencies = [ [[package]] name = "uffs-diag" -version = "0.5.72" +version = "0.5.73" dependencies = [ "anyhow", "chrono", @@ -4464,7 +4464,7 @@ dependencies = [ [[package]] name = "uffs-format" -version = "0.5.72" +version = "0.5.73" dependencies = [ "chrono", "itoa", @@ -4476,7 +4476,7 @@ dependencies = [ [[package]] name = "uffs-mcp" -version = "0.5.72" +version = "0.5.73" dependencies = [ "anyhow", "axum", @@ -4497,7 +4497,7 @@ dependencies = [ [[package]] name = "uffs-mft" -version = "0.5.72" +version = "0.5.73" dependencies = [ "anyhow", "bitflags", @@ -4533,14 +4533,14 @@ dependencies = [ [[package]] name = "uffs-polars" -version = "0.5.72" +version = "0.5.73" dependencies = [ "polars", ] [[package]] name = "uffs-security" -version = "0.5.72" +version = "0.5.73" dependencies = [ "aes-gcm", "dirs-next", @@ -4553,14 +4553,14 @@ dependencies = [ [[package]] name = "uffs-text" -version = "0.5.72" +version = "0.5.73" dependencies = [ "bytemuck", ] [[package]] name = "uffs-time" -version = "0.5.72" +version = "0.5.73" [[package]] name = "unarray" diff --git a/Cargo.toml b/Cargo.toml index 4bde09686..e4f63a2f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ members = [ # Workspace Package Metadata (inherited by all crates) # ───────────────────────────────────────────────────────────────────────────── [workspace.package] -version = "0.5.72" +version = "0.5.73" edition = "2024" # MSRV: Pure Rust code compiles on stable 1.91+ (Duration::from_mins), # but Polars is built with features = ["nightly", "simd"] which requires