Files
onyx/project.yml
Guido Schmit f48b29e53e Helfer startet nicht: --deep hat ihm die App-Entitlements verpasst
launchd lehnte den Start ab, ohne Absturzbericht und ohne sichtbaren Fehler:

  launchd: exited with exit reason (namespace: 9 code: 0x8) - OS_REASON_EXEC
  amfid: OnyxHelper not valid: Code=-413 "No matching profile found"
  taskgated-helper: Disallowing com.scarriffleservices.onyx.helper
                    because no eligible provisioning profiles found

Ursache war OTHER_CODE_SIGN_FLAGS = --deep, das ich anfangs für das ad-hoc
signierte MediaRemoteAdapter.framework gesetzt hatte. --deep überträgt die
Entitlements der App auf jede eingebettete Binary. Der Helfer bekam dadurch
application-identifier, weatherkit und application-groups verpasst — alles
eingeschränkte Entitlements, die ein Provisioning-Profil verlangen. Ein nacktes
Kommandozeilenprogramm kann aber keines einbetten, denn das ist eine Datei im
Bundle. Also verweigerte AMFI die Ausführung.

Für das Framework wird --deep gar nicht gebraucht: es wird von /usr/bin/perl
geladen, nicht von Onyx, und dafür ist ohnehin disable-library-validation da.

Der Helfer trägt jetzt keine Entitlements — er braucht auch keine. Ein
root-Dienst mit möglichst wenig Rechten ist genau das, was man will.

Gefunden über das Protokoll von amfid und taskgated. Der Weg dorthin führte
über zwei Ausschlüsse: der Helfer läuft direkt gestartet einwandfrei, und seine
Signatur erfüllt die Anforderung der App. Damit war klar, dass es weder an der
Binary noch an der Signatur liegt, sondern an der Umgebung.
2026-08-10 23:01:51 +02:00

169 lines
7.2 KiB
YAML

