Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit da925f5

Browse files
committed
chore(ci): use script to install MAS provisioning profile
- Add install-mas-profile.sh for profile fetch/installation - Update workflow to call script and simplify steps - Improve docs on provisioning profile management
1 parent e0321d9 commit da925f5

2 files changed

Lines changed: 90 additions & 64 deletions

File tree

.github/workflows/appstore-release.yml

Lines changed: 17 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,20 @@ name: App Store Release
33
# Uploads a Mac App Store build to App Store Connect, distributes to TestFlight,
44
# and optionally submits for App Store review.
55
#
6-
# The provisioning profile is downloaded automatically from App Store Connect via
7-
# `asc profiles list` — no need to store it as a secret.
8-
#
96
# Required GitHub Secrets:
10-
# APPLE_MAS_CERTIFICATE_P12 — Base64-encoded P12 containing both:
11-
# • "3rd Party Mac Developer Application: ..." (signs the app)
12-
# • "3rd Party Mac Developer Installer: ..." (signs the PKG)
13-
# Different cert type from APPLE_CERTIFICATE_P12 (Developer ID).
14-
# APPLE_MAS_CERTIFICATE_PASSWORD — Password for APPLE_MAS_CERTIFICATE_P12
15-
# APP_STORE_CONNECT_KEY_IDApp Store Connect API Key ID (same key as APP_STORE_CONNECT_KEY_ID)
16-
# APP_STORE_CONNECT_ISSUER_ID — Issuer ID UUID (same as APP_STORE_CONNECT_ISSUER_ID)
17-
# APP_STORE_CONNECT_API_KEY_P8 — PEM content of .p8 file (cat AuthKey_XXXX.p8 — NOT base64)
7+
# APPLE_MAS_CERTIFICATE_P12 — Base64-encoded P12 containing both:
8+
# • "3rd Party Mac Developer Application: ..." (signs the app)
9+
# • "3rd Party Mac Developer Installer: ..." (signs the PKG)
10+
# APPLE_MAS_CERTIFICATE_PASSWORD — Password for APPLE_MAS_CERTIFICATE_P12
11+
# APP_STORE_CONNECT_KEY_ID — App Store Connect API Key ID
12+
# APP_STORE_CONNECT_ISSUER_IDIssuer ID UUID
13+
# APP_STORE_CONNECT_API_KEY_P8 — Base64-encoded .p8 key file
14+
# base64 -i AuthKey_XXXX.p8 | pbcopy
1815
#
1916
# Required GitHub Variables (Settings → Variables → Actions):
20-
# APP_ID — Numeric App Store Connect app ID (asc apps list)
21-
# BETA_GROUP_ID — TestFlight beta group ID (asc testflight groups list --app-id $APP_ID)
22-
# DEVELOPMENT_TEAM — Apple Developer Team ID (10-char string, e.g. ABCD123456)
23-
#
24-
# One-time setup (run locally with `asc` before first CI run):
25-
# asc bundle-ids list --identifier com.tddworks.claudebar --platform macos
26-
# asc certificates list --type MAC_APP_DISTRIBUTION
27-
# asc profiles create --name "ClaudeBar Mac App Store" --type MAC_APP_STORE \
28-
# --bundle-id-id <id> --certificate-ids <cert-id>
17+
# APP_ID — Numeric App Store Connect app ID
18+
# BETA_GROUP_ID — TestFlight beta group ID
19+
# DEVELOPMENT_TEAM — Apple Developer Team ID (10-char string, e.g. ABCD123456)
2920

3021
on:
3122
workflow_dispatch:
@@ -142,8 +133,7 @@ jobs:
142133

