build: make mas build work and fix guide

This commit is contained in:
johannesjo 2025-11-09 16:35:09 +01:00
parent 96a36a82ff
commit 63b021d942
3 changed files with 244 additions and 2 deletions

View file

@ -12,7 +12,7 @@ files:
- '!**/@nx/nx-linux-*/**'
- '!**/@nx/nx-win32-*/**'
directories:
output: './app-builds'
output: './.tmp/app-builds'
mac:
appId: com.super-productivity.app

View file

@ -12,7 +12,7 @@ files:
- '!**/@nx/nx-linux-*/**'
- '!**/@nx/nx-win32-*/**'
directories:
output: './app-builds'
output: './.tmp/app-builds'
mac:
target:

View file

@ -6,6 +6,8 @@ Mac access required! The instructions below refresh every asset used by the GitH
### 1. Clean up old material
⚠️ Note: Deleting old certificates also removes their private keys. If you dont have the private key backed up, generate a new CSR before creating new certificates (so maybe we should not delete the certificates too early?).
- In <https://developer.apple.com/account/resources/certificates/list>, revoke the expiring certificates so they cannot be downloaded again by accident.
- Remove the matching identities from your local keychain (`Keychain Access → My Certificates` - `open -a "Keychain Access"` ) so you do not export the wrong private key later.
@ -83,3 +85,243 @@ See also:
rm -Rf app-builds && npm run build && npm run dist:mac:dl
```
4. The script signs, notarizes (via `notarytool`), and staples the DMG using the new certificates and provisioning profiles. Validate with `spctl --assess -vv --type install path/to/app`.
---
# macOS App Store Certificates Guide
_(Local + CI workflow with electron-builder — 2025 edition)_
---
## 1) Overview
To build and publish your Electron app to the **Mac App Store (MAS)**, you need these **certificates** and a **provisioning profile**:
| Item | Purpose | Used in |
| -------------------------------------- | ---------------------------------------- | ---------- |
| **Apple Development** | Sign local debug/test builds | Local only |
| **Apple Distribution** | Sign the App Store `.app` | Local + CI |
| **Mac Installer Distribution** | Sign the `.pkg` uploaded via Transporter | Local + CI |
| **Mac App Store provisioning profile** | Ties the App ID to Apple Distribution | Local + CI |
> You **do not** need Developer ID certificates or notarization for MAS-only distribution.
---
## 2) Generate a new CSR (Certificate Signing Request)
1. On your Mac, open **Keychain Access → Certificate Assistant → Request a Certificate From a Certificate Authority…**
2. Fill in:
- **User Email Address:** your Apple ID for the developer team
- **Common Name:** e.g. `Super Productivity MAS Signing Key`
- **CA Email Address:** _leave blank_
- **Request is:** _Saved to disk_
3. Save as `mac-mas.csr`.
> This also creates a **private key** in your login keychain.
---
## 3) Create the MAS certificates in the Apple Developer Portal
1. Go to [https://developer.apple.com/account/resources/certificates/list](https://developer.apple.com/account/resources/certificates/list) → ** Add**
2. Create each certificate using **`mac-mas.csr`**:
- **Apple Development** (for local testing)
- **Apple Distribution** (replaces “Mac App Distribution”)
- **Mac Installer Distribution** (required for `.pkg` upload)
3. Download each resulting **`.cer`** file.
---
## 4) Install and export the identities (for local and CI)
1. **Install:** Double-click each `.cer` to add it under **Keychain Access → My Certificates**.
- Each entry must show a **disclosure triangle** with a **private key**.
- If the private key is missing, regenerate the CSR and certificate.
2. **Export:** Select the relevant identities → **right-click → Export …**
- Format: **Personal Information Exchange (.p12)**
- Name: `mas-certs.p12`
- Set a strong password (→ `MAC_CERTS_PASSWORD`).
3. **Verify on a second Mac (optional but recommended):**
```bash
security import mas-certs.p12 -k login.keychain-db -P "$MAC_CERTS_PASSWORD"
security find-identity -v -p codesigning
```
You should see **Apple Distribution** and **Mac Installer Distribution**.
---
## 5) Create / refresh the Mac App Store provisioning profile
1. Go to [https://developer.apple.com/account/resources/profiles/list](https://developer.apple.com/account/resources/profiles/list) → ** Add Profile**
2. Profile type: **Mac App Store**
3. Select:
- **Apple Distribution** certificate
- Your **App ID**
4. Download as `mas.provisionprofile`.
5. Place it in your repo, e.g.:
```
tools/mac-profiles/mas.provisionprofile
```
---
## 6) Configure electron-builder
In `electron-builder.yml` or `package.json > build`:
```yaml
mac:
category: public.app-category.productivity
hardenedRuntime: true
provisioningProfile: tools/mac-profiles/mas.provisionprofile
entitlements: build/entitlements.mas.plist
entitlementsInherit: build/entitlements.mas.inherit.plist
target:
- mas
```
> Ensure your MAS entitlements files are correct and compatible with App Store requirements.
---
## 7) Local build (MAS)
With the identities installed in your keychain:
```bash
npm run build && npm run dist:mac:mas
```
**Result:** `dist/mac/YourApp.pkg` — signed and ready for App Store upload.
---
## 8) Prepare CI secrets
Base64-encode the cert bundle and profile:
```bash
base64 -i mas-certs.p12 -o mas-certs.b64
base64 -i tools/mac-profiles/mas.provisionprofile -o mas-profile.b64
```
Create **GitHub Actions** secrets (Repo → _Settings → Secrets and variables → Actions_):
| Secret | Value |
| ------------------------- | --------------------------------------------------- |
| `MAC_CERTS` | contents of `mas-certs.b64` |
| `MAC_CERTS_PASSWORD` | the `.p12` export password |
| `MAS_PROVISION_PROFILE` | contents of `mas-profile.b64` |
| `APPLE_APP_SPECIFIC_PASS` | Apple ID app-specific password (for upload tooling) |
---
## 9) GitHub Actions workflow (example)
```yaml
name: Build macOS MAS
on:
workflow_dispatch:
push:
tags:
- 'v*'
jobs:
build-mas:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Decode certificates
run: echo "${{ secrets.MAC_CERTS }}" | base64 --decode > mas-certs.p12
- name: Create and unlock keychain
run: |
security create-keychain -p "" build.keychain
security import mas-certs.p12 -k build.keychain -P "${{ secrets.MAC_CERTS_PASSWORD }}" -T /usr/bin/codesign -T /usr/bin/security
security set-key-partition-list -S apple-tool:,apple: -s -k "" build.keychain
security list-keychains -s build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "" build.keychain
security find-identity -v -p codesigning build.keychain
- name: Write provisioning profile
run: echo "${{ secrets.MAS_PROVISION_PROFILE }}" | base64 --decode > tools/mac-profiles/mas.provisionprofile
- name: Install dependencies
run: npm ci
- name: Build & sign for MAS
env:
CSC_LINK: ${{ secrets.MAC_CERTS }}
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTS_PASSWORD }}
CSC_IDENTITY_AUTO_DISCOVERY: true
APPLEID: you@example.com
APPLEIDPASS: ${{ secrets.APPLE_APP_SPECIFIC_PASS }}
run: npm run build && npm run dist:mac:mas
```
> The `set-key-partition-list` step grants non-interactive access to the private keys for `codesign` during CI.
---
## 10) Upload to App Store Connect
1. Find the generated `.pkg` in `dist/`.
2. Upload with **Transporter** (Apples tool):
- Open Transporter, sign in with your Apple ID
- Drag the `.pkg` and click **Deliver**
3. Optional verification:
```bash
pkgutil --check-signature path/to/YourApp.pkg
```
Expect:
```
Signed by "Apple Mac Installer Distribution: <Your Team>"
Status: signed Apple Software
```
---
## 11) Maintenance & rotation
- Certificates typically expire after **1 year** (some teams may have 3-year certs).
- Before expiry, repeat this guide:
- Revoke/replace **Apple Distribution** and **Mac Installer Distribution**
- Recreate the **Mac App Store** provisioning profile
- Export a **new** `mas-certs.p12`, update **CI secrets**, and (if needed) reimport locally
- Keep your **App-Specific Password** valid for uploads.
---
### Quick Reference (What you actually need for MAS)
- **Certificates:** Apple Development (local), Apple Distribution, Mac Installer Distribution
- **Profile:** Mac App Store provisioning profile
- **No** Developer ID / notarization needed for MAS-only
- **Build target:** `mas`
- **Upload:** `.pkg` via Transporter
---