5 Commits
Author SHA1 Message Date
Rsclub2_2andClaude Opus 5 af30c17a0d Macos signing (#80)
* Sign and notarize macOS builds

jpackage cannot produce a distributable macOS bundle on its own. It ad-hoc
signs the embedded runtime and then re-runs codesign on the same files without
--force, which codesign rejects; and "--type dmg --app-image" re-signs the app
it is handed, replacing a Developer ID signature with an ad-hoc one. So the
build now creates an unsigned app-image, signs it from the inside out, and
wraps it with hdiutil.

Apple's notary service also unpacks JARs and checks the native libraries
inside them, which sqlite-jdbc ships for both architectures. Those are signed
before the bundle is sealed, since rewriting a JAR afterwards would invalidate
the seal. A preflight check verifies Apple's two criteria locally, so a missed
binary costs seconds rather than a round trip to the notary service.

Two long-standing defects surfaced while testing and are fixed here: the
bundle identifier defaulted to the main class's package name (kst4contest.view
instead of de.x08.KST4Contest), and every release reported version 1.0 in
Finder because --app-version was never passed. Neither affects existing users:
the app keeps its settings in ~/.praktiKST, independent of the bundle ID.

Both workflows call the same script the local Mac uses, so the two cannot
drift apart. Signing needs a keychain that can answer a UI prompt, which a
runner cannot, so ci-import-cert.sh creates a throwaway keychain whose
password is generated per job and discarded with it. Notarization goes through
an App Store Connect API key and needs no keychain at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* Sign bundle contents serially

Signing the app image's Mach-O files with "xargs -P 8" passed locally but
failed on a runner: codesign reported "replacing existing signature" and then
"No such file or directory" for that same path. The two libjli.dylib copies are
separate inodes, so this is not hard links being signed twice -- concurrent
codesign runs over one bundle are simply not reliable. Serially costs about a
minute, since each call waits on Apple's timestamp server.

Also stop the matrix from cancelling the other architecture on a failure; that
throws away half the diagnostic information from a failed run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* Document macOS signing from 1.42

The installation guides described the right-click workaround as the normal
first launch. That stays, but as the path for 1.41.1 and older; from 1.42 a
double-click works. Both guides also show how to verify a download with spctl,
so the claim is checkable rather than something to take on faith.

