
あなたのMacアプリはマイクへのアクセスを許可する — そして起動するたびに、それを忘れる
GeekByeがマイクの許可を求め、あなたは許可し、動きました。次に起動すると、消えている。しかもアプリは、システム設定 → マイク にそもそも一度も現れなかった。犯人は、アプリを「消えてしまうパス」から静かに実行していたmacOSのセキュリティ機能でした — その診断と、たった一つのプロンプトで済む修正をここに記します。
自分の目を疑わせるバグを一つ紹介しましょう。GeekByeをインストールし、マイクへのアクセスを求められ、許可をクリックすると、文字起こしが動きます。結構。あなたは終了し、翌朝また開くと — もう一度 マイクへのアクセスを求めてきます。手動で直そうとシステム設定 → プライバシーとセキュリティ → マイク を確認しに行くと、GeekByeはそもそも一覧にいません。 拒否されてもいない。許可されてもいない。まるで一度も求めなかったかのように、ただ不在なのです。
一つ一つの要素は、どれも正しく見えました。プロンプトは本物でした。許可はその場では機能しました。アプリは正しい用途文字列とともに、きちんと署名され公証されていました。それでも許可は起動するたびに蒸発しました。GeekBye v2.0.6がこれを修正しました — そして根本原因は、macOSがあなたを守るためにする、最もこっそりとした振る舞いの一つです。
アプリを、アプリ自身から隠していた機能
犯人はmacOS App Translocation、Gatekeeperのセキュリティ機能です。アプリをダウンロードし、それをDMGから直接、あるいは~/Downloadsフォルダから — まだ「隔離」されているどこかから — 実行すると、macOSは実際にはあなたが見ている場所からそれを実行しません。それを/private/var/folders/.../AppTranslocation/…の奥深くにある、ランダム化された読み取り専用のパスへ透過的にコピーし、そのコピー を実行します。これは良い防御です: 悪意あるダウンロードが、自分の隣にあるファイルを改ざんするのを止めるのですから。
しかし、ここで衝突が起きます。macOSの許可システム(TCC — 誰があなたのマイク、カメラ、画面を使えるかを追跡するもの)は、アプリをそのパスとコードのアイデンティティによって識別します。アプリがtranslocateされると、そのパスはランダムで一時的です。だからあなたがマイクへのアクセスを許可すると、macOSは律儀にその許可を記録します — 次の起動には存在しないパスに対して。 アプリを開き直すと、macOSはそれを別のランダムなパスへtranslocateし、記録のないアプリを目にし、また尋ねてくる。そしてその幻のパスは決して安定した場所にならないので、アプリはシステム設定 → マイク に永続的な行を一度も得られないのです。
アプリは、幽霊に許可を与えていたのです。
これは、一部 の人だけがこれに遭遇した理由でもあります。あなたのGeekByeのコピーがすでに/Applicationsにあったなら — そこへドラッグしたから、あるいは自動更新でそこに来たから — 隔離もなく、translocationもなく、安定したパスがあり、何もかもが完璧に保持されます。このバグは、私たちにも、最初のインストールを過ぎた誰にとっても見えませんでした — それはまさに、最も長く生き延びる類のバグです。
修正: アプリに本当の住まいを与える
問題のすべてが不安定なパスにあるのだから、修正はアプリを安定したパスに乗せることです。v2.0.6は、GeekByeがtranslocateされて(あるいは単に/Applicationsの外から)動いているのを検知し、ワンクリックの**「Move to Applications」(アプリケーションへ移動)**を提供します — バンドルを/Applicationsへコピーし、そこから再起動する、macOSの再配置呼び出しを使って。その時点からアプリは固定されたアイデンティティを持ちます: マイクの許可が持続し、画面収録も持続し、GeekByeはやっと、あなたが期待する場所であるシステム設定に現れるのです。
プロンプトはそれについて礼儀正しくあります。Move to Applications(アプリケーションへ移動)、Not Now(今はしない)、**Don't Ask Again(今後表示しない)**を提供し — そして最後の選択を覚えているので、あえて別の場所から実行する意図的な理由がある人を、アプリは決してしつこく煩わせません。そもそもプロンプトを表示するかどうか の判断は、小さく純粋な関数へ分離されています(このビルドはtranslocateされているか? /Applicationsの外か? ユーザーはそれを抑制したか?)。そのおかげで、本物の隔離されたボリューム上で本物の公証済みビルドを起動しなくても、ロジックはユニットテストできます。
同じリリースは、許可の体験そのものも簡素化しました。GeekByeはかつて、独自の作り込んだアプリ内許可ウィンドウをポップさせていました — OSがすでに上手にやっていることを再現しようとする、数百行のUIです。v2.0.6はそれを削除し、ネイティブのmacOS許可プロンプトに頼りました。必要な許可が実際に欠けているときにだけ現れる、静かでブロックしないバナーがそれを支えています。コードは減り、しかも他のあらゆるMacアプリが同じように動くので、ユーザーがすでに見慣れている振る舞いになりました。
私が一番誇りに思う部分: 信じる前に、証明した
translocationを推測 して修正を出荷するのは簡単だったでしょう。その代わり、このリリースはまず起動時の診断を出荷しました: 起動時に、GeekByeは今や自分自身の実行ファイルのパスと、translocateされているか、/Applicationsの中にいるか、そして現在のマイクと画面の許可状態を報告します。そのテレメトリが、もっともらしい仮説を確証済みのものへ変えました — 本番データは、影響を受けたセッションが実際に、/Applicationsの外のtranslocateされたパスから動いていたことを、まさに予測どおりに示したのです。
その順序が大事です。「プロンプトは現れるのに許可が持続しない」には、いくつもの可能な説明があります — 署名の問題、欠けた用途文字列、エンタイトルメントの問題、TCCデータベースの癖。私たちはAPIレベルの原因を除外し(リクエストの経路は明白に正しかった)、それから現実世界のデータに、希望的な修正を出荷して問い合わせが止まるのを祈るのではなく、アイデンティティ/パスの層を指し示させたのです。
このバグが教える三つのこと
- プロンプトは出るのに持続しない許可は、API の問題ではなく アイデンティティ の問題だ。 リクエストのコードが正しいのに許可がなお消えるなら、リクエストを書き直すのをやめましょう。OSがその許可を、どのパスとコードのアイデンティティに紐づけているのか — そしてそのアイデンティティが起動をまたいで安定しているのか — を問いましょう。
- 診断を、修正と同時に(あるいはその前に)出荷せよ。 ほんの数個のフィールド — 自分はどこから動いているのか、許可の状態はどうか — が、当て推量を検証済みの根本原因へ変え、どのユーザーが影響を受けたのかを正確に教えてくれました。疑わしい境界を、パッチする前に計測しましょう。
- 開発者から隠れるバグは、「間違った」環境で動いているものだ。 私たちのバグは、あらゆる開発機の
/Applicationsに住んでいたので、構造的に私たちには見えないまま、初めて使うユーザーを襲っていました。報告が再現しないとき、最初の問いはユーザーが勘違いしているのか ではなく、それが動いている場所の何が違うのか です。
GeekBye v2.0.6は、再配置プロンプトと診断を一緒に出荷しました。これが収まる、より広い信頼性の弧については、バージョン2に本当に必要なもの(v2.0.0)と、なぜ画面収録は間違ったモニターを捉えるのか(v2.0.10) — これも特定の環境でだけ表面化した、もう一つのバグです — をご覧ください。隣の小さな細部のリリースについては、穏やかなソフトウェア: ちらつきの修正と、応答モードのチップ(v2.0.3 + v2.0.5)をどうぞ。