Steven
Steven5 мин четене

Вашето Mac приложение получава достъп до микрофона — после го забравя при всяко стартиране

GeekBye поиска разрешение за микрофона, вие го дадохте и всичко работеше. При следващото стартиране: изчезнало. А приложението изобщо не се появи в Системни настройки → Микрофон. Виновникът беше функция за сигурност на macOS, която тихомълком пускаше приложението от път, който изчезва — ето диагнозата и корекцията с един-единствен подкана.

macOS
Разрешения
Инженеринг
Издания на GeekBye
Вашето Mac приложение получава достъп до микрофона — после го забравя при всяко стартиране

Ето бъг, който те кара да се съмняваш в собствените си очи. Инсталираш 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 (пътят на заявката беше доказуемо правилен), после оставихме реалните данни да сочат към слоя на идентичността/пътя, вместо да пуснем обнадеждаваща корекция и да се надяваме, че тикетите за поддръжка спират.

Три неща, на които учи този бъг

  1. Разрешение, което подканя, но не се запазва, е проблем на идентичността, не на API-то. Ако кодът на заявката е правилен, а разрешението пак изчезва, спри да пренаписваш заявката. Питай към кой път и кодова идентичност операционната система обвързва разрешението — и дали тази идентичност е стабилна между стартиранията.
  2. Пусни диагностиката с (или преди) корекцията. Няколко полета — откъде работя, какъв е статусът на разрешенията ми — превърнаха едно образовано предположение в проверена основна причина и ни казаха точно кои потребители са засегнати. Инструментирай границата, която подозираш, преди да я закърпиш.
  3. Бъговете, които се крият от разработчиците, са тези, работещи в „грешната" среда. Нашият живееше в /Applications на всяка машина за разработка, така че бъгът беше структурно невидим за нас, докато удряше потребителите при първа инсталация. Когато доклад не се възпроизвежда, първият въпрос е какво е различно за мястото, където работи, не греши ли потребителят.

GeekBye v2.0.6 пусна подканата за преместване и диагностиката заедно. За по-широката дъга на надеждността, в която това се вписва, виж какво всъщност изисква версия 2 (v2.0.0) и защо записът на екрана хваща грешния монитор (v2.0.10) — друг бъг, който изплува само в специфична среда. За изданието с дребни детайли до него, спокоен софтуер: корекцията на трептенето и чипът за режим-на-отговор (v2.0.3 + v2.0.5).

Свързани статии

Анатомията на изпращането на софтуер до съвършенство: как прегледът на кода улови това, което тестовете не можаха
Steven
Steven6 мин четене

Анатомията на изпращането на софтуер до съвършенство: как прегледът на кода улови това, което тестовете не можаха

В цялата поредица за GeekBye v2 се случва едно и също нещо: дадена поправка минава всеки тест на машината на разработчика, а после прегледът на кода доказва, че тя би се провалила за почти всеки друг. Това е работният процес зад девет издания — портата на прегледа, ранните улавяния при поправките и дисциплината „тествай преди да изпратиш“, която превръща „при мен работи“ в „работи“.

Инженеринг
Процес
Преглед на кода
Спокоен софтуер: как убихме един трептящ превключвател и научихме чата да казва в кой режим е
Steven
Steven6 мин четене

Спокоен софтуер: как убихме един трептящ превключвател и научихме чата да казва в кой режим е

Две малки издания на GeekBye, без ефектни функции — просто превключвател в настройките, който спря да трепти, и чат асистент, който най-накрая ти казва дали е отговорил в режим на среща или в режим на кодиране. Ето колко всъщност струва „спокойният софтуер", по един детайл наведнъж.

Продукт
Дизайн
Инженеринг
Какво всъщност изисква една Версия 2: 206 комита честни състояния
Steven
Steven7 мин четене

Какво всъщност изисква една Версия 2: 206 комита честни състояния

GeekBye v2 не беше издание с нови функции. Бяха 206 комита, насочени към една-единствена идея: приложението никога не бива да лъже за собственото си състояние. Ето колко струва това — включително еднолинейната грешка в lockfile, която за малко да ни попречи да пуснем каквото и да било от всичко това.

Надеждност
Инженеринг
Издание