Skip to content

Commit 7d75866

Browse files
committed
Add signed macOS build workflow
1 parent 50bc76e commit 7d75866

3 files changed

Lines changed: 171 additions & 11 deletions

File tree

.github/workflows/build-macos.yml

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
name: Build macOS
2+
run-name: Build macOS • ${{ github.ref_name }}
3+
4+
on:
5+
workflow_dispatch:
6+
push:
7+
tags:
8+
- 'v*.*.*'
9+
10+
permissions:
11+
contents: read
12+
13+
jobs:
14+
build-macos:
15+
name: Build signed and notarized macOS app artifact
16+
runs-on: macos-15-arm64
17+
18+
env:
19+
NOTARY_PROFILE: cloudscope-ci-notary-profile
20+
CLOUDSCOPE_NATIVE: '1'
21+
CLOUDSCOPE_REMOTE: '0'
22+
CLOUDSCOPE_RELOAD: '0'
23+
CLOUDSCOPE_STORAGE_SECRET: cloudscope-packaged-app-secret
24+
25+
steps:
26+
- name: Check out repository
27+
uses: actions/checkout@v4
28+
with:
29+
fetch-depth: 0
30+
31+
- name: Install uv
32+
uses: astral-sh/setup-uv@v6
33+
with:
34+
enable-cache: true
35+
36+
- name: Set up Python
37+
uses: actions/setup-python@v5
38+
with:
39+
python-version: '3.12'
40+
41+
- name: Validate required secrets
42+
shell: bash
43+
env:
44+
MACOS_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE_BASE64 }}
45+
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
46+
MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
47+
APPLE_ID: ${{ secrets.APPLE_ID }}
48+
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
49+
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
50+
MACOS_SIGN_ID: ${{ secrets.MACOS_SIGN_ID }}
51+
run: |
52+
for name in \
53+
MACOS_CERTIFICATE_BASE64 \
54+
MACOS_CERTIFICATE_PASSWORD \
55+
MACOS_KEYCHAIN_PASSWORD \
56+
APPLE_ID \
57+
APPLE_APP_SPECIFIC_PASSWORD \
58+
APPLE_TEAM_ID \
59+
MACOS_SIGN_ID
60+
do
61+
if [[ -z "${!name}" ]]; then
62+
echo "ERROR: missing GitHub secret: $name" >&2
63+
exit 2
64+
fi
65+
done
66+
67+
- name: Import Developer ID certificate
68+
shell: bash
69+
env:
70+
MACOS_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE_BASE64 }}
71+
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
72+
MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
73+
run: |
74+
CERTIFICATE_PATH="$RUNNER_TEMP/developer_id_application.p12"
75+
KEYCHAIN_PATH="$RUNNER_TEMP/cloudscope-build.keychain-db"
76+
77+
echo "$MACOS_CERTIFICATE_BASE64" | base64 --decode > "$CERTIFICATE_PATH"
78+
79+
security create-keychain -p "$MACOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
80+
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
81+
security unlock-keychain -p "$MACOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
82+
security default-keychain -d user -s "$KEYCHAIN_PATH"
83+
84+
security import "$CERTIFICATE_PATH" \
85+
-P "$MACOS_CERTIFICATE_PASSWORD" \
86+
-A \
87+
-t cert \
88+
-f pkcs12 \
89+
-k "$KEYCHAIN_PATH"
90+
91+
security set-key-partition-list \
92+
-S apple-tool:,apple:,codesign: \
93+
-s \
94+
-k "$MACOS_KEYCHAIN_PASSWORD" \
95+
"$KEYCHAIN_PATH"
96+
97+
security find-identity -v -p codesigning "$KEYCHAIN_PATH"
98+
99+
- name: Create notarytool profile and packaging secrets
100+
shell: bash
101+
env:
102+
APPLE_ID: ${{ secrets.APPLE_ID }}
103+
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
104+
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
105+
MACOS_SIGN_ID: ${{ secrets.MACOS_SIGN_ID }}
106+
NOTARY_PROFILE: ${{ env.NOTARY_PROFILE }}
107+
run: |
108+
xcrun notarytool store-credentials "$NOTARY_PROFILE" \
109+
--apple-id "$APPLE_ID" \
110+
--team-id "$APPLE_TEAM_ID" \
111+
--password "$APPLE_APP_SPECIFIC_PASSWORD"
112+
113+
cat > packaging/macos/_secrets.sh <<EOF
114+
#!/usr/bin/env bash
115+
export SIGN_ID='$MACOS_SIGN_ID'
116+
export NOTARY_PROFILE='$NOTARY_PROFILE'
117+
EOF
118+
119+
chmod 600 packaging/macos/_secrets.sh
120+
121+
- name: Build app
122+
shell: bash
123+
run: ./packaging/macos/build_app.sh
124+
125+
- name: Sign and create notarization zip
126+
shell: bash
127+
run: ./packaging/macos/codesign_and_zip.sh
128+
129+
- name: Submit for notarization
130+
shell: bash
131+
run: ./packaging/macos/notary_submit.sh
132+
133+
- name: Poll notarization
134+
shell: bash
135+
run: ./packaging/macos/notary_poll_until_done.sh
136+
137+
- name: Staple and verify
138+
shell: bash
139+
run: ./packaging/macos/staple_and_verify.sh
140+
141+
- name: Create final macOS release zip
142+
shell: bash
143+
run: ./packaging/macos/make_release_zip.sh
144+
145+
- name: Upload macOS app artifact
146+
uses: actions/upload-artifact@v4
147+
with:
148+
name: CloudScope-macos-arm64
149+
path: |
150+
packaging/macos/dist/CloudScope-*-macos.zip
151+
packaging/macos/dist/CloudScope-*-macos-manifest.json
152+
if-no-files-found: error

