diff --git a/Onyx/Onyx.entitlements b/Onyx/Onyx.entitlements index b1cd6bd..6523950 100644 --- a/Onyx/Onyx.entitlements +++ b/Onyx/Onyx.entitlements @@ -23,5 +23,39 @@ der Host mit Team-Zertifikat. Ohne das wird es nicht geladen. --> com.apple.security.cs.disable-library-validation + + + + + com.apple.security.personal-information.calendars + + + + com.apple.security.personal-information.location + + + + com.apple.security.automation.apple-events + + + + com.apple.security.device.audio-input + diff --git a/docs/spikes/E-tcc-hardened-runtime.md b/docs/spikes/E-tcc-hardened-runtime.md new file mode 100644 index 0000000..74b277d --- /dev/null +++ b/docs/spikes/E-tcc-hardened-runtime.md @@ -0,0 +1,73 @@ +# Hardened Runtime verlangt eigene TCC-Entitlements + +Aufgetreten am 10.08.2026 beim Kalender-Widget. Aufwendig zu finden, in einer +Zeile zu beheben — deshalb hier festgehalten, bevor es bei Standort, Apple +Events und Audio erneut zuschlägt. + +## Erscheinungsbild + +`EKEventStore.requestFullAccessToEvents()` kehrt nach wenigen Millisekunden mit +`false` zurück. Kein Fehler, kein Dialog. `authorizationStatus` bleibt auf +`notDetermined`. In den Systemeinstellungen taucht die App **gar nicht** auf — +und dort lässt sich auch nichts von Hand nachtragen, denn der Kalenderbereich +hat kein Pluszeichen. Einträge entstehen ausschließlich durch eine erfolgreiche +Anfrage. Man sitzt also in einer Sackgasse ohne jede Fehlermeldung. + +## Ursache + +``` +tccd: Prompting policy for hardened runtime; service: kTCCServiceCalendar + requires entitlement com.apple.security.personal-information.calendars + but it is missing +``` + +Bei aktivierter Hardened Runtime verlangt TCC diese Entitlements — **auch ohne +App-Sandbox.** Die verbreitete Annahme, sie gälten nur für sandboxed Apps, ist +falsch. Ohne sie zeigt macOS den Dialog nicht einmal an. + +## Behebung + +In `Onyx.entitlements`, je nach genutztem Dienst: + +| Dienst | Entitlement | +|---|---| +| Kalender | `com.apple.security.personal-information.calendars` | +| Standort | `com.apple.security.personal-information.location` | +| Apple Events (AppleScript) | `com.apple.security.automation.apple-events` | +| Audioaufnahme / Process Taps | `com.apple.security.device.audio-input` | +| Kontakte | `com.apple.security.personal-information.addressbook` | + +## Wie es gefunden wurde + +Nicht durch Nachdenken, sondern durch Ausschluss. Entscheidend war eine +**minimale Test-App**: normales Fenster, im Vordergrund, gleiches Zertifikat, +nichts von Onyx darin — und sie scheiterte identisch. Damit war belegt, dass es +nicht an Onyx lag, und die Suche konnte sich auf die Umgebung verlagern. + +Der Weg dorthin führte über mehrere falsche Fährten, die hier stehen, damit sie +niemand zweimal geht: + +- **`log show` wurde von zsh abgefangen** („too many arguments"). Weil stderr + umgeleitet war, sah die leere Ausgabe wie ein Befund aus. `/usr/bin/log` + benutzen. +- **`promptPolicy = 0`** im Protokoll gehörte zu `kTCCServiceReminders`, nicht + zum Kalender. Der bekam durchgehend `promptPolicy = 4`. +- **Bildschirmzeit** stand unter Verdacht (ein `digital_health_restrictions`-Profil + ist installiert), schränkt aber nur Game Center und die Zeitsynchronisation ein. +- **Ein verklemmter TCC-Eintrag** existierte tatsächlich und wurde mit + `tccutil reset Calendar ` entfernt — behob das Problem aber nicht. + +Zwei Nebenbefunde, die für sich schon Fehler waren und mitbehoben wurden: + +- **`ENABLE_DEBUG_DYLIB`** (Xcodes Voreinstellung im Debug-Build) lagert den + Programmcode in eine eigene dylib aus. Das Hauptprogramm ist dann nur ein + Rumpf, und die TCC-Anfrage erreichte `tccd` überhaupt nicht. Steht jetzt auf `NO`. +- **SwiftUIs `Settings`-Szene** wird über den privaten Selektor + `showSettingsWindow:` geöffnet und kommt bei `.accessory`-Apps unzuverlässig + an. Onyx führt sein Einstellungsfenster deshalb selbst. + +## Merksatz + +Wenn ein Berechtigungsdialog ausbleibt, ohne dass irgendwo ein Fehler steht: +zuerst `/usr/bin/log show --predicate 'process == "tccd"'` lesen. Der Grund +steht dort im Klartext — und nirgendwo sonst.