name: Onyx
options:
bundleIdPrefix: com.scarriffleservices
deploymentTarget:
macOS: "26.0"
createIntermediateGroups: true
groupSortPosition: top
settings:
base:
DEVELOPMENT_TEAM: PP34X97WS3
SWIFT_VERSION: "6.0"
MARKETING_VERSION: "0.1.0"
CURRENT_PROJECT_VERSION: "1"
ENABLE_HARDENED_RUNTIME: YES
# KEIN --deep.
#
# Es überträgt die Entitlements der App auf jede eingebettete Binary. Der
# privilegierte Helfer bekam dadurch application-identifier, weatherkit und
# application-groups verpasst — allesamt eingeschränkte Entitlements, die
# ein Provisioning-Profil verlangen. Ein nacktes Kommandozeilenprogramm kann
# aber keines einbetten, also lehnte AMFI den Start ab:
#
# amfid: OnyxHelper not valid: Code=-413 "No matching profile found"
# taskgated-helper: Disallowing com.scarriffleservices.onyx.helper
# because no eligible provisioning profiles found
#
# Für das ad-hoc signierte MediaRemoteAdapter.framework wird --deep nicht
# gebraucht: dafür ist disable-library-validation da.
SWIFT_STRICT_CONCURRENCY: complete
# Xcode lagert im Debug-Build den Programmcode in eine eigene dylib aus
# (für SwiftUI-Vorschauen). Das Hauptprogramm ist dann nur noch ein Rumpf —
# und TCC ordnet Berechtigungsanfragen dem Rumpf zu, der weder Info.plist
# noch Entitlements trägt. Ergebnis: requestFullAccessToEvents() liefert
# kommentarlos false, ohne dass je ein Dialog erscheint.
ENABLE_DEBUG_DYLIB: NO
packages:
OnyxKit:
path: Packages/OnyxKit
targets:
# Der privilegierte Helfer. Läuft als root und tut genau eine Sache:
# Lüfterdrehzahlen setzen. Kein Netzwerk, keine Oberfläche, kein
# Dateizugriff — je weniger hier steht, desto kleiner die Angriffsfläche.
OnyxHelper:
type: tool
platform: macOS
sources:
- path: OnyxHelper
excludes:
- "*.plist"
dependencies:
- package: OnyxKit
product: OnyxHelperProtocol
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.onyx.helper
PRODUCT_NAME: OnyxHelper
CODE_SIGN_STYLE: Automatic
SKIP_INSTALL: YES
# Kommandozeilenprogramme haben kein Bundle. Die Kennung muss deshalb
# in die Binary selbst — sonst signiert codesign sie unter dem
# Dateinamen und die Signaturprüfung zwischen App und Helfer scheitert.
INFOPLIST_FILE: OnyxHelper/Info.plist
CREATE_INFOPLIST_SECTION_IN_BINARY: YES
Onyx:
type: application
platform: macOS
sources:
- path: Onyx
dependencies:
- target: OnyxHelper
embed: false
- package: OnyxKit
product: OnyxCore
- package: OnyxKit
product: OnyxHelperProtocol
- package: OnyxKit
product: OnyxDesign
- package: OnyxKit
product: OnyxNotch
- package: OnyxKit
product: OnyxWidgetKit
- package: OnyxKit
product: OnyxMenuBar
- package: OnyxKit
product: CalendarProvider
- package: OnyxKit
product: WeatherProvider
- package: OnyxKit
product: MediaProvider
- package: OnyxKit
product: MetricsProvider
- package: OnyxKit
product: NetworkProvider
postBuildScripts:
# Der Helfer und seine Plist müssen an genau diese Stellen: SMAppService
# sucht die Plist unter Contents/Library/LaunchDaemons und liest von dort
# den Pfad zum Programm.
- name: Helfer und Launchd-Plist einbetten
script: |
APP="$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH"
mkdir -p "$APP/MacOS" "$APP/Library/LaunchDaemons"
cp "$BUILT_PRODUCTS_DIR/OnyxHelper" "$APP/MacOS/OnyxHelper"
cp "$SRCROOT/OnyxHelper/com.scarriffleservices.onyx.helper.plist" \
"$APP/Library/LaunchDaemons/"
# Der Helfer wird eigenständig signiert — die Signatur der App deckt
# ihn nicht ab, und ohne gültige eigene Signatur lehnt launchd ihn ab.
#
# `-i` ist Pflicht: Xcode signiert Kommandozeilenprogramme sonst mit
# dem Produktnamen ("OnyxHelper") als Bezeichner. Die App prüft aber
# auf com.scarriffleservices.onyx.helper und würde ihren eigenen
# Helfer ablehnen.
codesign --force --options runtime --timestamp=none \
-i com.scarriffleservices.onyx.helper \
--sign "$EXPANDED_CODE_SIGN_IDENTITY" "$APP/MacOS/OnyxHelper"
# Das Kopieren passiert nach Xcodes Signatur und bricht damit das
# Siegel des App-Bundles ("nested code is modified or invalid").
# Deshalb zum Schluss die App selbst neu signieren — mit denselben
# Entitlements, sonst verliert sie App-Group, WeatherKit und die
# TCC-Berechtigungen.
codesign --force --options runtime --timestamp=none \
--entitlements "$SRCROOT/Onyx/Onyx.entitlements" \
--sign "$EXPANDED_CODE_SIGN_IDENTITY" \
"$BUILT_PRODUCTS_DIR/$WRAPPER_NAME"
# Bewusst ohne outputFiles: mit ihnen überspringt Xcode den Schritt,
# solange die Plist unverändert ist — auch wenn sich das Programm oder
# die Signaturvorgaben geändert haben.
# Der MediaRemote-Adapter wird aus dem mitgelieferten Quellcode gebaut,
# nicht als fertige Binary eingecheckt: so ist nachvollziehbar, was da
# läuft, und die Ad-hoc-Signatur passt zum restlichen Bundle.
#
# Er darf NICHT gelinkt werden. Geladen wird er von /usr/bin/perl, einem
# berechtigten Systemprogramm — im eigenen Prozess greift Apples
# Entitlement-Prüfung und es käme gar nichts an.
- name: MediaRemote-Adapter bauen und beilegen
script: |
OUT="$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/Vendor" \
"$SRCROOT/Scripts/build-mediaremote-adapter.sh"
inputFiles:
- $(SRCROOT)/Scripts/build-mediaremote-adapter.sh
outputFiles:
- $(BUILT_PRODUCTS_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/Vendor/mediaremote-adapter.pl
# Das Menüleistensymbol soll das Glyph aus dem App-Icon zeigen, nicht die
# abgerundete Kachel mit Verlauf. actool kompiliert das .icon-Bündel zu
# .icns und Assets.car und legt nichts Lesbares ins Bundle — und eine
# einzelne Datei daraus lässt sich nicht als Ressource referenzieren.
# Deshalb kopieren statt duplizieren: es bleibt bei einer Quelldatei.
outputFiles:
- $(BUILT_PRODUCTS_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/quartz.svg
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: com.scarriffleservices.onyx
INFOPLIST_FILE: Onyx/Info.plist
CODE_SIGN_ENTITLEMENTS: Onyx/Onyx.entitlements
CODE_SIGN_STYLE: Automatic
# Kein App-Sandbox: der privilegierte Helper, IOKit und der
# MediaRemote-Adapter sind damit unvereinbar. Der App-Group-Container
# bleibt trotzdem erreichbar — siehe docs/spikes/D-appgroup.md.
ENABLE_APP_SANDBOX: NO
ENABLE_USER_SCRIPT_SANDBOXING: NO
COMBINE_HIDPI_IMAGES: YES
# Icon-Composer-Bündel (Onyx/AppIcon.icon). actool übernimmt daraus
# alle Größen und die Transluzenz-Darstellung von macOS 26.
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon