fix(ci): judge a Mach-O's signature by codesign's exit status (#696)

`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.
This commit is contained in:
l0ng-ai
2026-08-20 14:00:40 +08:00
committed by GitHub
parent 51b0fe64b9
commit 47e25ef854
+16 -2
View File
@@ -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