From 47e25ef8542921e8cf176bac2a981bf52ae3632a Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Thu, 20 Aug 2026 14:00:40 +0800 Subject: [PATCH] fix(ci): judge a Mach-O's signature by codesign's exit status (#696) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `codesign -dv` spells its signature line differently per posture: `Signature=adhoc` for an ad-hoc or linker signature, `Signature size=8968` for a Developer ID one with a timestamp. The check matched the literal `Signature=`, which the second spelling does not contain. While the script only pointed at the standalone tty7-server, which is ad-hoc signed, that was invisible. #692 pointed it at the bundle's tty7-app, tty7 and tty7-updater as well, and those are Developer ID signed whenever the signing secrets are present. Pull requests do not see the secrets, so every PR run took the ad-hoc branch and passed; the first build that signed for real — the nightly — failed on all three binaries, printing `CodeDirectory`, `Signature size=8968` and a Developer ID `TeamIdentifier` as its proof they carried no signature. The binaries were signed, notarized and stapled; only the assertion was wrong. Exit status has no such split: 0 for anything signed, 1 with `code object is not signed at all` for anything not, verified against all three postures. The output is still captured so the failure message carries it. --- .github/scripts/assert-macho.sh | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/scripts/assert-macho.sh b/.github/scripts/assert-macho.sh index 9254fd20..54278023 100755 --- a/.github/scripts/assert-macho.sh +++ b/.github/scripts/assert-macho.sh @@ -66,8 +66,22 @@ fi # Rosetta shell (`uname -sm` = "Darwin x86_64"), and that is not a machine to # hand an unsigned binary to on a guess. The workflow signs it; this catches the # day it stops. -SIGNING=$(codesign -dv "$BIN" 2>&1 || true) -if [[ "$SIGNING" != *"Signature="* ]]; then +# The verdict is `codesign -dv`'s exit status, not a word in its output. It +# spells the signature line differently per posture — `Signature=adhoc` for an +# ad-hoc or linker signature, `Signature size=8968` for a Developer ID one with +# a timestamp — so the `*"Signature="*` this used to match held only for ad-hoc. +# While the script pointed at the standalone tty7-server, which is ad-hoc +# signed, that was invisible; #692 pointed it at the bundle's binaries as well, +# and those are Developer ID signed whenever the signing secrets are present. +# Pull requests do not see the secrets, so every PR run took the ad-hoc branch +# and passed, and the first build that signed for real — the nightly — failed +# on all three binaries with `Signature size=` in the very output it printed as +# proof they were unsigned. +# +# Exit status has no such split: 0 for anything signed, 1 with `code object is +# not signed at all` for anything not. The output is still captured so the +# failure message can carry it. +if ! SIGNING=$(codesign -dv "$BIN" 2>&1); then echo "::error::$BIN carries no code signature — arm64 macOS will refuse to run it" echo "$SIGNING" fail=1