-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.sh
More file actions
executable file
Β·326 lines (274 loc) Β· 10.3 KB
/
Copy pathbuild.sh
File metadata and controls
executable file
Β·326 lines (274 loc) Β· 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
#!/bin/bash
set -e
# Build and (optionally) sign+notarize the dir binary.
#
# For normal development you do not need this script:
# go build -o dir . # build in place
# go install # build and install to $GOPATH/bin (or $GOBIN)
#
# This script is only needed when distributing a signed+notarized binary.
# Run it from the root of the dir repository.
BINARY="dir"
IDENTITY='Developer ID Application: WILLIAM ANTONY MC NAMARA (VC4YYTGXP7)'
NOTARY_PROFILE="${NOTARY_PROFILE:-}"
NOBUILD=false
SIGN_BINARY=false
BUILD_UNIVERSAL=false
usage() {
cat <<EOF
Usage: $0 [-nobuild] [-universal] [-sign] [-h|--help]
For everyday development, use standard Go tooling instead:
go build -o dir . Build the binary in the current directory
go install Build and install to \$GOPATH/bin (or \$GOBIN)
go test ./... Run the test suite
bash verify_search.sh Run integration verification
This script adds:
-universal Build a universal (arm64 + x86_64) binary via lipo
-sign Code-sign and notarize with Developer ID (requires NOTARY_PROFILE)
-nobuild Skip the Go build; sign/notarize the existing binary
-h/--help Show this help
Signing requires:
1. Xcode Command Line Tools (xcrun, codesign, spctl)
2. Developer ID Application certificate in your Keychain
3. A notarytool credential profile, e.g.:
xcrun notarytool store-credentials "AC_NOTARY" \\
--apple-id "you@domain.com" \\
--team-id "VC4YYTGXP7" \\
--password "app-specific-password"
4. NOTARY_PROFILE set to that profile name, e.g.:
NOTARY_PROFILE=AC_NOTARY ./build.sh -sign
Note: standalone binaries receive a notarization ticket but cannot be stapled.
Distribute inside a signed+stapled .dmg or .pkg if Gatekeeper assessment is required.
EOF
}
verify_release_signature() {
local binary="$1"
local expected_identity='Developer ID Application: WILLIAM ANTONY MC NAMARA (VC4YYTGXP7)'
local expected_team="VC4YYTGXP7"
local details
echo "π Verifying release signature for $binary"
if [ ! -f "$binary" ]; then
echo "β Error: binary not found: $binary"
return 1
fi
codesign --verify --strict --verbose=4 "$binary" || {
echo "β Error: codesign verification failed for $binary"
return 1
}
details="$(codesign -dv --verbose=4 "$binary" 2>&1)"
if ! printf '%s\n' "$details" | grep -Fq "Authority=${expected_identity}"; then
echo "β Error: $binary is not signed with the expected Developer ID identity."
printf '%s\n' "$details"
return 1
fi
if ! printf '%s\n' "$details" | grep -Fq "TeamIdentifier=${expected_team}"; then
echo "β Error: $binary is not signed by the expected team (${expected_team})."
printf '%s\n' "$details"
return 1
fi
if ! printf '%s\n' "$details" | grep -Fq "flags=0x10000(runtime)"; then
echo "β Error: $binary is missing the hardened runtime flag required for notarization."
printf '%s\n' "$details"
return 1
fi
echo "β
Release signature verified"
}
assess_gatekeeper() {
local binary="$1"
local label="$2"
local output status
set +e
output="$(spctl --assess --type execute --verbose=4 "$binary" 2>&1)"
status=$?
set -e
printf '%s\n' "$output"
if [ "$status" -eq 0 ]; then
echo "$label: accepted"
return 0
fi
if printf '%s\n' "$output" | grep -Fq "source=Unnotarized Developer ID"; then
echo "$label: standalone binary assessed as Unnotarized Developer ID."
echo "(Informational: standalone executables do not receive a stapled ticket.)"
return 0
fi
echo "β $label: unexpected Gatekeeper assessment failure" >&2
return 1
}
for arg in "$@"; do
case $arg in
-nobuild)
NOBUILD=true
echo "π¦ Skipping build; will sign existing binary."
;;
-universal)
BUILD_UNIVERSAL=true
echo "𧬠Universal binary (arm64 + x86_64) requested."
;;
-sign)
SIGN_BINARY=true
echo "π Code signing enabled."
;;
-h|--help|-help)
usage
exit 0
;;
*)
echo "β οΈ Unknown flag: $arg" >&2
usage >&2
exit 1
;;
esac
done
if [ "$NOBUILD" = true ] && [ "$BUILD_UNIVERSAL" = true ]; then
echo "β Error: -nobuild and -universal are mutually exclusive." >&2
exit 1
fi
# ββ Step 1: Build ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if [ "$NOBUILD" = true ]; then
echo "βοΈ Skipping build (-nobuild)."
if [ ! -f "$BINARY" ]; then
echo "β Error: $BINARY not found. Remove -nobuild or build first." >&2
exit 1
fi
elif [ "$BUILD_UNIVERSAL" = true ]; then
echo "π¨ Building dir (arm64)..."
GOARCH=arm64 GOOS=darwin go build -o "${BINARY}_arm64" .
echo "π¨ Building dir (x86_64)..."
GOARCH=amd64 GOOS=darwin go build -o "${BINARY}_amd64" .
echo "𧬠Creating universal binary..."
lipo -create "${BINARY}_arm64" "${BINARY}_amd64" -output "$BINARY"
rm -f "${BINARY}_arm64" "${BINARY}_amd64"
echo "π Universal archs: $(lipo -archs "$BINARY")"
echo "β
Universal build complete."
else
echo "π¨ Building dir..."
go build -o "$BINARY" .
echo "β
Build complete."
fi
# ββ Step 2: Sign and notarize ββββββββββββββββββββββββββββββββββββββββββββββββββ
if [ "$SIGN_BINARY" = false ]; then
echo ""
echo "βΉοΈ Binary built but not signed. Pass -sign to code-sign and notarize."
exit 0
fi
if [ -z "$NOTARY_PROFILE" ]; then
echo "β Error: NOTARY_PROFILE is not set." >&2
echo "Example: NOTARY_PROFILE=AC_NOTARY ./build.sh -sign" >&2
exit 1
fi
if ! command -v xcrun >/dev/null 2>&1; then
echo "β Error: xcrun not found. Install Xcode Command Line Tools." >&2
exit 1
fi
for tool in codesign security spctl zip shasum python3; do
command -v "$tool" >/dev/null 2>&1 || {
echo "β Error: required tool not found: $tool" >&2
exit 1
}
done
if ! security find-identity -v -p codesigning 2>/dev/null | grep -Fq "$IDENTITY"; then
echo "β Error: signing identity not found in your Keychain:" >&2
echo " $IDENTITY" >&2
echo "Available identities:" >&2
security find-identity -v -p codesigning 2>/dev/null || true
exit 1
fi
echo ""
echo "β οΈ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ"
echo "β οΈ π SIGNING dir BINARY WITH DEVELOPER ID"
echo "β οΈ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ"
echo "Binary: $BINARY"
echo "Identity: $IDENTITY"
echo "Notary profile: $NOTARY_PROFILE"
echo ""
echo "== Pre-sign status (if already signed) =="
codesign -dv --verbose=4 "$BINARY" 2>&1 || true
echo ""
chmod u+w "$BINARY" || true
echo "== Sign (Developer ID + hardened runtime + timestamp) =="
codesign --force \
--sign "$IDENTITY" \
--options runtime \
--timestamp \
--verbose \
"$BINARY"
echo ""
echo "== Verify signature (codesign) =="
codesign --verify --strict --verbose=4 "$BINARY"
codesign -dv --verbose=4 "$BINARY" 2>&1
echo ""
echo "== Gatekeeper assessment (pre-notarization, informational) =="
assess_gatekeeper "$BINARY" "Pre-notarization"
echo ""
echo "== Create notarization archive =="
TMPDIR_NOTARY="$(mktemp -d)"
cleanup() { rm -rf "$TMPDIR_NOTARY"; }
trap cleanup EXIT
STAGE="$TMPDIR_NOTARY/stage"
mkdir -p "$STAGE"
cp -p "$BINARY" "$STAGE/$BINARY"
ZIP_OUT="$TMPDIR_NOTARY/dir_notarize.zip"
(
cd "$STAGE"
zip -qryX "$ZIP_OUT" "$BINARY"
)
echo "Zip: $ZIP_OUT"
echo "Zip SHA-256: $(shasum -a 256 "$ZIP_OUT" | awk '{print $1}')"
echo ""
echo "== Submit for notarization (waiting) =="
SUBMIT_JSON="$TMPDIR_NOTARY/notary_submit.json"
SUBMIT_ERROR="$TMPDIR_NOTARY/notary_submit.stderr"
set +e
xcrun notarytool submit "$ZIP_OUT" \
--keychain-profile "$NOTARY_PROFILE" \
--wait \
--output-format json 2>"$SUBMIT_ERROR" | tee "$SUBMIT_JSON"
SUBMIT_STATUS=${PIPESTATUS[0]}
set -e
cat "$SUBMIT_ERROR" >&2
if [ "$SUBMIT_STATUS" -ne 0 ]; then
if grep -Eiq 'required agreement is missing|agreement.*(expired|not been signed)' \
"$SUBMIT_ERROR" "$SUBMIT_JSON" 2>/dev/null; then
echo "" >&2
echo "β Apple Developer agreement action required." >&2
echo " Sign in as the team Account Holder and accept the pending agreement:" >&2
echo " https://developer.apple.com/account/" >&2
echo " Look for the \"Review Agreement\" banner, accept, then retry." >&2
fi
exit "$SUBMIT_STATUS"
fi
echo ""
echo "== Notarization summary =="
python3 - <<'PY' "$SUBMIT_JSON"
import json, sys
data = json.load(open(sys.argv[1]))
for k in ("id", "status", "message", "createdDate", "finishedDate"):
if k in data:
print(f"{k}: {data[k]}")
status = data.get("status", "").lower()
if status not in ("accepted", "success"):
raise SystemExit(2)
PY
REQUEST_ID="$(python3 - <<'PY' "$SUBMIT_JSON"
import json, sys
print(json.load(open(sys.argv[1])).get("id", ""))
PY
)"
echo ""
echo "== Notarization log =="
if [ -n "$REQUEST_ID" ]; then
xcrun notarytool log "$REQUEST_ID" --keychain-profile "$NOTARY_PROFILE" || true
fi
echo ""
echo "== Post-notarization verification =="
codesign --verify --strict --verbose=4 "$BINARY"
codesign -dv --verbose=4 "$BINARY" 2>&1
echo ""
echo "== Gatekeeper assessment (post-notarization, informational) =="
assess_gatekeeper "$BINARY" "Post-notarization"
echo ""
verify_release_signature "$BINARY" || exit 1
echo ""
echo "β
dir is built, signed, and notarized."
echo "Note: standalone binaries cannot be stapled. Wrap in a signed+stapled .dmg"
echo "or .pkg if distributing in a context where Gatekeeper assessment is required."