Skip to content

Commit 8402de8

Browse files
committed
fix(sign): gon is gone, and the macOS bundle steps no longer run for every stack
Two things, and the second is why macOS was red across four unrelated stacks. gon has been unmaintained since 2022. It did two jobs here: drive codesign from a JSON file, and notarise. codesign is the thing it wrapped, so calling it directly loses nothing and removes a dependency and two config files. notarytool is Apple's supported replacement and staples the ticket, so an app validates on first launch without a network round trip. Notarisation stays opt-in because it needs an Apple ID and team ID that a build otherwise does not; signing itself does not change shape. --deep is deliberately absent from the codesign call: Apple deprecated it, and nested code — Sparkle being the example already in this repository — wants signing individually anyway. The `Build .app zip file` step was gated on `runner.os == 'macOS'` and nothing else. Harmless while every stack was Wails and every macOS build produced a bundle. The go, cpp and deno stacks produce a binary and no bundle, so on macOS the step asked ditto for a .app that never existed and took the job with it — one ungated step showing up as four different stacks failing. It and the two productbuild steps now skip with a notice when there is no bundle, which is a fact about the stack rather than an error. Also: the options matrix assertion read BUILD_OPTIONS by interpolation, and -upxflags='--best --lzma' contains quotes that a shell assignment mangles. It reads from env now, which is the same lesson as everywhere else. Co-Authored-By: Virgil <virgil@lethean.io>
1 parent 58c484b commit 8402de8

9 files changed

Lines changed: 123 additions & 83 deletions

File tree

.github/workflows/ci.yml

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,18 +140,23 @@ jobs:
140140
upx-flags: ${{ matrix.upx_flags || '' }}
141141
- name: Assert BUILD_OPTIONS
142142
shell: bash
143+
env:
144+
# Through env, not interpolation: -upxflags='--best --lzma' contains
145+
# quotes, and pasting that inside a shell assignment mangles it.
146+
BUILD_OPTIONS: ${{ steps.opts.outputs.BUILD_OPTIONS }}
147+
EXPECT_FLAG: ${{ matrix.expect_flag || '' }}
143148
run: |
144149
set -euo pipefail
145-
BO='${{ steps.opts.outputs.BUILD_OPTIONS }}'
150+
BO="$BUILD_OPTIONS"
146151
echo "BUILD_OPTIONS=$BO"
147152
if [ "${{ matrix.obf }}" = "true" ] && ! echo "$BO" | grep -q -- "-obfuscated"; then echo "missing -obfuscated"; exit 1; fi
148153
if [ "${{ matrix.nsis }}" = "true" ] && ! echo "$BO" | grep -q -- "-nsis"; then echo "missing -nsis"; exit 1; fi
149154
if [ "${{ matrix.expect_webkit }}" = "true" ] && ! echo "$BO" | grep -q -- "webkit2_41"; then echo "missing webkit2_41"; exit 1; fi
150155
if [ "${{ matrix.disable_webkit || 'false' }}" = "true" ] && echo "$BO" | grep -q -- "webkit2_41"; then echo "webkit2_41 should be disabled"; exit 1; fi
151-
if [ -n "${{ matrix.expect_flag || '' }}" ]; then
156+
if [ -n "$EXPECT_FLAG" ]; then
152157
case "$BO" in
153-
*"${{ matrix.expect_flag }}"*) : ;;
154-
*) echo "missing ${{ matrix.expect_flag }}"; exit 1 ;;
158+
*"$EXPECT_FLAG"*) : ;;
159+
*) echo "missing $EXPECT_FLAG"; exit 1 ;;
155160
esac
156161
fi
157162
if [ -n "${{ matrix.expect_dedupe || '' }}" ]; then
@@ -301,14 +306,21 @@ jobs:
301306
os: [macos-latest, windows-latest]
302307
runs-on: ${{ matrix.os }}
303308
steps:
304-
- name: macOS gon presence
309+
- name: macOS signing tool discovery
305310
if: runner.os == 'macOS'
306311
shell: bash
307312
run: |
308-
if command -v gon >/dev/null 2>&1; then
309-
echo "[DEBUG_LOG] gon present: $(gon --version)"
313+
# Diagnostic, so it reports and stays green either way — a runner
314+
# without these is a fact worth seeing before a release depends on it.
315+
if command -v codesign >/dev/null 2>&1; then
316+
echo "[DEBUG_LOG] codesign: $(codesign --version 2>&1 | head -1)"
317+
else
318+
echo "[DEBUG_LOG] codesign not found"
319+
fi
320+
if xcrun notarytool --version >/dev/null 2>&1; then
321+
echo "[DEBUG_LOG] notarytool: $(xcrun notarytool --version 2>&1 | head -1)"
310322
else
311-
echo "[DEBUG_LOG] gon not found. It is installed during the Go setup step in real builds (macOS only)."
323+
echo "[DEBUG_LOG] notarytool not found — notarisation would fail on a tag"
312324
fi
313325
- name: Windows signtool discovery
314326
if: runner.os == 'Windows'

