Skip to content

Commit 029e571

Browse files
committed
fix(release): Developer-ID sign nested computerd bundle before notarization
The computerd helpers ship as a nested .app resource (Resources/jcode-computerd.app) inside the Tauri app. Tauri signs the outer app and externalBin sidecars with Developer ID but does not re-sign resource bundles, so the ad-hoc signature from build_computerd_bundle.sh reached notarization and Apple rejected it: 'not signed with a valid Developer ID certificate', 'no secure timestamp', 'hardened runtime not enabled'. Add a CI step that imports the Developer ID cert into a throwaway keychain and re-signs the nested bundle (hardened runtime + secure timestamp, shared identifier) before 'pnpm tauri build'. Skipped when signing is disabled (no APPLE_CERTIFICATE), since Tauri then neither signs nor notarizes.
1 parent 7d40f7c commit 029e571

1 file changed

Lines changed: 69 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,75 @@ jobs:
401401
echo "notarization: DISABLED (no API key or Apple ID secrets)"
402402
fi
403403
404+
# The computerd bundle is a nested .app *resource* inside the Tauri app
405+
# (Resources/jcode-computerd.app). Tauri signs the outer app and its
406+
# externalBin sidecars with Developer ID, but does NOT re-sign resource
407+
# bundles — so the ad-hoc signature applied by build_computerd_bundle.sh
408+
# would survive into the notarization upload and Apple rejects it ("not
409+
# signed with a valid Developer ID certificate" / "no secure timestamp" /
410+
# "hardened runtime not enabled"). Re-sign the nested bundle here, before
411+
# `tauri build`, so the outer signature references a properly signed inner
412+
# bundle. Skipped when signing is disabled (no APPLE_CERTIFICATE): Tauri
413+
# then neither signs nor notarizes, and the ad-hoc bundle is fine for an
414+
# unsigned local build.
415+
- name: Sign computerd bundle (Developer ID)
416+
if: runner.os == 'macOS'
417+
shell: bash
418+
run: |
419+
set -euo pipefail
420+
if [ -z "${APPLE_CERTIFICATE:-}" ]; then
421+
echo "code-signing disabled — leaving ad-hoc signature (no notarization)"
422+
exit 0
423+
fi
424+
BUNDLE="desktop/src-tauri/bundles/jcode-computerd.app"
425+
426+
# Import the Developer ID certificate into a throwaway keychain so
427+
# codesign can use it. Tauri builds its own keychain later for the
428+
# outer app; the two coexist.
429+
KEYCHAIN="$RUNNER_TEMP/computerd-signing.keychain-db"
430+
KEYCHAIN_PW="$(openssl rand -hex 16)"
431+
security create-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN"
432+
security set-keychain-settings -lut 21600 "$KEYCHAIN"
433+
security unlock-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN"
434+
CERT="$RUNNER_TEMP/computerd-cert.p12"
435+
echo -n "$APPLE_CERTIFICATE" | base64 --decode > "$CERT"
436+
security import "$CERT" -P "$APPLE_CERTIFICATE_PASSWORD" \
437+
-A -t cert -f pkcs12 -k "$KEYCHAIN"
438+
security set-key-partition-list -S apple-tool:,apple: \
439+
-k "$KEYCHAIN_PW" "$KEYCHAIN" >/dev/null
440+
# Prepend our keychain so codesign resolves the identity. The
441+
# unquoted substitution is intentional: it expands to the list of
442+
# existing keychain paths, each a separate argument.
443+
# shellcheck disable=SC2046
444+
security list-keychains -d user -s "$KEYCHAIN" \
445+
$(security list-keychains -d user | tr -d '"')
446+
447+
# Resolve the signing identity (fall back to the first valid
448+
# codesigning identity in the keychain when not explicitly set).
449+
IDENTITY="${APPLE_SIGNING_IDENTITY:-}"
450+
if [ -z "$IDENTITY" ]; then
451+
IDENTITY="$(security find-identity -v -p codesigning "$KEYCHAIN" | awk -F'"' 'NR==1{print $2}')"
452+
fi
453+
[ -n "$IDENTITY" ] || { echo "no Developer ID signing identity found" >&2; exit 1; }
454+
455+
# Sign from the inside out: workers first, then the daemon, then the
456+
# bundle wrapper. Hardened runtime (--options runtime) + a secure
457+
# timestamp are both mandatory for notarization. A shared identifier
458+
# keeps the three binaries under one TCC identity (see the bundle
459+
# script header). The daemon uses only AX + ScreenCaptureKit, which
460+
# work under hardened runtime without extra entitlements.
461+
for bin in jcode-computerd-capture jcode-computerd-onboarding jcode-computerd; do
462+
[ -x "$BUNDLE/Contents/MacOS/$bin" ] || continue
463+
codesign --force --options runtime --timestamp \
464+
--sign "$IDENTITY" --identifier com.cnjack.jcode.computerd \
465+
"$BUNDLE/Contents/MacOS/$bin"
466+
done
467+
codesign --force --options runtime --timestamp \
468+
--sign "$IDENTITY" "$BUNDLE"
469+
470+
echo "Signed nested bundle with: $IDENTITY"
471+
codesign --verify --deep --strict --verbose=2 "$BUNDLE"
472+
404473
- name: Build desktop bundle
405474
shell: bash
406475
working-directory: desktop

0 commit comments

Comments
 (0)