
Вашето Mac приложение получава достъп до микрофона — после го забравя при всяко стартиране
GeekBye поиска разрешение за микрофона, вие го дадохте и всичко работеше. При следващото стартиране: изчезнало. А приложението изобщо не се появи в Системни настройки → Микрофон. Виновникът беше функция за сигурност на macOS, която тихомълком пускаше приложението от път, който изчезва — ето диагнозата и корекцията с един-единствен подкана.
Ето бъг, който те кара да се съмняваш в собствените си очи. Инсталираш GeekBye, той иска достъп до микрофона, натискаш Allow и транскрипцията работи. Чудесно. Затваряш, отваряш го отново на следващата сутрин — и той иска достъп до микрофона пак. Отиваш да провериш Системни настройки → Поверителност и сигурност → Микрофон, за да го оправиш ръчно, а GeekBye дори не е в списъка. Нито отказан. Нито разрешен. Просто липсва, сякаш никога не е искал.
Всяка отделна част изглеждаше правилна. Подканата беше истинска. Разрешението работеше в момента. Приложението беше правилно подписано и нотаризирано с правилните низове за употреба. И въпреки това разрешението се изпаряваше при всяко стартиране. GeekBye v2.0.6 го поправи — а основната причина е едно от най-коварните неща, които macOS прави, за да те защити.
Функцията, която скриваше приложението от самото себе си
Виновникът е macOS App Translocation, функция за сигурност на Gatekeeper. Когато изтеглиш приложение и го пуснеш директно от DMG или от папката ~/Downloads — навсякъде, където все още е „под карантина" — macOS всъщност не го изпълнява оттам, откъдето го виждаш. Той прозрачно го копира на случаен път само за четене, дълбоко под /private/var/folders/.../AppTranslocation/… и изпълнява това копие. Това е добра защита: спира зловредно изтегляне да пипа файлове до себе си.
Но ето сблъсъка. Системата за разрешения на macOS (TCC — тази, която следи кой може да използва микрофона, камерата, екрана ти) идентифицира приложение по неговия път и кодова идентичност. Когато приложението е транслокирано, този път е случаен и временен. Затова, когато дадеш достъп до микрофона, macOS послушно записва разрешението — за път, който няма да съществува при следващото стартиране. Отваряш приложението отново, macOS го транслокира на различен случаен път, вижда приложение, за което няма никакъв запис, и пита пак. И понеже този призрачен път никога не е стабилно място, приложението никога не печели постоянен ред в Системни настройки → Микрофон.
Приложението даваше разрешение на призрак.
Ето защо също така само някои хора го срещаха. Ако твоето копие на GeekBye вече живееше в /Applications — защото си го издърпал там, или защото е стигнало там чрез автоматично обновяване — няма карантина, няма транслокация, стабилен път, и всичко се запазва перфектно. Бъгът беше невидим за нас и за всеки след първата инсталация, точно този вид бъг, който оцелява най-дълго.
Корекцията: дай на приложението истински дом
Тъй като целият проблем е нестабилен път, корекцията е да преместиш приложението на стабилен. v2.0.6 засича кога GeekBye работи транслокирано (или просто работи извън /Applications) и предлага „Move to Applications" с едно кликване — използвайки повикването за преместване на macOS, което копира бъндъла в /Applications и го рестартира оттам. От този момент нататък приложението има фиксирана идентичност: разрешението за микрофон се запазва, записът на екрана се запазва, а GeekBye най-накрая се появява в Системни настройки, където би очаквал.
Подканата е учтива за това. Тя предлага Move to Applications, Not Now и Don't Ask Again — и помни последния избор, така че приложението никога не досажда на някого, който има умишлена причина да го пуска отдругаде. Решението дали изобщо да покаже подканата е изолирано в малки, чисти функции (транслокиран ли е този билд? извън /Applications ли е? потисна ли го потребителят?), така че логиката е тествана единично без нужда да пускаш истински нотаризиран билд на истински том под карантина.
Същото издание опрости и самото изживяване с разрешенията. GeekBye използваше собствен, специално направен вътрешен прозорец за разрешения — няколко стотин реда UI, опитващи се да възпроизведат нещо, което операционната система вече прави добре. v2.0.6 го изтри и се опря на нативната подкана за разрешения на macOS, подкрепена от тих, неблокиращ банер, който се появява само когато необходимо разрешение действително липсва. По-малко код и поведение, което потребителите вече разпознават, защото всяко друго Mac приложение работи по същия начин.
Частта, с която най-много се гордея: доказахме го, преди да го повярваме
Щеше да е лесно да предположим транслокация и да пуснем корекция. Вместо това изданието пусна първо диагностика при стартиране: при стартиране GeekBye сега докладва собствения си път на изпълнимия файл и дали е транслокиран, дали е вътре в /Applications, и текущия статус на разрешенията за микрофон и екран. Тази телеметрия превърна една правдоподобна теория в потвърдена — продукционните данни показаха, че засегнатите сесии всъщност работят от транслокирани пътища извън /Applications, точно както беше предсказано.
Този ред има значение. „Подканата се появява, но разрешението не се запазва" има няколко възможни обяснения — проблем с подписа, липсващ низ за употреба, проблем с entitlement, странност в базата данни на TCC. Изключихме причините на ниво API (пътят на заявката беше доказуемо правилен), после оставихме реалните данни да сочат към слоя на идентичността/пътя, вместо да пуснем обнадеждаваща корекция и да се надяваме, че тикетите за поддръжка спират.
Три неща, на които учи този бъг
- Разрешение, което подканя, но не се запазва, е проблем на идентичността, не на API-то. Ако кодът на заявката е правилен, а разрешението пак изчезва, спри да пренаписваш заявката. Питай към кой път и кодова идентичност операционната система обвързва разрешението — и дали тази идентичност е стабилна между стартиранията.
- Пусни диагностиката с (или преди) корекцията. Няколко полета — откъде работя, какъв е статусът на разрешенията ми — превърнаха едно образовано предположение в проверена основна причина и ни казаха точно кои потребители са засегнати. Инструментирай границата, която подозираш, преди да я закърпиш.
- Бъговете, които се крият от разработчиците, са тези, работещи в „грешната" среда. Нашият живееше в
/Applicationsна всяка машина за разработка, така че бъгът беше структурно невидим за нас, докато удряше потребителите при първа инсталация. Когато доклад не се възпроизвежда, първият въпрос е какво е различно за мястото, където работи, не греши ли потребителят.
GeekBye v2.0.6 пусна подканата за преместване и диагностиката заедно. За по-широката дъга на надеждността, в която това се вписва, виж какво всъщност изисква версия 2 (v2.0.0) и защо записът на екрана хваща грешния монитор (v2.0.10) — друг бъг, който изплува само в специфична среда. За изданието с дребни детайли до него, спокоен софтуер: корекцията на трептенето и чипът за режим-на-отговор (v2.0.3 + v2.0.5).