actions/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Sub-actions overview
66
- discovery — Detect OS/ARCH, Ubuntu distro (on Linux), repo/ref metadata, and project markers. Suggests a primary stack.
77
- options — Compute `BUILD_OPTIONS` string for Wails v2 builds (adds `-tags webkit2_41` on Ubuntu 24.04 when appropriate).
88
- setup — Orchestrator for toolchains (Go → npm → optional Deno → optional Conan).
9-
- setup/go — Installs Go, optional Garble (when obfuscating), Wails CLI, and `gon` on macOS.
9+
- setup/go — Installs Go, optional Garble (when obfuscating), and the Wails CLI when asked for.
1010
- setup/npm — Installs Node.js and optionally runs `npm ci`/`npm install` in your app directory (auto-detects `frontend/`).
1111
- setup/deno — ENV-first Deno setup and command runner (`DENO_*` envs).
1212
- setup/conan — Installs Conan via pip (placeholder for future C++ builds).

actions/build/wails2/README.md

Lines changed: 12 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,13 @@ jobs:
5151
5252
macOS Code Signing (Wails v2)
5353
54-
You need two `gon` configuration files to sign and notarize the `.app` before building the installer pkg.
54+
Signing and notarisation are handled by `codesign` and `xcrun notarytool`, both
55+
of which come with the Xcode command line tools. There are no configuration
56+
files to write: what used to live in `gon-sign.json` and `gon-notarize.json` is
57+
now inputs.
58+
59+
`build/darwin/entitlements.plist` is still read if you have one — it is passed
60+
to `codesign --entitlements` when present, and skipped when not.
5561

5662
Workflow snippet
5763
```yaml
@@ -67,46 +73,13 @@ Workflow snippet
6773
sign-macos-installer-id: ${{ secrets.MACOS_INSTALLER_CERT_ID }}
6874
sign-macos-installer-cert: ${{ secrets.MACOS_INSTALLER_CERT }}
6975
sign-macos-installer-cert-password: ${{ secrets.MACOS_INSTALLER_CERT_PASSWORD }}
76+
# Notarisation is opt-in: it needs an Apple ID and team ID a build
77+
# otherwise does not.
78+
notarize: true
79+
sign-macos-app-email: ${{ secrets.APPLE_ID }}
80+
sign-macos-app-team-id: ${{ secrets.APPLE_TEAM_ID }}
7081
```
7182

72-
`build/darwin/gon-sign.json`
73-
```json
74-
{
75-
"source" : ["./build/bin/wailsApp.app"],
76-
"bundle_id" : "com.wails.app",
77-
"apple_id": {
78-
"username": "username",
79-
"password": "@env:APPLE_PASSWORD"
80-
},
81-
"sign" :{
82-
"application_identity" : "Developer ID Application: XXXXXXXX (XXXXXX)",
83-
"entitlements_file": "./build/darwin/entitlements.plist"
84-
},
85-
"dmg" :{
86-
"output_path": "./build/bin/wailsApp.dmg",
87-
"volume_name": "Lethean"
88-
}
89-
}
90-
```
91-
92-
`build/darwin/gon-notarize.json`
93-
```json
94-
{
95-
"notarize": [{
96-
"path": "./build/bin/wailsApp.pkg",
97-
"bundle_id": "com.wails.app",
98-
"staple": true
99-
},{
100-
"path": "./build/bin/wailsApp.app.zip",
101-
"bundle_id": "com.wails.app",
102-
"staple": false
103-
}],
104-
"apple_id": {
105-
"username": "USER name",
106-
"password": "@env:APPLE_PASSWORD"
107-
}
108-
}
109-
```
11083