The per-channel download notes distinguish where the channels actually stand:
Nightly is built from main and is signed as of now, while Stable still points
at 1.41.1, so those notes name the version instead of claiming it outright.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 16:48:31 +02:00
Rsclub2_2 399e5f34b7 Updated KST4C Logo for Builds in Higher Resolution and added it as an
SVG for Source. Should also be done when building Package with the help
of AUR in all Version and every Linux dist.
2026-08-22 00:32:07 +02:00
Rsclub2_2 2bc7554a52 Manual Fixup & Screenshots 2026-08-21 14:17:11 +02:00
Rsclub2_2 77b7a4729f Excuse me, wir 2026 2026-08-18 17:04:42 +02:00
Rsclub2_2 56b2fae0a3 Fix Nightly Build... 2026-08-18 17:00:13 +02:00
30 changed files with 499 additions and 71 deletions
+2 -1
View File
@@ -95,7 +95,8 @@ $endif$
belowskip = 8pt, belowskip = 8pt,
literate = {}{{\ensuremath{\rightarrow}}}1 literate = {}{{\ensuremath{\rightarrow}}}1
{}{{\ensuremath{\leftarrow}}}1 {}{{\ensuremath{\leftarrow}}}1
{}{{\ensuremath{\leftrightarrow}}}1, {}{{\ensuremath{\leftrightarrow}}}1
{}{{\ldots}}1,
} }
%% ─── Blockquotes ────────────────────────────────────────────────────────── %% ─── Blockquotes ──────────────────────────────────────────────────────────
+4
View File
@@ -94,6 +94,10 @@ jobs:
sed -i "s/^pkgver=.*/pkgver=${PKGVER}/" packaging/aur/kst4contest/PKGBUILD sed -i "s/^pkgver=.*/pkgver=${PKGVER}/" packaging/aur/kst4contest/PKGBUILD
sed -i "s/^sha256sums=.*/sha256sums=('${SHA_SRC}')/" packaging/aur/kst4contest/PKGBUILD sed -i "s/^sha256sums=.*/sha256sums=('${SHA_SRC}')/" packaging/aur/kst4contest/PKGBUILD
# A new pkgver supersedes any rebuild-only pkgrel bumps made in between.
sed -i "s/^pkgrel=.*/pkgrel=1/" packaging/aur/kst4contest-bin/PKGBUILD
sed -i "s/^pkgrel=.*/pkgrel=1/" packaging/aur/kst4contest/PKGBUILD
# kst4contest-git: Basis aus pom.xml, Suffix aus git # kst4contest-git: Basis aus pom.xml, Suffix aus git
BASE_VER=$(grep -m1 '<version>' pom.xml \ BASE_VER=$(grep -m1 '<version>' pom.xml \
| sed 's/.*<version>\(.*\)<\/version>.*/\1/' | sed 's/[-.]nightly//') | sed 's/.*<version>\(.*\)<\/version>.*/\1/' | sed 's/[-.]nightly//')
+33 -27
View File
@@ -7,6 +7,7 @@ on:
paths: paths:
- "src/**" - "src/**"
- "packaging/icons/**" - "packaging/icons/**"
- "packaging/macos/**"
- "pom.xml" - "pom.xml"
- "mvnw" - "mvnw"
- "mvnw.cmd" - "mvnw.cmd"
@@ -126,7 +127,7 @@ jobs:
jpackage \ jpackage \
--type app-image \ --type app-image \
--name KST4Contest \ --name KST4Contest \
--icon src/main/resources/icons/kst4contest.png \ --icon packaging/icons/kst4contest.png \
--input target/dist-libs \ --input target/dist-libs \
--main-jar app.jar \ --main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \ --main-class kst4contest.view.Kst4ContestApplication \
@@ -213,7 +214,7 @@ jobs:
jpackage \ jpackage \
--type deb \ --type deb \
--name KST4Contest \ --name KST4Contest \
--icon src/main/resources/icons/kst4contest.png \ --icon packaging/icons/kst4contest.png \
--input target/dist-libs \ --input target/dist-libs \
--main-jar app.jar \ --main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \ --main-class kst4contest.view.Kst4ContestApplication \
@@ -274,7 +275,7 @@ jobs:
jpackage \ jpackage \
--type rpm \ --type rpm \
--name KST4Contest \ --name KST4Contest \
--icon src/main/resources/icons/kst4contest.png \ --icon packaging/icons/kst4contest.png \
--input target/dist-libs \ --input target/dist-libs \
--main-jar app.jar \ --main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \ --main-class kst4contest.view.Kst4ContestApplication \
@@ -337,7 +338,7 @@ jobs:
jpackage \ jpackage \
--type app-image \ --type app-image \
--name KST4Contest \ --name KST4Contest \
--icon src/main/resources/icons/kst4contest.png \ --icon packaging/icons/kst4contest.png \
--input target/dist-libs \ --input target/dist-libs \
--main-jar app.jar \ --main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \ --main-class kst4contest.view.Kst4ContestApplication \
@@ -457,7 +458,7 @@ jobs:
jpackage \ jpackage \
--type app-image \ --type app-image \
--name KST4Contest \ --name KST4Contest \
--icon src/main/resources/icons/kst4contest.png \ --icon packaging/icons/kst4contest.png \
--input target/dist-libs \ --input target/dist-libs \
--main-jar app.jar \ --main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \ --main-class kst4contest.view.Kst4ContestApplication \
@@ -608,6 +609,7 @@ jobs:
name: Build macOS DMG (${{ matrix.os }}) name: Build macOS DMG (${{ matrix.os }})
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false
matrix: matrix:
os: [macos-latest, macos-15-intel] os: [macos-latest, macos-15-intel]
@@ -634,34 +636,38 @@ jobs:
- name: Ensure mvnw is executable - name: Ensure mvnw is executable
run: chmod +x mvnw run: chmod +x mvnw
- name: Build JAR and copy runtime dependencies - name: Import signing certificate
run: |
./mvnw -B -DskipTests package dependency:copy-dependencies -DincludeScope=runtime -DoutputDirectory=target/dist-libs
cp "$(ls -t target/praktiKST-*.jar | head -n 1)" target/dist-libs/app.jar
- name: Build macOS DMG with jpackage
run: |
mkdir -p dist
ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type dmg \
--name KST4Contest \
--icon packaging/icons/kst4contest.icns \
--input target/dist-libs \
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
--add-modules "$ADD_MODULES" \
--dest dist
env: env:
MACOSX_DEPLOYMENT_TARGET: "13.0" MACOS_CERT_P12: ${{ secrets.MACOS_CERT_P12 }}
MACOS_CERT_PASSWORD: ${{ secrets.MACOS_CERT_PASSWORD }}
run: ./packaging/macos/ci-import-cert.sh
# Builds the jar, signs the app bundle and every native library inside it,
# wraps it into a DMG and has Apple notarize the result. Same script the
# local Mac uses, so the two cannot drift apart.
- name: Build signed and notarized DMG
env:
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
NOTARY_ISSUER: ${{ secrets.MACOS_NOTARY_ISSUER }}
run: |
printf '%s' "$MACOS_NOTARY_KEY" | base64 --decode > "$RUNNER_TEMP/notary.p8"
export NOTARY_KEY="$RUNNER_TEMP/notary.p8"
./packaging/macos/build-signed-dmg.sh
- name: Remove signing credentials
if: always()
run: |
rm -f "$RUNNER_TEMP/notary.p8"
if [ -n "${SIGNING_KEYCHAIN:-}" ]; then
security delete-keychain "$SIGNING_KEYCHAIN" || true
fi
- name: Rename DMG artifact - name: Rename DMG artifact
run: | run: |
DMG=$(ls dist/*.dmg | head -n 1) DMG=$(ls dist/*.dmg | head -n 1)
if [ -z "$DMG" ]; then if [ -z "$DMG" ]; then
echo "No DMG produced by jpackage" && exit 1 echo "No DMG produced by the build" && exit 1
fi fi
mv "$DMG" "dist/${ASSET_BASENAME}-macos-${ARCH}.dmg" mv "$DMG" "dist/${ASSET_BASENAME}-macos-${ARCH}.dmg"
+32 -27
View File
@@ -104,7 +104,7 @@ jobs:
jpackage \ jpackage \
--type app-image \ --type app-image \
--name KST4Contest \ --name KST4Contest \
--icon src/main/resources/icons/kst4contest.png \ --icon packaging/icons/kst4contest.png \
--input target/dist-libs \ --input target/dist-libs \
--main-jar app.jar \ --main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \ --main-class kst4contest.view.Kst4ContestApplication \
@@ -184,7 +184,7 @@ jobs:
jpackage \ jpackage \
--type deb \ --type deb \
--name KST4Contest \ --name KST4Contest \
--icon src/main/resources/icons/kst4contest.png \ --icon packaging/icons/kst4contest.png \
--input target/dist-libs \ --input target/dist-libs \
--main-jar app.jar \ --main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \ --main-class kst4contest.view.Kst4ContestApplication \
@@ -238,7 +238,7 @@ jobs:
jpackage \ jpackage \
--type rpm \ --type rpm \
--name KST4Contest \ --name KST4Contest \
--icon src/main/resources/icons/kst4contest.png \ --icon packaging/icons/kst4contest.png \
--input target/dist-libs \ --input target/dist-libs \
--main-jar app.jar \ --main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \ --main-class kst4contest.view.Kst4ContestApplication \
@@ -292,7 +292,7 @@ jobs:
jpackage \ jpackage \
--type app-image \ --type app-image \
--name KST4Contest \ --name KST4Contest \
--icon src/main/resources/icons/kst4contest.png \ --icon packaging/icons/kst4contest.png \
--input target/dist-libs \ --input target/dist-libs \
--main-jar app.jar \ --main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \ --main-class kst4contest.view.Kst4ContestApplication \
@@ -403,7 +403,7 @@ jobs:
jpackage \ jpackage \
--type app-image \ --type app-image \
--name KST4Contest \ --name KST4Contest \
--icon src/main/resources/icons/kst4contest.png \ --icon packaging/icons/kst4contest.png \
--input target/dist-libs \ --input target/dist-libs \
--main-jar app.jar \ --main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \ --main-class kst4contest.view.Kst4ContestApplication \
@@ -506,6 +506,7 @@ jobs:
name: Build macOS DMG (${{ matrix.os }}) name: Build macOS DMG (${{ matrix.os }})
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false
matrix: matrix:
os: [macos-latest, macos-15-intel] os: [macos-latest, macos-15-intel]
@@ -522,35 +523,39 @@ jobs:
- name: Ensure mvnw is executable - name: Ensure mvnw is executable
run: chmod +x mvnw run: chmod +x mvnw
- name: Build JAR and copy runtime dependencies - name: Import signing certificate
run: |
./mvnw -B -DskipTests package dependency:copy-dependencies -DincludeScope=runtime -DoutputDirectory=target/dist-libs
cp "$(ls -t target/praktiKST-*.jar | head -n 1)" target/dist-libs/app.jar
- name: Build macOS DMG with jpackage
run: |
mkdir -p dist
ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type dmg \
--name KST4Contest \
--icon packaging/icons/kst4contest.icns \
--input target/dist-libs \
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
--add-modules "$ADD_MODULES" \
--dest dist
env: env:
MACOSX_DEPLOYMENT_TARGET: "13.0" MACOS_CERT_P12: ${{ secrets.MACOS_CERT_P12 }}
MACOS_CERT_PASSWORD: ${{ secrets.MACOS_CERT_PASSWORD }}
run: ./packaging/macos/ci-import-cert.sh
# Builds the jar, signs the app bundle and every native library inside it,
# wraps it into a DMG and has Apple notarize the result. Same script the
# local Mac uses, so the two cannot drift apart.
- name: Build signed and notarized DMG
env:
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
NOTARY_ISSUER: ${{ secrets.MACOS_NOTARY_ISSUER }}
run: |
printf '%s' "$MACOS_NOTARY_KEY" | base64 --decode > "$RUNNER_TEMP/notary.p8"
export NOTARY_KEY="$RUNNER_TEMP/notary.p8"
./packaging/macos/build-signed-dmg.sh
- name: Remove signing credentials
if: always()
run: |
rm -f "$RUNNER_TEMP/notary.p8"
if [ -n "${SIGNING_KEYCHAIN:-}" ]; then
security delete-keychain "$SIGNING_KEYCHAIN" || true
fi
- name: Rename DMG artifact - name: Rename DMG artifact
run: | run: |
ARCH=$(uname -m) ARCH=$(uname -m)
DMG=$(ls dist/*.dmg | head -n 1) DMG=$(ls dist/*.dmg | head -n 1)
if [ -z "$DMG" ]; then if [ -z "$DMG" ]; then
echo "No DMG produced by jpackage" && exit 1 echo "No DMG produced by the build" && exit 1
fi fi
mv "$DMG" "dist/KST4Contest-${{ github.ref_name }}-macos-${ARCH}.dmg" mv "$DMG" "dist/KST4Contest-${{ github.ref_name }}-macos-${ARCH}.dmg"
+3
View File
@@ -44,3 +44,6 @@ website/_site/
# Local secrets for act testing # Local secrets for act testing
.secrets .secrets
# Apple notarization private keys - never commit these
*.p8
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

+4
View File
@@ -123,6 +123,10 @@ v1.42 führt mehrere bisher getrennte Auswertungen zusammen. Bandinformationen,
- Nightly-Pakete werden automatisiert aus dem aktuellen `main`-Branch gebaut. Stable- und Beta-Releases verwenden reproduzierbare Paketnamen für die unterstützten Plattformen. - Nightly-Pakete werden automatisiert aus dem aktuellen `main`-Branch gebaut. Stable- und Beta-Releases verwenden reproduzierbare Paketnamen für die unterstützten Plattformen.
- **Signierte und notarisierte macOS-Pakete:** Die DMG-Dateien für Apple Silicon und Intel sind mit einer Apple Developer ID signiert und von Apple notarisiert; das Notarisierungsticket ist in der DMG hinterlegt. Der erste Start funktioniert damit per Doppelklick, ohne den bisherigen Umweg über **Öffnen** im Kontextmenü, und die Prüfung gelingt auch ohne Internetverbindung. Betroffen sind Nightly-, Beta- und Stable-Pakete gleichermaßen. Die Windows-Pakete sind weiterhin nicht signiert.
- **Korrekte Bundle-Kennung und Version unter macOS:** Die Anwendung meldet sich jetzt als `de.x08.KST4Contest` statt als `kst4contest.view` und trägt die tatsächliche Versionsnummer im Bundle. Bisher wies jedes Release im Finder unter **Informationen** die Version `1.0` aus. Bestehende Einstellungen sind davon nicht betroffen, da KST4Contest seine Daten in `~/.praktiKST/` ablegt und nicht an der Bundle-Kennung festmacht.
### Bekannte Grenzen ### Bekannte Grenzen
- Die aktive Geländedatenquelle verwendet Open-Meteo mit Copernicus-GLO-90-Daten und höchstens 100 Höhenpunkten pro Strecke. - Die aktive Geländedatenquelle verwendet Open-Meteo mit Copernicus-GLO-90-Daten und höchstens 100 Höhenpunkten pro Strecke.
+1 -1
View File
@@ -123,6 +123,6 @@ Besonderer Dank gilt:
- Konrad Neitzel (DC9DJ) für Unterstützung bei der Projektstruktur, - Konrad Neitzel (DC9DJ) für Unterstützung bei der Projektstruktur,
- Andreas (DO5ALF), Webmaster von funkerportal.de, - Andreas (DO5ALF), Webmaster von funkerportal.de,
- Franz van Velzen (PE0WGA) für Tests sowie - Franz van Velzen (PE0WGA) für Tests sowie
- DN9APW (Philipp Wagner), der seit Mai 2025 an der Entwicklung und den CI/CD-Pipelines mitarbeitet. - DN9APW (Philipp Wagner), der seit Mai 2026 an der Entwicklung und den CI/CD-Pipelines mitarbeitet.
Ebenso wichtig sind die Fehlermeldungen, Tests und konkreten Betriebserfahrungen aller weiteren Nutzer. Eine genaue Beschreibung eines reproduzierbaren Problems hilft dem Projekt meistens mehr als ein allgemeines „läuft gut“ auch wenn Letzteres natürlich angenehmer zu lesen ist. Ebenso wichtig sind die Fehlermeldungen, Tests und konkreten Betriebserfahrungen aller weiteren Nutzer. Eine genaue Beschreibung eines reproduzierbaren Problems hilft dem Projekt meistens mehr als ein allgemeines „läuft gut“ auch wenn Letzteres natürlich angenehmer zu lesen ist.
+16 -2
View File
@@ -267,7 +267,19 @@ Für Apple-Silicon-Macs wird das Paket mit `arm64` benötigt. Für Intel-Macs is
3. Ziehe `KST4Contest.app` in den Ordner **Programme**. 3. Ziehe `KST4Contest.app` in den Ordner **Programme**.
4. Starte KST4Contest aus dem Programme-Ordner oder über das Launchpad. 4. Starte KST4Contest aus dem Programme-Ordner oder über das Launchpad.
Die Anwendung ist derzeit nicht von Apple notarisiert. macOS kann den ersten Start deshalb blockieren. Ab Version 1.42 sind die macOS-Pakete mit einer Apple Developer ID signiert und von Apple notarisiert. Der erste Start funktioniert damit per Doppelklick, ohne Umweg über das Kontextmenü und ohne Sicherheitsabfrage. Das Notarisierungsticket liegt in der DMG-Datei selbst, sodass die Prüfung auch ohne Internetverbindung gelingt.
Wer nachsehen möchte, ob ein heruntergeladenes Paket wirklich signiert ist, kann das im Terminal prüfen:
```bash
spctl --assess --type open --context context:primary-signature -v KST4Contest-v<Version>-macos-arm64.dmg
```
Erwartet wird `accepted` zusammen mit `source=Notarized Developer ID`.
### Versionen bis einschließlich 1.41.1
Ältere Pakete sind nicht notarisiert. macOS blockiert den ersten Start deshalb.
Falls die Anwendung aus dem offiziellen GitHub Release stammt: Falls die Anwendung aus dem offiziellen GitHub Release stammt:
@@ -408,7 +420,9 @@ Starte die Datei anschließend aus einem Terminal. Fehlermeldungen sind dort mei
### macOS blockiert die Anwendung ### macOS blockiert die Anwendung
Verwende die unter [Installation unter macOS](#installation-unter-macos) beschriebene Funktion **Öffnen** im Kontextmenü. Prüfe vorher, ob die DMG-Datei aus dem offiziellen GitHub Release stammt. Ab Version 1.42 sollte das nicht mehr vorkommen, da die Pakete signiert und notarisiert sind. Tritt die Blockade trotzdem auf, ist die DMG-Datei meist unvollständig heruntergeladen oder nachträglich verändert worden. Lade sie in dem Fall erneut aus dem offiziellen GitHub Release.
Bei älteren Versionen ist die Blockade zu erwarten. Verwende dort die unter [Installation unter macOS](#installation-unter-macos) beschriebene Funktion **Öffnen** im Kontextmenü.
### Das Problem bleibt bestehen ### Das Problem bleibt bestehen
+4
View File
@@ -121,6 +121,10 @@ v1.42 brings several previously separate calculations together. Band information
- Nightly packages are built automatically from the current `main` branch. Stable and Beta releases use predictable asset names for the supported platforms. - Nightly packages are built automatically from the current `main` branch. Stable and Beta releases use predictable asset names for the supported platforms.
- **Signed and notarized macOS packages:** The DMG files for Apple Silicon and Intel are signed with an Apple Developer ID and notarized by Apple, with the notarization ticket stapled into the DMG. The first launch now works by double-clicking, without the previous detour through **Open** in the context menu, and the check also succeeds without an internet connection. This applies to Nightly, Beta and Stable packages alike. The Windows packages remain unsigned.
- **Correct bundle identifier and version on macOS:** The application now identifies itself as `de.x08.KST4Contest` rather than `kst4contest.view`, and carries its actual version number in the bundle. Previously every release reported version `1.0` in Finder's **Get Info** panel. Existing settings are unaffected, because KST4Contest stores its data in `~/.praktiKST/` rather than keying it to the bundle identifier.
### Known limitations ### Known limitations
- The active terrain provider uses Open-Meteo with Copernicus GLO-90 data and no more than 100 elevation samples per path. - The active terrain provider uses Open-Meteo with Copernicus GLO-90 data and no more than 100 elevation samples per path.
+16 -2
View File
@@ -267,7 +267,19 @@ Apple Silicon Macs require the package marked `arm64`. Intel Macs require the pa
3. Drag `KST4Contest.app` into the **Applications** folder. 3. Drag `KST4Contest.app` into the **Applications** folder.
4. Start KST4Contest from the Applications folder or Launchpad. 4. Start KST4Contest from the Applications folder or Launchpad.
The application is not currently notarized by Apple. macOS may therefore block the first launch. From version 1.42 onwards the macOS packages are signed with an Apple Developer ID and notarized by Apple. The first launch therefore works by double-clicking, without going through the context menu and without a security prompt. The notarization ticket is stapled into the DMG file itself, so the check also succeeds without an internet connection.
To confirm that a downloaded package really is signed, check it in a terminal:
```bash
spctl --assess --type open --context context:primary-signature -v KST4Contest-v<version>-macos-arm64.dmg
```
The expected result is `accepted` together with `source=Notarized Developer ID`.
### Versions up to and including 1.41.1
Older packages are not notarized, so macOS blocks the first launch.
If the application came from the official GitHub Release: If the application came from the official GitHub Release:
@@ -408,7 +420,9 @@ Then start the file from a terminal. Error messages shown there are usually more
### macOS blocks the application ### macOS blocks the application
Use the **Open** function described under [Installing on macOS](#installing-on-macos). Before doing so, verify that the DMG file came from the official GitHub Release. From version 1.42 onwards this should no longer happen, because the packages are signed and notarized. If it does occur, the DMG file was most likely downloaded incompletely or modified afterwards; download it again from the official GitHub Release.
On older versions the block is expected. Use the **Open** function described under [Installing on macOS](#installing-on-macos).
### The problem remains ### The problem remains
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 36 KiB

+1
View File
@@ -37,6 +37,7 @@ build() {
jpackage \ jpackage \
--type app-image \ --type app-image \
--name KST4Contest \ --name KST4Contest \
--icon packaging/icons/kst4contest.png \
--input target/dist-libs \ --input target/dist-libs \
--main-jar app.jar \ --main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \ --main-class kst4contest.view.Kst4ContestApplication \
+1 -1
View File
@@ -1,7 +1,7 @@
pkgbase = kst4contest pkgbase = kst4contest
pkgdesc = ON4KST Chat Client for VHF/UHF contest operation pkgdesc = ON4KST Chat Client for VHF/UHF contest operation
pkgver = 1.41.1 pkgver = 1.41.1
pkgrel = 1 pkgrel = 2
url = https://github.com/praktimarc/kst4contest url = https://github.com/praktimarc/kst4contest
arch = x86_64 arch = x86_64
license = GPL-3.0-only license = GPL-3.0-only
+9 -1
View File
@@ -1,7 +1,7 @@
# Maintainer: Philipp Wagner <philipp@wagnersnetz.de> # Maintainer: Philipp Wagner <philipp@wagnersnetz.de>
pkgname=kst4contest pkgname=kst4contest
pkgver=1.41.1 pkgver=1.41.1
pkgrel=1 pkgrel=2
pkgdesc="ON4KST Chat Client for VHF/UHF contest operation" pkgdesc="ON4KST Chat Client for VHF/UHF contest operation"
arch=('x86_64') arch=('x86_64')
url="https://github.com/praktimarc/kst4contest" url="https://github.com/praktimarc/kst4contest"
@@ -34,9 +34,17 @@ build() {
else else
ADD_MODULES="$(sed -n 's:.*<addmodule>\(.*\)</addmodule>.*:\1:p' pom.xml | paste -sd,)" ADD_MODULES="$(sed -n 's:.*<addmodule>\(.*\)</addmodule>.*:\1:p' pom.xml | paste -sd,)"
fi fi
# Same story for the packaging icon: without --icon jpackage silently ships
# its own Duke placeholder, but tarballs older than v1.42.0 have no icon to
# point at, so only pass the flag when the file is actually there.
ICON_ARGS=()
if [ -f packaging/icons/kst4contest.png ]; then
ICON_ARGS=(--icon packaging/icons/kst4contest.png)
fi
jpackage \ jpackage \
--type app-image \ --type app-image \
--name KST4Contest \ --name KST4Contest \
"${ICON_ARGS[@]}" \
--input target/dist-libs \ --input target/dist-libs \
--main-jar app.jar \ --main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \ --main-class kst4contest.view.Kst4ContestApplication \
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

+9
View File
@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180" width="180" height="180"><rect x="0" y="0" width="180" height="180" rx="40" fill="#5fd63a"></rect><g transform="translate(40,40) scale(1)">
<path d="M20 34 h60 a12 12 0 0 1 12 12 v20 a12 12 0 0 1 -12 12 h-30 l-16 12 v-12 h-14 a12 12 0 0 1 -12 -12 v-20 a12 12 0 0 1 12 -12 z" fill="#0a110a"></path>
<text x="50" y="65" text-anchor="middle" font-family="&#39;Space Grotesk&#39;,&#39;Helvetica Neue&#39;,Arial,sans-serif" font-weight="700" font-size="24" letter-spacing="0.5" fill="#5fd63a">KST</text>
<line x1="50" y1="34" x2="50" y2="17" stroke="#0a110a" stroke-width="6" stroke-linecap="round"></line>
<circle cx="50" cy="13" r="4.5" fill="#0a110a"></circle>
<path d="M58 6 a9 9 0 0 1 0 14" fill="none" stroke="#0a110a" stroke-width="4" stroke-linecap="round"></path>
<path d="M64 1 a15 15 0 0 1 0 24" fill="none" stroke="#0a110a" stroke-width="4" stroke-linecap="round"></path>
<path d="M42 6 a9 9 0 0 0 0 14" fill="none" stroke="#0a110a" stroke-width="4" stroke-linecap="round"></path>
<path d="M36 1 a15 15 0 0 0 0 24" fill="none" stroke="#0a110a" stroke-width="4" stroke-linecap="round"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+268
View File
@@ -0,0 +1,268 @@
#!/usr/bin/env bash
#
# Local signed (and optionally notarized) macOS build.
#
# jpackage cannot sign the app itself: it ad-hoc signs the embedded runtime and
# then re-runs codesign on the same files without --force, which codesign
# rejects with "is already signed". So this builds an unsigned app-image, signs
# it from the inside out ourselves, and only then wraps it into a DMG.
#
# Required:
# SIGNING_IDENTITY The name part of the Developer ID Application certificate,
# without the "Developer ID Application: " prefix. Example:
# SIGNING_IDENTITY="Philipp Wagner (ABCDE12345)"
# List available ones with:
# security find-identity -v -p codesigning
#
# Optional:
# Notarization, either as three separate values (what CI uses)...
# NOTARY_KEY Path to the App Store Connect .p8 private key
# NOTARY_KEY_ID The key's ID, also part of the .p8 filename
# NOTARY_ISSUER The issuer UUID, shown above the key list in the portal
# ...or as a keychain profile previously created with
# NOTARY_PROFILE xcrun notarytool store-credentials <name>
#
# With neither, the build is signed but not notarized -- enough to test
# locally, not enough to distribute.
#
set -euo pipefail
cd "$(dirname "$0")/../.."
REPO_ROOT="$PWD"
BUNDLE_ID="de.x08.KST4Contest"
ENTITLEMENTS="packaging/macos/kst4contest.entitlements"
if [ -z "${SIGNING_IDENTITY:-}" ]; then
echo "SIGNING_IDENTITY is not set. Available signing identities:" >&2
security find-identity -v -p codesigning >&2 || true
exit 1
fi
FULL_IDENTITY="Developer ID Application: $SIGNING_IDENTITY"
# notarytool takes either an API key triple or a stored keychain profile. The
# triple needs no keychain at all, which is why CI uses it.
NOTARY_ARGS=()
if [ -n "${NOTARY_KEY:-}" ] && [ -n "${NOTARY_KEY_ID:-}" ] && [ -n "${NOTARY_ISSUER:-}" ]; then
NOTARY_ARGS=(--key "$NOTARY_KEY" --key-id "$NOTARY_KEY_ID" --issuer "$NOTARY_ISSUER")
elif [ -n "${NOTARY_PROFILE:-}" ]; then
NOTARY_ARGS=(--keychain-profile "$NOTARY_PROFILE")
fi
echo "==> Building JAR and collecting runtime dependencies"
chmod +x mvnw
./mvnw -B -DskipTests package \
dependency:copy-dependencies -DincludeScope=runtime -DoutputDirectory=target/dist-libs
JAR="$(ls -t target/praktiKST-*.jar | head -n 1)"
cp "$JAR" target/dist-libs/app.jar
# jpackage only accepts a numeric major[.minor[.patch]] as the macOS bundle
# version, so a Maven qualifier like "-nightly" has to be trimmed off.
POM_VERSION="${JAR##*/praktiKST-}"
POM_VERSION="${POM_VERSION%.jar}"
APP_VERSION="$(printf '%s' "$POM_VERSION" | sed -e 's/[^0-9.].*$//' -e 's/\.*$//')"
[ -n "$APP_VERSION" ] || { echo "Could not derive app version from $JAR" >&2; exit 1; }
echo "==> Version: $POM_VERSION -> bundle version $APP_VERSION"
echo "==> Step 1/4: jpackage app-image (unsigned)"
rm -rf dist
mkdir -p dist
ADD_MODULES="$(java packaging/AddModules.java)"
MACOSX_DEPLOYMENT_TARGET="13.0" jpackage \
--type app-image \
--name KST4Contest \
--app-version "$APP_VERSION" \
--icon packaging/icons/kst4contest.icns \
--input target/dist-libs \
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
--add-modules "$ADD_MODULES" \
--mac-package-identifier "$BUNDLE_ID" \
--mac-package-name KST4Contest \
--dest dist/appimage
APP="dist/appimage/KST4Contest.app"
[ -d "$APP" ] || { echo "jpackage produced no app image" >&2; exit 1; }
echo "==> Step 2/4: signing bundle contents (this takes a few minutes)"
# Apple's notary service unpacks JARs and checks the native libraries inside
# them. sqlite-jdbc ships libsqlitejdbc.dylib for both architectures that way,
# and an unsigned binary in there fails the whole submission. So sign those
# first: the app bundle's seal covers Contents/app, and rewriting a JAR
# afterwards would invalidate it.
echo " scanning jars for native libraries"
find "$APP/Contents/app" -name '*.jar' -type f | while read -r JARPATH; do
# Only unpack jars that can plausibly hold a native library. Note the
# plain grep: "grep -q" exits at the first match, which hands unzip a
# SIGPIPE, and under "set -o pipefail" that failure becomes the pipeline's
# status -- inverting this very test.
if ! unzip -l "$JARPATH" | grep -E '\.(dylib|jnilib|so)$' >/dev/null; then
continue
fi
JARABS="$(cd "$(dirname "$JARPATH")" && pwd)/$(basename "$JARPATH")"
JARTMP="$(mktemp -d)"
unzip -q "$JARABS" -d "$JARTMP"
NATIVES="$(mktemp)"
( cd "$JARTMP" && find . -type f \( -name '*.dylib' -o -name '*.jnilib' -o -name '*.so' \) \
| while read -r n; do
if [ "$(file --mime-type -b "$n")" = "application/x-mach-binary" ]; then
printf '%s\n' "${n#./}"
fi
done ) > "$NATIVES"
if [ -s "$NATIVES" ]; then
echo " $(basename "$JARPATH"): $(wc -l < "$NATIVES" | tr -d ' ') native lib(s)"
( cd "$JARTMP" && xargs -I {} codesign --force --timestamp --options runtime \
--sign "$FULL_IDENTITY" {} < "$NATIVES" )
# Update in place rather than repacking, so the rest of the jar --
# manifest, module descriptor, entry order -- stays byte for byte.
( cd "$JARTMP" && xargs jar --update --file "$JARABS" < "$NATIVES" )
fi
rm -rf "$JARTMP" "$NATIVES"
done
# Every Mach-O file has to carry its own signature before the enclosing bundle
# can be sealed, so collect them first. jpackage leaves them ad-hoc signed,
# hence --force on every call.
# file(1) pads its output into columns when given several arguments at once,
# so ask it one file at a time with -b and get an unambiguous answer.
MACHO_LIST="$(mktemp)"
find "$APP" -type f -print0 | while IFS= read -r -d '' f; do
case "$(file --mime-type -b "$f")" in
application/x-mach-binary) printf '%s\n' "$f" ;;
esac
done > "$MACHO_LIST"
COUNT="$(wc -l < "$MACHO_LIST" | tr -d ' ')"
echo " $COUNT Mach-O files to sign"
# Serially, deliberately. Running codesign concurrently over several files of
# the same bundle fails intermittently -- a CI run died with "replacing existing
# signature" immediately followed by "No such file or directory" for that same
# path, while the identical script passed locally. Each call contacts Apple's
# timestamp server, so this costs about a minute for a runtime this size.
xargs -I {} codesign --force --timestamp --options runtime \
--sign "$FULL_IDENTITY" {} < "$MACHO_LIST"
rm -f "$MACHO_LIST"
# The embedded JDK is a bundle in its own right and must be sealed before the
# app that contains it.
echo " sealing embedded runtime"
codesign --force --timestamp --options runtime \
--sign "$FULL_IDENTITY" "$APP/Contents/runtime"
# Entitlements go on the outermost bundle: the hardened runtime derives the
# process's entitlements from the main executable's signature.
echo " sealing app bundle"
codesign --force --timestamp --options runtime \
--entitlements "$ENTITLEMENTS" \
--sign "$FULL_IDENTITY" "$APP"
# Apple rejects the whole submission over a single unsigned native library, and
# a round trip to the notary service costs minutes. Check its two criteria --
# a Developer ID authority and a secure timestamp -- locally first.
echo " preflight: verifying native libraries inside jars"
PREFLIGHT_ERRORS="$(mktemp)"
find "$APP/Contents/app" -name '*.jar' -type f | while read -r JARPATH; do
if ! unzip -l "$JARPATH" | grep -E '\.(dylib|jnilib|so)$' >/dev/null; then
continue
fi
CHECKTMP="$(mktemp -d)"
unzip -q "$JARPATH" -d "$CHECKTMP"
find "$CHECKTMP" -type f \( -name '*.dylib' -o -name '*.jnilib' -o -name '*.so' \) \
| while read -r NATIVE; do
[ "$(file --mime-type -b "$NATIVE")" = "application/x-mach-binary" ] || continue
INFO="$(codesign -dv --verbose=2 "$NATIVE" 2>&1 || true)"
LABEL="$(basename "$JARPATH")/${NATIVE#"$CHECKTMP"/}"
printf '%s' "$INFO" | grep -q "Authority=Developer ID Application" \
|| echo "$LABEL: not signed with a Developer ID certificate" >> "$PREFLIGHT_ERRORS"
printf '%s' "$INFO" | grep -q "Timestamp=" \
|| echo "$LABEL: signature has no secure timestamp" >> "$PREFLIGHT_ERRORS"
done
rm -rf "$CHECKTMP"
done
if [ -s "$PREFLIGHT_ERRORS" ]; then
echo "ERROR: these would fail notarization:" >&2
sed 's/^/ /' "$PREFLIGHT_ERRORS" >&2
rm -f "$PREFLIGHT_ERRORS"
exit 1
fi
rm -f "$PREFLIGHT_ERRORS"
echo " preflight ok"
echo "==> Step 3/4: building the dmg"
# Not with jpackage: "jpackage --type dmg --app-image" re-signs the app it is
# handed, replacing our Developer ID signature with an ad-hoc one and dropping
# the hardened runtime flag. hdiutil copies the bundle verbatim instead.
DMG="dist/KST4Contest-${APP_VERSION}.dmg"
STAGE="$(mktemp -d)"
# ditto rather than cp -R: it preserves the extended attributes the code
# signature depends on.
ditto "$APP" "$STAGE/KST4Contest.app"
ln -s /Applications "$STAGE/Applications"
hdiutil create -volname "KST4Contest" -srcfolder "$STAGE" \
-ov -format UDZO -quiet "$DMG"
rm -rf "$STAGE"
[ -f "$DMG" ] || { echo "hdiutil produced no DMG" >&2; exit 1; }
# Signing the DMG itself is not what Gatekeeper judges -- that is the .app
# inside -- but Apple expects the container to be signed too.
codesign --force --timestamp --sign "$FULL_IDENTITY" "$DMG"
echo "==> Built $DMG"
echo "==> Step 4/4: verification"
if [ ${#NOTARY_ARGS[@]} -gt 0 ]; then
echo " submitting for notarization (waits for Apple's verdict)"
# Without a timeout a stalled submission would hang a CI job forever.
xcrun notarytool submit "$DMG" "${NOTARY_ARGS[@]}" --wait --timeout 30m
echo " stapling ticket"
xcrun stapler staple "$DMG"
else
echo " no notarization credentials set, skipping notarization"
fi
# Everything below inspects the app as it actually ships, mounted from the DMG,
# rather than the staging copy on disk.
MOUNT_POINT="$(mktemp -d)"
hdiutil attach "$DMG" -nobrowse -quiet -mountpoint "$MOUNT_POINT"
trap 'hdiutil detach "$MOUNT_POINT" -quiet 2>/dev/null || hdiutil detach "$MOUNT_POINT" -force -quiet 2>/dev/null || true' EXIT
SHIPPED_APP="$MOUNT_POINT/KST4Contest.app"
echo "--- codesign --verify on the app inside the DMG ---"
codesign --verify --deep --strict --verbose=2 "$SHIPPED_APP"
echo "--- app identity ---"
codesign -dv --verbose=2 "$SHIPPED_APP" 2>&1 | grep -iE "identifier|authority|teamidentifier|flags"
# An ad-hoc signature here means something along the way re-signed the bundle.
if codesign -dv "$SHIPPED_APP" 2>&1 | grep -q "adhoc"; then
echo "ERROR: the app inside the DMG is ad-hoc signed, not Developer ID signed" >&2
exit 1
fi
echo "--- entitlements as signed ---"
codesign -d --entitlements - --xml "$SHIPPED_APP" 2>/dev/null | plutil -convert xml1 -o - - | grep -E "key|true|false"
echo "--- dmg identity ---"
codesign -dv --verbose=2 "$DMG" 2>&1 | grep -iE "authority|teamidentifier" | head -2
echo "--- spctl assessment ---"
# Without notarization this reports "rejected"; that is expected.
spctl --assess --type execute --verbose=4 "$SHIPPED_APP" || true
if [ ${#NOTARY_ARGS[@]} -gt 0 ]; then
echo "--- stapler validate ---"
xcrun stapler validate "$DMG"
fi
echo
echo "Done: $REPO_ROOT/$DMG"
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env bash
#
# Import the Developer ID certificate into a throwaway keychain on a CI runner.
#
# A runner cannot answer the keychain's authorization dialog, so the login
# keychain is unusable there. This creates a dedicated keychain instead, whose
# password is generated here and needed nowhere else -- it is discarded with the
# keychain at the end of the job.
#
# Reads from the environment:
# MACOS_CERT_P12 base64 of the exported .p12
# MACOS_CERT_PASSWORD the password that .p12 was exported with
#
# Exports to $GITHUB_ENV:
# SIGNING_IDENTITY for packaging/macos/build-signed-dmg.sh
# SIGNING_KEYCHAIN so the cleanup step knows what to delete
#
set -euo pipefail
: "${MACOS_CERT_P12:?MACOS_CERT_P12 is not set}"
: "${MACOS_CERT_PASSWORD:?MACOS_CERT_PASSWORD is not set}"
: "${RUNNER_TEMP:?RUNNER_TEMP is not set}"
: "${GITHUB_ENV:?GITHUB_ENV is not set}"
KEYCHAIN="$RUNNER_TEMP/kst4contest-signing.keychain-db"
KEYCHAIN_PASSWORD="$(uuidgen)"
CERT="$RUNNER_TEMP/cert.p12"
printf '%s' "$MACOS_CERT_P12" | base64 --decode > "$CERT"
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN"
# Keychains re-lock after five minutes by default, which would strand a build
# halfway through signing.
security set-keychain-settings -lut 21600 "$KEYCHAIN"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN"
security import "$CERT" -k "$KEYCHAIN" -P "$MACOS_CERT_PASSWORD" \
-T /usr/bin/codesign -T /usr/bin/security
rm -f "$CERT"
# Lets codesign reach the private key without the UI prompt a runner has no way
# of answering.
security set-key-partition-list -S apple-tool:,apple:,codesign: \
-s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN" >/dev/null
# codesign searches the keychain list, so the new keychain has to be on it --
# added to whatever the runner already had, not in place of it.
EXISTING_KEYCHAINS="$(security list-keychains -d user | sed -e 's/^[[:space:]]*"//' -e 's/"$//')"
# shellcheck disable=SC2086
security list-keychains -d user -s "$KEYCHAIN" $EXISTING_KEYCHAINS
IDENTITY="$(security find-identity -v -p codesigning "$KEYCHAIN" \
| sed -n 's/.*"Developer ID Application: \(.*\)".*/\1/p' | head -n 1)"
if [ -z "$IDENTITY" ]; then
echo "No 'Developer ID Application' identity found in the imported certificate." >&2
echo "What the keychain does contain:" >&2
security find-identity -v -p codesigning "$KEYCHAIN" >&2
exit 1
fi
echo "Imported identity: Developer ID Application: $IDENTITY"
echo "SIGNING_IDENTITY=$IDENTITY" >> "$GITHUB_ENV"
echo "SIGNING_KEYCHAIN=$KEYCHAIN" >> "$GITHUB_ENV"
+21
View File
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- The JVM compiles bytecode to machine code at runtime and executes it
from memory it allocated itself. Under the hardened runtime all three
of these are required or the app is killed on launch. -->
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<!-- jpackage bundles JavaFX native libraries that are signed with our own
identity rather than Apple's, and the JVM dlopen()s them at runtime. -->
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<!-- KST4Contest talks to the ON4KST chat servers. -->
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

+2 -2
View File
@@ -129,14 +129,14 @@ module.exports = async function () {
os: "macOS Apple Silicon", os: "macOS Apple Silicon",
format: "DMG arm64", format: "DMG arm64",
icon: "🍎", icon: "🍎",
note: "Best-effort build for Apple Silicon Macs. Not currently notarized by Apple.", note: "Best-effort build for Apple Silicon Macs. Signed and notarized by Apple from version 1.42 onwards.",
url: assetUrl("KST4Contest-{tag}-macos-arm64.dmg") url: assetUrl("KST4Contest-{tag}-macos-arm64.dmg")
}, },
{ {
os: "macOS Intel", os: "macOS Intel",
format: "DMG x86_64", format: "DMG x86_64",
icon: "🍎", icon: "🍎",
note: "Best-effort build for Intel Macs. Not currently notarized by Apple.", note: "Best-effort build for Intel Macs. Signed and notarized by Apple from version 1.42 onwards.",
url: assetUrl("KST4Contest-{tag}-macos-x86_64.dmg") url: assetUrl("KST4Contest-{tag}-macos-x86_64.dmg")
} }
]; ];
+2 -2
View File
@@ -121,7 +121,7 @@ module.exports = async function () {
format: "DMG arm64", format: "DMG arm64",
icon: "🍎", icon: "🍎",
recommended: false, recommended: false,
note: "Best-effort build for Apple Silicon Macs. The application is not currently notarized by Apple.", note: "Best-effort build for Apple Silicon Macs. Signed and notarized by Apple from version 1.42 onwards.",
url: assetUrl("KST4Contest-{tag}-macos-arm64.dmg") url: assetUrl("KST4Contest-{tag}-macos-arm64.dmg")
}, },
{ {
@@ -129,7 +129,7 @@ module.exports = async function () {
format: "DMG x86_64", format: "DMG x86_64",
icon: "🍎", icon: "🍎",
recommended: false, recommended: false,
note: "Best-effort build for Intel Macs. The application is not currently notarized by Apple.", note: "Best-effort build for Intel Macs. Signed and notarized by Apple from version 1.42 onwards.",
url: assetUrl("KST4Contest-{tag}-macos-x86_64.dmg") url: assetUrl("KST4Contest-{tag}-macos-x86_64.dmg")
}, },
{ {
+2 -2
View File
@@ -67,14 +67,14 @@ const ARTIFACT_INFO = {
os: "macOS Apple Silicon", os: "macOS Apple Silicon",
format: "DMG arm64", format: "DMG arm64",
icon: "🍎", icon: "🍎",
note: "Best-effort build for Apple Silicon Macs. Not notarized by Apple.", note: "Best-effort build for Apple Silicon Macs. Signed and notarized by Apple.",
order: 7 order: 7
}, },
"macos-dmg-macos-15-intel": { "macos-dmg-macos-15-intel": {
os: "macOS Intel", os: "macOS Intel",
format: "DMG x86_64", format: "DMG x86_64",
icon: "🍎", icon: "🍎",
note: "Best-effort build for Intel Macs. Not notarized by Apple.", note: "Best-effort build for Intel Macs. Signed and notarized by Apple.",
order: 8 order: 8
} }
}; };
+5 -3
View File
@@ -223,9 +223,11 @@ description: Download the latest stable KST4Contest packages for Windows, Linux
with their respective package managers. with their respective package managers.
</p> </p>
<p> <p>
macOS packages are provided for Apple Silicon and Intel systems on a best-effort basis. They are macOS packages are provided for Apple Silicon and Intel systems on a best-effort basis. From
not currently notarized by Apple. The installation guide covers the first launch, updates, the version 1.42 onwards they are signed with an Apple Developer ID and notarized by Apple, so they
Stable, Beta and Nightly channels, and the location of the settings directory. start by double-clicking without a security prompt. The installation guide covers the first
launch, updates, the Stable, Beta and Nightly channels, and the location of the settings
directory.
</p> </p>
<div class="actions"> <div class="actions">
<a class="button" href="/manual/en/installation/">Read the installation guide</a> <a class="button" href="/manual/en/installation/">Read the installation guide</a>