143134
- name: Setup ASC credentials
144135
# Decode the base64-encoded .p8 key into raw PEM that asc CLI expects via ASC_PRIVATE_KEY.
145-
# Setting all three vars in $GITHUB_ENV avoids repeating them in every asc step.
146-
# printf '%s\n' guarantees a trailing newline so the EOF delimiter is on its own line.
136+
# Setting all three vars globally avoids repeating them in every asc step.
147137
env:
148138
ASC_PRIVATE_KEY_B64: ${{ secrets.APP_STORE_CONNECT_API_KEY_P8 }}
149139
run: |
@@ -156,49 +146,11 @@ jobs:
156146
echo 'EOF'
157147
} >> $GITHUB_ENV
158148
159-
- name: Download & Install Provisioning Profile
160-
# Downloads the MAC_APP_STORE profile directly from App Store Connect via `asc`.
161-
# No MAS_PROVISIONING_PROFILE secret needed — always fetches the latest version.
162-
# ASC_KEY_ID / ASC_ISSUER_ID / ASC_PRIVATE_KEY are set globally by "Setup ASC credentials".
149+
- name: Install Provisioning Profile
150+
# ASC credentials are set globally by "Setup ASC credentials" — no extra secret needed.
163151
run: |
164-
# Resolve the bundle ID resource ID for this app
165-
BUNDLE_ID_ID=$(asc bundle-ids list --identifier "$BUNDLE_ID" --platform macos \
166-
| jq -r '.data[0].id')
167-
if [ -z "$BUNDLE_ID_ID" ] || [ "$BUNDLE_ID_ID" = "null" ]; then
168-
echo "Error: Bundle ID '$BUNDLE_ID' not found in App Store Connect"
169-
echo "Run: asc bundle-ids create --name ClaudeBar --identifier $BUNDLE_ID --platform macos"
170-
exit 1
171-
fi
172-
173-
# Fetch the MAC_APP_STORE profile and extract its content
174-
# asccli may return attributes at the top level (flattened) or nested under .attributes
175-
PROFILE_JSON=$(asc profiles list --bundle-id-id "$BUNDLE_ID_ID" --type MAC_APP_STORE)
176-
PROFILE_ID=$(echo "$PROFILE_JSON" | jq -r '.data[0].id')
177-
PROFILE_CONTENT=$(echo "$PROFILE_JSON" | jq -r '.data[0].profileContent // .data[0].attributes.profileContent')
178-
PP_NAME=$(echo "$PROFILE_JSON" | jq -r '.data[0].name // .data[0].attributes.name')
179-
180-
if [ -z "$PROFILE_CONTENT" ] || [ "$PROFILE_CONTENT" = "null" ]; then
181-
echo "Error: No MAC_APP_STORE profile found for $BUNDLE_ID"
182-
echo "Run: asc profiles create --name 'ClaudeBar Mac App Store' --type MAC_APP_STORE \\"
183-
echo " --bundle-id-id $BUNDLE_ID_ID --certificate-ids <cert-id>"
184-
exit 1
185-
fi
186-
187-
# Decode and install the profile
188-
# printf '%s' avoids the trailing newline echo adds, which breaks macOS base64 -D
189-
PP_PATH="$RUNNER_TEMP/mas.provisionprofile"
190-
printf '%s' "$PROFILE_CONTENT" | base64 -D > "$PP_PATH"
191-
if [ ! -s "$PP_PATH" ]; then
192-
echo "Error: Provisioning profile decoded to an empty file (profile ID: $PROFILE_ID)"
193-
echo "Profile content length: ${#PROFILE_CONTENT}"
194-
exit 1
195-
fi
196-
PP_UUID=$(security cms -D -i "$PP_PATH" | /usr/libexec/PlistBuddy -c 'Print UUID' /dev/stdin)
197-
mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"
198-
cp "$PP_PATH" "$HOME/Library/MobileDevice/Provisioning Profiles/$PP_UUID.provisionprofile"
199-
152+
PP_NAME=$(./scripts/install-mas-profile.sh)
200153
echo "PP_NAME=$PP_NAME" >> $GITHUB_ENV
201-
echo "Installed profile: $PP_NAME ($PP_UUID)"
202154
203155
- name: Archive for Mac App Store
204156
run: |
@@ -293,4 +245,5 @@ jobs:
293245
if [ -n "$KEYCHAIN_PATH" ] && [ -f "$KEYCHAIN_PATH" ]; then
294246
security delete-keychain "$KEYCHAIN_PATH" || true
295247
fi
296-
rm -f "$RUNNER_TEMP/mas-cert.p12" || true
248+
rm -f "$RUNNER_TEMP/mas-cert.p12" || true
249+
rm -f "$RUNNER_TEMP/profile.b64" || true