11184
`build/darwin/entitlements.plist`
11285
```xml

actions/build/wails2/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ inputs:
121121
default: ''
122122
description: "Password for the installer certificate"
123123
notarize:
124-
description: "Notarise with xcrun notarytool rather than gon"
124+
description: "Notarise with xcrun notarytool"
125125
required: false
126126
default: "false"
127127
sign-macos-app-email:

actions/setup/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ Purpose
66
- npm/Node (optional install in your app working directory)
77
- Deno (optional; ENV-first configuration)
88
- Wails CLI (unless `wails-dev-build` is true)
9-
- Installs `gon` on macOS for later signing
109
- Conan (placeholder for future C++ stack)
1110

1211
Inputs
@@ -61,6 +60,5 @@ Usage
6160
```
6261
6362
Notes
64-
- On macOS, `gon` is installed for later signing steps. No-op on other OSes.
6563
- If you do not need Deno, leave envs and inputs empty — it will be skipped.
6664
- If `wails-dev-build` is `true`, ensure `wails` is already available on PATH.

actions/setup/go/action.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: "Setup Go (and Wails)"
2-
description: "Sets up Go (with optional cache), installs Garble when obfuscating, installs Wails CLI unless wails-dev-build is true; installs gon on macOS"
2+
description: "Sets up Go with an optional cache, Garble when obfuscating, and the Wails v2 CLI when asked for"
33
inputs:
44
go-version:
55
description: "Go version to install"
@@ -57,7 +57,4 @@ runs:
5757
if: inputs.install-wails == 'true' && inputs.wails-dev-build == 'false'
5858
run: go install github.com/wailsapp/wails/v2/cmd/wails@${{ inputs.wails-version }}
5959
shell: bash
60-
- name: Install macOS deps (gon)
61-
if: runner.os == 'macOS'
62-
run: brew install mitchellh/gon/gon
6360
shell: bash

actions/sign/README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Purpose
44
- Unified signing step for macOS and Windows.
5-
- macOS: imports certificates, signs the `.app` with `gon`, zips the `.app`, builds a `.pkg` (signed or unsigned), and notarizes on tag builds.
5+
- macOS: imports certificates, signs the `.app` with `codesign`, zips the `.app`, builds a `.pkg` (signed or unsigned), and notarises with `xcrun notarytool` when `notarize` is on. All tag-gated.
66
- Windows: signs the `.exe` and the NSIS installer using a provided PFX (base64) and password.
77

88
When it runs
@@ -14,7 +14,7 @@ Inputs (union of previous per-OS signers)
1414
- `app-working-directory` (default `.`)
1515
- `build-name` (required)
1616
- macOS:
17-
- `sign-macos-apple-password` — app-specific password for Apple ID (`gon` uses this)
17+
- `sign-macos-apple-password` — app-specific password for the Apple ID (notarytool uses this)
1818
- `sign-macos-app-id` — Developer ID Application subject
1919
- `sign-macos-app-cert` — Base64-encoded `.p12`
2020
- `sign-macos-app-cert-password` — Password for the Application certificate
@@ -26,8 +26,6 @@ Inputs (union of previous per-OS signers)
2626
- `sign-windows-cert-password` — Password for the PFX
2727

2828
Required project files (macOS)
29-
- `build/darwin/gon-sign.json` — config for signing the `.app`
30-
- `build/darwin/gon-notarize.json` — config for notarizing `.pkg` and `.app.zip`
3129

3230
Usage
3331
```yaml
@@ -51,6 +49,6 @@ Usage
5149
```
5250
5351
Notes
54-
- On macOS, `gon` must be installed (`actions/setup/go` installs it automatically on macOS).
52+
- On macOS, `codesign` and `xcrun notarytool` come with the Xcode command line tools, which GitHub's macOS runners have.
5553
- The `.app` zip is produced regardless of signing to ease distribution.
5654
- Installer `.pkg` is signed when `sign == 'true'` and an installer ID is provided; otherwise an unsigned pkg is built on tags.

