Die Einrichtung beim ersten Start erklärt jede der vier Sachen einzeln und fragt jede einzeln an. Vier Systemdialoge hintereinander wären der übliche Weg und der falsche: wer nicht weiß wofür, klickt viermal „Nicht erlauben", und danach fragt macOS nie wieder. Sie kommt beim ersten Start immer, auch wenn zufällig schon alles erlaubt ist — sie erklärt auch den Helfer und den Autostart. Beim Autostart ist `requiresApproval` der Zustand, der weh tut. Wer das Anmeldeobjekt in den Systemeinstellungen abgeschaltet hat, kann in Onyx auf den Schalter drücken, so oft er will. Als „aus" angezeigt führt das in eine Schleife, also steht dort jetzt, wo es weitergeht. Der Mixer verliert den Schalter je Programm. Zehn Mini-Schalter untereinander sind das, was den Eindruck macht; am Regler zu ziehen ist ohnehin die Entscheidung, dieses Programm zu regeln, und der große Ausschalter stellt alles zurück. Der Regler ist selbst gezeichnet — der Systemregler bringt sein eigenes Erscheinungsbild mit und kann nicht zeigen, worauf es hier ankommt: den Pegel und die Grenze bei 100 %. Der Pegel wird im selben Durchlauf gemessen, in dem verstärkt wird, und über `Atomic` weitergereicht. Eine gewöhnliche Eigenschaft wäre ein Wettlauf, eine Sperre im Audiothread der klassische Weg zu Aussetzern. Dabei fällt das `Date()` aus dem Echtzeitpfad, das dort nie hingehört hat. Zwei Funde beim Bauen des Release-Wegs, beide hätten erst nach dem Hochladen zur Ablehnung geführt: der Helfer wurde ohne sicheren Zeitstempel signiert, und das Adapter-Framework ad-hoc. Beides gilt jetzt nur noch im Debug. Scripts/release.sh prüft Zertifikat und Notarisierungsprofil vorweg, statt nach zehn Minuten Bauen zu scheitern. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
154 lines
5.8 KiB
Bash
Executable File
154 lines
5.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# Baut Onyx als notarisiertes DMG.
|
|
#
|
|
# Voraussetzungen — beide einmalig einzurichten:
|
|
#
|
|
# 1. Ein Zertifikat „Developer ID Application: … (PP34X97WS3)" im Schlüsselbund.
|
|
# Xcode → Einstellungen → Konten → Manage Certificates → + →
|
|
# Developer ID Application. Das Entwicklerzertifikat („Apple Development")
|
|
# genügt NICHT: damit signierte Apps lassen sich nicht notarisieren und
|
|
# laufen auf keinem fremden Mac.
|
|
#
|
|
# 2. Ein Zugangsprofil für notarytool:
|
|
# xcrun notarytool store-credentials "Onyx" \
|
|
# --apple-id "<Apple-ID>" --team-id PP34X97WS3 \
|
|
# --password "<app-spezifisches Passwort>"
|
|
# Das app-spezifische Passwort kommt von appleid.apple.com, nicht das
|
|
# normale Kennwort.
|
|
#
|
|
# Danach genügt: Scripts/release.sh
|
|
|
|
set -euo pipefail
|
|
export DEVELOPER_DIR=${DEVELOPER_DIR:-/Applications/Xcode.app/Contents/Developer}
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
BUILD="$ROOT/build/release"
|
|
PROFILE="${NOTARY_PROFILE:-Onyx}"
|
|
TEAM="PP34X97WS3"
|
|
APP_NAME="Onyx"
|
|
|
|
cd "$ROOT"
|
|
|
|
VERSION=$(awk -F'"' '/MARKETING_VERSION/ {print $2; exit}' project.yml)
|
|
DMG="$BUILD/${APP_NAME}-${VERSION}.dmg"
|
|
|
|
fail() { echo "✗ $*" >&2; exit 1; }
|
|
step() { echo; echo "── $* ──"; }
|
|
|
|
# ---------------------------------------------------------------- Vorprüfung
|
|
#
|
|
# Beide Prüfungen vorweg statt unterwegs: ein Fehlschlag nach dem Archivieren
|
|
# kostet Minuten, und die Notarisierung scheitert sonst erst nach dem Hochladen.
|
|
|
|
step "Vorprüfung"
|
|
security find-identity -v -p codesigning | grep -q "Developer ID Application" \
|
|
|| fail "Kein „Developer ID Application“-Zertifikat im Schlüsselbund. Siehe Kopf dieses Skripts."
|
|
|
|
xcrun notarytool history --keychain-profile "$PROFILE" >/dev/null 2>&1 \
|
|
|| fail "Kein notarytool-Profil „$PROFILE“. Siehe Kopf dieses Skripts."
|
|
|
|
command -v xcodegen >/dev/null || fail "xcodegen fehlt (brew install xcodegen)"
|
|
echo "✓ Zertifikat, Notarisierungsprofil und xcodegen vorhanden"
|
|
|
|
step "Projekt erzeugen"
|
|
xcodegen generate
|
|
|
|
step "Tests"
|
|
(cd Packages/OnyxKit && swift test 2>&1 | tail -3)
|
|
|
|
# ------------------------------------------------------------------ Bauen
|
|
#
|
|
# Über ein Archiv und nicht über `build`: nur exportArchive signiert das
|
|
# fertige Bundle vollständig mit der Verteilungsidentität, samt aller
|
|
# eingebetteten Programme.
|
|
|
|
step "Archivieren"
|
|
rm -rf "$BUILD"
|
|
mkdir -p "$BUILD"
|
|
xcodebuild archive \
|
|
-project Onyx.xcodeproj -scheme Onyx -configuration Release \
|
|
-archivePath "$BUILD/$APP_NAME.xcarchive" \
|
|
-allowProvisioningUpdates \
|
|
CODE_SIGN_STYLE=Automatic \
|
|
CODE_SIGN_IDENTITY="Developer ID Application" \
|
|
DEVELOPMENT_TEAM="$TEAM" \
|
|
| grep -E "error:|warning: .*deprecated|ARCHIVE SUCCEEDED" || true
|
|
|
|
[ -d "$BUILD/$APP_NAME.xcarchive" ] || fail "Archivieren fehlgeschlagen"
|
|
|
|
cat > "$BUILD/export.plist" <<PLIST
|
|
<?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>
|
|
<key>method</key><string>developer-id</string>
|
|
<key>teamID</key><string>$TEAM</string>
|
|
<key>signingStyle</key><string>automatic</string>
|
|
<key>destination</key><string>export</string>
|
|
</dict></plist>
|
|
PLIST
|
|
|
|
step "Exportieren"
|
|
xcodebuild -exportArchive \
|
|
-archivePath "$BUILD/$APP_NAME.xcarchive" \
|
|
-exportPath "$BUILD/export" \
|
|
-exportOptionsPlist "$BUILD/export.plist" \
|
|
-allowProvisioningUpdates | tail -3
|
|
|
|
APP="$BUILD/export/$APP_NAME.app"
|
|
[ -d "$APP" ] || fail "Export fehlgeschlagen"
|
|
|
|
# --------------------------------------------------------------- Nachprüfen
|
|
#
|
|
# Was hier durchrutscht, lehnt Apple nach dem Hochladen ab. Die drei Punkte
|
|
# sind genau die, an denen dieses Projekt eine Sonderbehandlung hat.
|
|
|
|
step "Signatur prüfen"
|
|
codesign --verify --deep --strict --verbose=2 "$APP" 2>&1 | tail -3
|
|
|
|
codesign -d --entitlements - "$APP" 2>/dev/null | grep -q "application-groups" \
|
|
|| fail "App-Group fehlt in den Entitlements — Calendarr wäre unerreichbar"
|
|
|
|
# Der Helfer trägt seine Kennung in der Binary, nicht in einer Info.plist.
|
|
# Stimmt sie nicht, lehnt die App ihren eigenen Helfer ab.
|
|
HELPER_ID=$(codesign -d --verbose=2 "$APP/Contents/MacOS/OnyxHelper" 2>&1 \
|
|
| awk -F= '/^Identifier=/ {print $2}')
|
|
[ "$HELPER_ID" = "com.scarriffleservices.onyx.helper" ] \
|
|
|| fail "Helfer trägt die Kennung „$HELPER_ID“ statt com.scarriffleservices.onyx.helper"
|
|
|
|
# Ad-hoc signierte Bibliotheken sind der häufigste Ablehnungsgrund.
|
|
if codesign -dv "$APP/Contents/Resources/Vendor/MediaRemoteAdapter.framework" 2>&1 \
|
|
| grep -q "adhoc"; then
|
|
fail "MediaRemoteAdapter.framework ist ad-hoc signiert — die Notarisierung lehnt das ab"
|
|
fi
|
|
echo "✓ Signaturen, Entitlements, Helfer-Kennung und Adapter in Ordnung"
|
|
|
|
# ------------------------------------------------------------------- DMG
|
|
step "DMG bauen"
|
|
STAGE="$BUILD/stage"
|
|
rm -rf "$STAGE"; mkdir -p "$STAGE"
|
|
cp -R "$APP" "$STAGE/"
|
|
ln -s /Applications "$STAGE/Applications"
|
|
|
|
rm -f "$DMG"
|
|
hdiutil create -volname "$APP_NAME" -srcfolder "$STAGE" -ov -format UDZO "$DMG" | tail -1
|
|
|
|
# Das DMG selbst wird mitsigniert — sonst meldet Gatekeeper beim Öffnen einen
|
|
# unbekannten Entwickler, obwohl die App darin einwandfrei ist.
|
|
codesign --force --sign "Developer ID Application" --timestamp "$DMG"
|
|
|
|
# ---------------------------------------------------------- Notarisierung
|
|
step "Notarisieren (das dauert)"
|
|
xcrun notarytool submit "$DMG" --keychain-profile "$PROFILE" --wait \
|
|
|| fail "Notarisierung abgelehnt. Ursache: xcrun notarytool log <id> --keychain-profile $PROFILE"
|
|
|
|
step "Ticket anheften"
|
|
# Ohne Stapeln braucht der erste Start des Nutzers eine Netzverbindung.
|
|
xcrun stapler staple "$DMG"
|
|
xcrun stapler validate "$DMG"
|
|
|
|
step "Abschließende Prüfung"
|
|
spctl -a -t open --context context:primary-signature -v "$DMG" 2>&1 | tail -2
|
|
|
|
echo
|
|
echo "✓ Fertig: $DMG"
|