README-DEV.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ acqstore
2626

2727
zip -r cloudscope_docs_20260610_v1.zip docs -i '*.py' '*.md' '*.ipynb' '*.css' '*.png' '*.svg'
2828

29+
find packaging \
30+
-type d \( -name build -o -name dist \) -prune -o \
31+
-type f \( \
32+
-name "*.md" -o \
33+
-name "*.sh" -o \
34+
-name "*.icns" -o \
35+
-name "*.spec" -o \
36+
-name "*.entitlements" -o \
37+
-name "*.plist" \
38+
\) -print | zip cloudscope_packaging_20260610_v1.zip -@
39+
2940
find docs -type f \( \
3041
-name "*.md" -o \
3142
-name "*.ipynb" -o \

docs/index.md

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
---
2+
hide:
3+
- toc
4+
---
5+
16
# CloudScope
27

38
CloudScope is a desktop and browser application for viewing, annotating, and analyzing acquisition-backed microscopy files.
@@ -12,21 +17,13 @@ CloudScope is a desktop and browser application for viewing, annotating, and ana
1217

1318
[:octicons-arrow-right-24: Open cloudscope.mapmanager.net](https://cloudscope.mapmanager.net){target="_blank" rel="noopener"}
1419

15-
- :material-apple:{ .lg .middle } **Download for macOS**
16-
17-
---
18-
19-
Download the latest macOS desktop build from GitHub Releases.
20-
21-
[:octicons-arrow-right-24: macOS releases](https://github.com/mapmanager/cloudscope/releases){target="_blank" rel="noopener"}
22-
23-
- :material-microsoft-windows:{ .lg .middle } **Download for Windows**
20+
- :material-download:{ .lg .middle } **Download the desktop app**
2421

2522
---
2623

27-
Download the latest Windows desktop build from GitHub Releases.
24+
CloudScope desktop is the same application on macOS and Windows. Choose the build for your operating system from GitHub Releases.
2825

29-
[:octicons-arrow-right-24: Windows releases](https://github.com/mapmanager/cloudscope/releases){target="_blank" rel="noopener"}
26+
[:material-apple: macOS](https://github.com/mapmanager/cloudscope/releases){target="_blank" rel="noopener"} · [:material-microsoft-windows: Windows](https://github.com/mapmanager/cloudscope/releases){target="_blank" rel="noopener"}
3027

3128
</div>
3229

0 commit comments

Comments
 (0)