actions/sign/action.yml

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ inputs:
4444
# Windows
4545
notarize:
4646
description: >
47-
Notarise with xcrun notarytool instead of gon. gon has been unmaintained
48-
since 2022 and notarytool is Apple's supported path; this will become the
49-
default once callers have moved. Needs the Apple ID, team ID and an
50-
app-specific password.
47+
Notarise with xcrun notarytool. Off by default because it needs an Apple
48+
ID, a team ID and an app-specific password that a build otherwise does
49+
not. gon used to do this and is gone: unmaintained since 2022, and
50+
notarytool is Apple's supported path.
5151
required: false
5252
default: "false"
5353
sign-macos-app-email:
@@ -100,45 +100,76 @@ runs:
100100
p12-file-base64: ${{ inputs.sign-macos-installer-cert }}
101101
p12-password: ${{ inputs.sign-macos-installer-cert-password }}
102102
create-keychain: false
103-
- name: Sign macOS .app with gon
103+
- name: Sign the .app
104104
if: runner.os == 'macOS' && inputs.sign != 'false' && startsWith(github.ref, 'refs/tags/')
105105
shell: bash
106106
working-directory: ${{ inputs.app-working-directory }}
107107
env:
108-
APPLE_PASSWORD: ${{ inputs.sign-macos-apple-password }}
108+
IDENTITY: ${{ inputs.sign-macos-app-id }}
109+
NAME: ${{ inputs.build-name }}
109110
run: |
110-
echo "Signing Package"
111-
gon -log-level=info ./build/darwin/gon-sign.json
111+
set -euo pipefail
112+
APP="build/bin/$NAME.app"
113+
if [ ! -d "$APP" ]; then
114+
echo "::notice::no $APP — this stack produces no bundle, nothing to sign"
115+
exit 0
116+
fi
117+
if [ -z "$IDENTITY" ]; then
118+
echo "::error::sign is on but sign-macos-app-id is empty"
119+
exit 1
120+
fi
121+
122+
# gon drove codesign from a JSON file and has been unmaintained since
123+
# 2022. codesign is the thing it wrapped, so calling it directly loses
124+
# nothing and removes a dependency. --deep is deliberately absent:
125+
# Apple deprecated it, and nested code — Sparkle, for one — wants
126+
# signing individually anyway.
127+
ENTITLEMENTS="build/darwin/entitlements.plist"
128+
args=(-f -s "$IDENTITY" --timestamp -o runtime)
129+
if [ -f "$ENTITLEMENTS" ]; then args+=(--entitlements "$ENTITLEMENTS"); fi
130+
codesign "${args[@]}" "$APP"
131+
codesign --verify --strict --verbose=2 "$APP"
112132
- name: Build .app zip file
113133
if: runner.os == 'macOS'
114134
working-directory: ${{ inputs.app-working-directory }}
115135
shell: bash
136+
env:
137+
NAME: ${{ inputs.build-name }}
116138
run: |
139+
set -euo pipefail
117140
# Paths are relative to working-directory, which is already
118141
# app-working-directory — prefixing again asked ditto for
119142
# <dir>/<dir>/build/bin. harrys522 spotted this in #46.
120-
ditto -c -k --keepParent build/bin/${{ inputs.build-name }}.app build/bin/${{ inputs.build-name }}.app.zip
143+
APP="build/bin/$NAME.app"
144+
# This step had no gate beyond the OS, which was harmless while every
145+
# stack was Wails. The Go, C++ and Deno stacks produce a binary and no
146+
# bundle, so on macOS it asked ditto for something that never existed.
147+
if [ ! -d "$APP" ]; then
148+
echo "::notice::no $APP — this stack produces no bundle, nothing to zip"
149+
exit 0
150+
fi
151+
ditto -c -k --keepParent "$APP" "build/bin/$NAME.app.zip"
121152
- name: Build Installer (signed)
122153
if: runner.os == 'macOS' && inputs.sign != 'false' && inputs.sign-macos-installer-id != '' && startsWith(github.ref, 'refs/tags/')
123154
shell: bash
124155
working-directory: ${{ inputs.app-working-directory }}
156+
env:
157+
NAME: ${{ inputs.build-name }}
158+
INSTALLER_ID: ${{ inputs.sign-macos-installer-id }}
125159
run: |
126-
productbuild --sign '${{ inputs.sign-macos-installer-id }}' --component build/bin/${{ inputs.build-name }}.app /Applications build/bin/${{ inputs.build-name }}.pkg
160+
set -euo pipefail
161+
test -d "build/bin/$NAME.app" || { echo "::notice::no bundle to package"; exit 0; }
162+
productbuild --sign "$INSTALLER_ID" --component "build/bin/$NAME.app" /Applications "build/bin/$NAME.pkg"
127163
- name: Build Installer (unsigned)
128164
if: runner.os == 'macOS' && inputs.sign-macos-installer-id == '' && startsWith(github.ref, 'refs/tags/')
129165
shell: bash
130166
working-directory: ${{ inputs.app-working-directory }}
131-
run: |
132-
productbuild --component build/bin/${{ inputs.build-name }}.app /Applications build/bin/${{ inputs.build-name }}.pkg
133-
- name: Notarize Installer and zip with gon
134-
if: runner.os == 'macOS' && inputs.sign != 'false' && inputs.notarize != 'true' && startsWith(github.ref, 'refs/tags/')
135-
shell: bash
136-
working-directory: ${{ inputs.app-working-directory }}
137167
env:
138-
APPLE_PASSWORD: ${{ inputs.sign-macos-apple-password }}
168+
NAME: ${{ inputs.build-name }}
139169
run: |
140-
gon -log-level=info build/darwin/gon-notarize.json
141-
170+
set -euo pipefail
171+
test -d "build/bin/$NAME.app" || { echo "::notice::no bundle to package"; exit 0; }
172+
productbuild --component "build/bin/$NAME.app" /Applications "build/bin/$NAME.pkg"
142173
# Sparkle ships XPC services and helper apps inside its framework, and each
143174
# has to be signed on its own — the outer signature does not cover them.
144175
# A bundle missing these passes codesign and fails notarisation, which is