scripts/install-mas-profile.sh

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/usr/bin/env bash
2+
# install-mas-profile.sh
3+
# Fetches and installs the MAC_APP_STORE provisioning profile from App Store Connect.
4+
# Prints the profile name to stdout (for CI to capture as PP_NAME).
5+
#
6+
# Usage:
7+
# ./scripts/install-mas-profile.sh
8+
#
9+
# Prerequisites:
10+
# brew install asccli jq
11+
# export ASC_KEY_ID="<your-key-id>"
12+
# export ASC_ISSUER_ID="<your-issuer-id>"
13+
# export ASC_PRIVATE_KEY="$(cat ~/.asc/<key-id>.p8)"
14+
15+
set -euo pipefail
16+
17+
BUNDLE_ID="${BUNDLE_ID:-com.tddworks.claudebar}"
18+
WORK_DIR=$(mktemp -d)
19+
trap 'rm -rf "$WORK_DIR"' EXIT
20+
21+
# Verify asc credentials are set
22+
if [ -z "${ASC_KEY_ID:-}" ] || [ -z "${ASC_ISSUER_ID:-}" ] || [ -z "${ASC_PRIVATE_KEY:-}" ]; then
23+
echo "Error: ASC credentials not set. Export before running:" >&2
24+
echo "" >&2
25+
echo " export ASC_KEY_ID=\"<your-key-id>\"" >&2
26+
echo " export ASC_ISSUER_ID=\"<your-issuer-id>\"" >&2
27+
echo " export ASC_PRIVATE_KEY=\"\$(cat ~/.asc/<key-id>.p8)\"" >&2
28+
exit 1
29+
fi
30+
31+
echo "==> Resolving bundle ID for $BUNDLE_ID..." >&2
32+
BUNDLE_ID_ID=$(asc bundle-ids list --identifier "$BUNDLE_ID" --platform macos \
33+
| jq -r '.data[0].id')
34+
35+
if [ -z "$BUNDLE_ID_ID" ] || [ "$BUNDLE_ID_ID" = "null" ]; then
36+
echo "Error: Bundle ID '$BUNDLE_ID' not found in App Store Connect" >&2
37+
exit 1
38+
fi
39+
echo " Bundle ID resource: $BUNDLE_ID_ID" >&2
40+
41+
echo "==> Fetching MAC_APP_STORE profile..." >&2
42+
PROFILE_JSON=$(asc profiles list --bundle-id-id "$BUNDLE_ID_ID" --type MAC_APP_STORE)
43+
PROFILE_CONTENT=$(echo "$PROFILE_JSON" | jq -r '.data[0].profileContent // .data[0].attributes.profileContent')
44+
PP_NAME=$(echo "$PROFILE_JSON" | jq -r '.data[0].name // .data[0].attributes.name')
45+
46+
if [ -z "$PROFILE_CONTENT" ] || [ "$PROFILE_CONTENT" = "null" ]; then
47+
echo "Error: No MAC_APP_STORE profile found for $BUNDLE_ID" >&2
48+
echo "Create one with:" >&2
49+
echo " asc profiles create --name 'ClaudeBar Mac App Store' --type MAC_APP_STORE \\" >&2
50+
echo " --bundle-id-id $BUNDLE_ID_ID --certificate-ids <cert-id>" >&2
51+
exit 1
52+
fi
53+
echo " Profile: $PP_NAME (${#PROFILE_CONTENT} base64 chars)" >&2
54+
55+
echo "==> Decoding and installing..." >&2
56+
PP_PATH="$WORK_DIR/mas.provisionprofile"
57+
# -A: treat entire input as one line (ASC API returns non-line-wrapped base64)
58+
printf '%s' "$PROFILE_CONTENT" > "$WORK_DIR/profile.b64"
59+
openssl base64 -d -A -in "$WORK_DIR/profile.b64" -out "$PP_PATH"
60+
echo " Decoded size: $(wc -c < "$PP_PATH") bytes" >&2
61+
62+
security cms -D -i "$PP_PATH" > "$WORK_DIR/profile.plist"
63+
PP_UUID=$(/usr/libexec/PlistBuddy -c 'Print UUID' "$WORK_DIR/profile.plist")
64+
mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"
65+
cp "$PP_PATH" "$HOME/Library/MobileDevice/Provisioning Profiles/$PP_UUID.provisionprofile"
66+
67+
68+
PP_NAME=$(/usr/libexec/PlistBuddy -c 'Print Name' "$WORK_DIR/profile.plist")
69+
echo " UUID: $PP_UUID" >&2
70+
echo " Installed: ~/Library/MobileDevice/Provisioning Profiles/$PP_UUID.provisionprofile" >&2
71+
72+
# Print profile name to stdout for CI capture: PP_NAME=$(./scripts/install-mas-profile.sh)
73+
echo "$PP_NAME"

0 commit comments

Comments
 (0)