Skip to content

Commit 0663af0

Browse files
committed
chore: refactor mac os code signing
1 parent f754b19 commit 0663af0

File tree

2 files changed

+221
-190
lines changed

2 files changed

+221
-190
lines changed
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
name: macos-code-sign
2+
description: Configure, sign, notarize, and clean up macOS code signing artifacts.
3+
inputs:
4+
target:
5+
description: Rust compilation target triple (e.g. aarch64-apple-darwin).
6+
required: true
7+
apple-certificate:
8+
description: Base64-encoded Apple signing certificate (P12).
9+
required: true
10+
apple-certificate-password:
11+
description: Password for the signing certificate.
12+
required: true
13+
apple-notarization-key-p8:
14+
description: Base64-encoded Apple notarization key (P8).
15+
required: true
16+
apple-notarization-key-id:
17+
description: Apple notarization key ID.
18+
required: true
19+
apple-notarization-issuer-id:
20+
description: Apple notarization issuer ID.
21+
required: true
22+
runs:
23+
using: composite
24+
steps:
25+
- name: Configure Apple code signing
26+
shell: bash
27+
env:
28+
KEYCHAIN_PASSWORD: actions
29+
APPLE_CERTIFICATE: ${{ inputs.apple-certificate }}
30+
APPLE_CERTIFICATE_PASSWORD: ${{ inputs.apple-certificate-password }}
31+
run: |
32+
set -euo pipefail
33+
34+
if [[ -z "${APPLE_CERTIFICATE:-}" ]]; then
35+
echo "APPLE_CERTIFICATE is required for macOS signing"
36+
exit 1
37+
fi
38+
39+
if [[ -z "${APPLE_CERTIFICATE_PASSWORD:-}" ]]; then
40+
echo "APPLE_CERTIFICATE_PASSWORD is required for macOS signing"
41+
exit 1
42+
fi
43+
44+
cert_path="${RUNNER_TEMP}/apple_signing_certificate.p12"
45+
echo "$APPLE_CERTIFICATE" | base64 -d > "$cert_path"
46+
47+
keychain_path="${RUNNER_TEMP}/codex-signing.keychain-db"
48+
security create-keychain -p "$KEYCHAIN_PASSWORD" "$keychain_path"
49+
security set-keychain-settings -lut 21600 "$keychain_path"
50+
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$keychain_path"
51+
52+
keychain_args=()
53+
cleanup_keychain() {
54+
if ((${#keychain_args[@]} > 0)); then
55+
security list-keychains -s "${keychain_args[@]}" || true
56+
security default-keychain -s "${keychain_args[0]}" || true
57+
else
58+
security list-keychains -s || true
59+
fi
60+
if [[ -f "$keychain_path" ]]; then
61+
security delete-keychain "$keychain_path" || true
62+
fi
63+
}
64+
65+
while IFS= read -r keychain; do
66+
[[ -n "$keychain" ]] && keychain_args+=("$keychain")
67+
done < <(security list-keychains | sed 's/^[[:space:]]*//;s/[[:space:]]*$//;s/"//g')
68+
69+
if ((${#keychain_args[@]} > 0)); then
70+
security list-keychains -s "$keychain_path" "${keychain_args[@]}"
71+
else
72+
security list-keychains -s "$keychain_path"
73+
fi
74+
75+
security default-keychain -s "$keychain_path"
76+
security import "$cert_path" -k "$keychain_path" -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/security
77+
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$keychain_path" > /dev/null
78+
79+
codesign_hashes=()
80+
while IFS= read -r hash; do
81+
[[ -n "$hash" ]] && codesign_hashes+=("$hash")
82+
done < <(security find-identity -v -p codesigning "$keychain_path" \
83+
| sed -n 's/.*\([0-9A-F]\{40\}\).*/\1/p' \
84+
| sort -u)
85+
86+
if ((${#codesign_hashes[@]} == 0)); then
87+
echo "No signing identities found in $keychain_path"
88+
cleanup_keychain
89+
rm -f "$cert_path"
90+
exit 1
91+
fi
92+
93+
if ((${#codesign_hashes[@]} > 1)); then
94+
echo "Multiple signing identities found in $keychain_path:"
95+
printf ' %s\n' "${codesign_hashes[@]}"
96+
cleanup_keychain
97+
rm -f "$cert_path"
98+
exit 1
99+
fi
100+
101+
APPLE_CODESIGN_IDENTITY="${codesign_hashes[0]}"
102+
103+
rm -f "$cert_path"
104+
105+
echo "APPLE_CODESIGN_IDENTITY=$APPLE_CODESIGN_IDENTITY" >> "$GITHUB_ENV"
106+
echo "APPLE_CODESIGN_KEYCHAIN=$keychain_path" >> "$GITHUB_ENV"
107+
echo "::add-mask::$APPLE_CODESIGN_IDENTITY"
108+
109+
- name: Sign macOS binaries
110+
shell: bash
111+
run: |
112+
set -euo pipefail
113+
114+
if [[ -z "${APPLE_CODESIGN_IDENTITY:-}" ]]; then
115+
echo "APPLE_CODESIGN_IDENTITY is required for macOS signing"
116+
exit 1
117+
fi
118+
119+
keychain_args=()
120+
if [[ -n "${APPLE_CODESIGN_KEYCHAIN:-}" && -f "${APPLE_CODESIGN_KEYCHAIN}" ]]; then
121+
keychain_args+=(--keychain "${APPLE_CODESIGN_KEYCHAIN}")
122+
fi
123+
124+
for binary in codex codex-responses-api-proxy; do
125+
path="codex-rs/target/${{ inputs.target }}/release/${binary}"
126+
codesign --force --options runtime --timestamp --sign "$APPLE_CODESIGN_IDENTITY" "${keychain_args[@]}" "$path"
127+
done
128+
129+
- name: Notarize macOS binaries
130+
shell: bash
131+
env:
132+
APPLE_NOTARIZATION_KEY_P8: ${{ inputs.apple-notarization-key-p8 }}
133+
APPLE_NOTARIZATION_KEY_ID: ${{ inputs.apple-notarization-key-id }}
134+
APPLE_NOTARIZATION_ISSUER_ID: ${{ inputs.apple-notarization-issuer-id }}
135+
run: |
136+
set -euo pipefail
137+
138+
for var in APPLE_NOTARIZATION_KEY_P8 APPLE_NOTARIZATION_KEY_ID APPLE_NOTARIZATION_ISSUER_ID; do
139+
if [[ -z "${!var:-}" ]]; then
140+
echo "$var is required for notarization"
141+
exit 1
142+
fi
143+
done
144+
145+
notary_key_path="${RUNNER_TEMP}/notarytool.key.p8"
146+
echo "$APPLE_NOTARIZATION_KEY_P8" | base64 -d > "$notary_key_path"
147+
cleanup_notary() {
148+
rm -f "$notary_key_path"
149+
}
150+
trap cleanup_notary EXIT
151+
152+
notarize_binary() {
153+
local binary="$1"
154+
local source_path="codex-rs/target/${{ inputs.target }}/release/${binary}"
155+
local archive_path="${RUNNER_TEMP}/${binary}.zip"
156+
157+
if [[ ! -f "$source_path" ]]; then
158+
echo "Binary $source_path not found"
159+
exit 1
160+
fi
161+
162+
rm -f "$archive_path"
163+
ditto -c -k --keepParent "$source_path" "$archive_path"
164+
165+
submission_json=$(xcrun notarytool submit "$archive_path" \
166+
--key "$notary_key_path" \
167+
--key-id "$APPLE_NOTARIZATION_KEY_ID" \
168+
--issuer "$APPLE_NOTARIZATION_ISSUER_ID" \
169+
--output-format json \
170+
--wait)
171+
172+
status=$(printf '%s\n' "$submission_json" | jq -r '.status // "Unknown"')
173+
submission_id=$(printf '%s\n' "$submission_json" | jq -r '.id // ""')
174+
175+
if [[ -z "$submission_id" ]]; then
176+
echo "Failed to retrieve submission ID for $binary"
177+
exit 1
178+
fi
179+
180+
echo "::notice title=Notarization::$binary submission ${submission_id} completed with status ${status}"
181+
182+
if [[ "$status" != "Accepted" ]]; then
183+
echo "Notarization failed for ${binary} (submission ${submission_id}, status ${status})"
184+
exit 1
185+
fi
186+
}
187+
188+
notarize_binary "codex"
189+
notarize_binary "codex-responses-api-proxy"
190+
191+
- name: Remove signing keychain
192+
if: ${{ always() }}
193+
shell: bash
194+
env:
195+
APPLE_CODESIGN_KEYCHAIN: ${{ env.APPLE_CODESIGN_KEYCHAIN }}
196+
run: |
197+
set -euo pipefail
198+
if [[ -n "${APPLE_CODESIGN_KEYCHAIN:-}" ]]; then
199+
keychain_args=()
200+
while IFS= read -r keychain; do
201+
[[ "$keychain" == "$APPLE_CODESIGN_KEYCHAIN" ]] && continue
202+
[[ -n "$keychain" ]] && keychain_args+=("$keychain")
203+
done < <(security list-keychains | sed 's/^[[:space:]]*//;s/[[:space:]]*$//;s/"//g')
204+
if ((${#keychain_args[@]} > 0)); then
205+
security list-keychains -s "${keychain_args[@]}"
206+
security default-keychain -s "${keychain_args[0]}"
207+
fi
208+
209+
if [[ -f "$APPLE_CODESIGN_KEYCHAIN" ]]; then
210+
security delete-keychain "$APPLE_CODESIGN_KEYCHAIN"
211+
fi
212+
fi

0 commit comments

Comments
 (0)