docs/src/content/docs/reference/signing.md

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,44 @@ never touch your certificates.
1818
Runs on tags only:
1919
2020
1. Import the code-signing and installer certificates
21-
2. Sign the `.app` with `gon`
21+
2. Sign the `.app` with `codesign`
2222
3. Zip the `.app`
2323
4. Build the `.pkg` installer
24-
5. Notarise with `gon`
24+
5. Notarise with `xcrun notarytool` and staple the ticket, when `notarize` is on
2525

26-
Needs certificates and an Apple ID in secrets. `gon` is installed by
27-
`setup/go` on macOS runners.
26+
`codesign` and `notarytool` both ship with the Xcode command line tools, so
27+
there is nothing to install and no configuration file to write.
28+
29+
`gon` used to do steps 2 and 5. It has been unmaintained since 2022, and
30+
`notarytool` is Apple's supported path — it also staples, so the app validates
31+
on first launch without a network round trip. The two `gon-*.json` files are no
32+
longer read; what they configured is inputs now.
33+
34+
```yaml
35+
- uses: dAppCore/build@v4
36+
with:
37+
build-name: myApp
38+
build-platform: darwin/universal
39+
sign: true
40+
notarize: true
41+
dmg: true
42+
sign-macos-app-id: ${{ secrets.MACOS_APP_ID }}
43+
sign-macos-app-cert: ${{ secrets.MACOS_APP_CERT }}
44+
sign-macos-app-cert-password: ${{ secrets.MACOS_APP_CERT_PASSWORD }}
45+
sign-macos-app-email: ${{ secrets.APPLE_ID }}
46+
sign-macos-app-team-id: ${{ secrets.APPLE_TEAM_ID }}
47+
sign-macos-apple-password: ${{ secrets.APPLE_APP_PASSWORD }}
48+
```
49+
50+
`build/darwin/entitlements.plist` is passed to `codesign --entitlements` when
51+
it exists and skipped when it does not.
52+
53+
### Sparkle
54+
55+
`sign-sparkle: true` signs a bundled Sparkle framework. Sparkle ships XPC
56+
services and helper apps inside the framework and the outer signature does not
57+
cover them — a bundle missing those individual signatures passes `codesign` and
58+
then fails notarisation.
2859

2960
## Windows
3061

0 commit comments

Comments
 (0)