Slide 1

Slide 1 text

テストを司るデーモンに会いに 行く 〜隔離した仮想マシンでテストを通すまで〜 2026.09.12 15:35 ~ iOSDC Japan 2026 Track D h1d3mun3

Slide 2

Slide 2 text

自己紹介 • h1d3mun3(ヒデムネ) • お仕事 • iOSエンジニア • 普段はタクシーアプリを作っている !!! • 趣味はエレキギター" • BOSSのGX-1を買ったら出音が良すぎてびっくり 2

Slide 3

Slide 3 text

みなさん、日々の開発でAIエー ジェント使ってますか?

Slide 4

Slide 4 text

Docker Sandboxes とかで隔離し てますか?

Slide 5

Slide 5 text

でも…

Slide 6

Slide 6 text

Xcodeが隔離環境で動かなくて辛 くないですか?

Slide 7

Slide 7 text

隔離環境内部のClaude CodeからXcodeが直接動 かせる「augur」というツールを開発しました

Slide 8

Slide 8 text

macOS VMの内部でxcodebuild test が通らなくて困ったので今日はその話をします

Slide 9

Slide 9 text

目次 1. Motivation 2. 隔離macOS VMを作ろう! 3. Claude Codeを動かそう! 4. デーモンに会いに行こう! 5. まとめ 6. 参考資料 11

Slide 10

Slide 10 text

1. Motivation

Slide 11

Slide 11 text

コンテナ隔離の一般化 • AIエージェントにコーディングさせるために、ソースコード は読める状態にする必要 • ホストのすべてのファイルにアクセスさせるのは、AIエー ジェントの暴走リスクを踏まえるとハイリスク → 組織開発はもちろん、個人開発でもDocker Sandboxesを始 めとしたAIエージェントのコンテナ隔離が一般化 13

Slide 12

Slide 12 text

既存のコンテナ隔離の限界 • iOSなどのAppleプラットフォーム向けの開発にはAppleが提 供するXcodeが必要 • Xcodeの動作にはmacOSが必要 • 多くのコンテナ隔離ツールはゲストOSにLinuxを採用 → 既存の多くのコンテナ隔離ツールではXcodeが動作不可 14

Slide 13

Slide 13 text

Xcodeが動くmacOS VMを作れば 良いのでは?

Slide 14

Slide 14 text

Xcodeが動くmacOS VMを「自前」で構築する • Tartなどのツールで、プリビルドイメージを使いXcodeを利 用することはすでに可能 • だが「中で何が動いているかを説明できる状態」ではない → IPSWとXIPというAppleアセットへの信頼をベースに、サー ドパーティツールへの信頼を最小限にしてAIエージェント向け macOS VMの隔離環境を自前で構築して運用する 16

Slide 15

Slide 15 text

2. 隔離macOS VMを作ろう!

Slide 16

Slide 16 text

Virtualization Frameworkを使う • Appleの仮想化フレームワーク • macOSやLinux-baseのOSを仮想マシンとして作成し、利用 することができる 18

Slide 17

Slide 17 text

全体の流れ 1. macOS VM作成 2. Setup Assistantを完了 3. Xcodeを転送 19

Slide 18

Slide 18 text

macOS VM作成 1. IPSWファイルから、VZMacOSRestoreImageを作成 2. VZVirtualMachineConfigurationを作成 3. VZVirtualMachineを作成 4. VZMacOSInstallerを作成し、インストール 20

Slide 19

Slide 19 text

Setup Assistantを完了 • 固定のID/PWでアカウントをセットアップ • Remote Loginを有効化 21

Slide 20

Slide 20 text

Xcodeを転送 • macOS VMにSCPでXIPを転送 • SSH接続し、展開 • /Applicationsへ移動しxcode-selectで切り替える • 初回起動処理とシミュレーターダウンロード 22

Slide 21

Slide 21 text

3. Claude Codeを動かそう!

Slide 22

Slide 22 text

隔離環境でClaude Codeを動かす場合の課題 • 認証情報をどうやって注入するか • ホストのディレクトリをどうやって参照させるか 24

Slide 23

Slide 23 text

認証情報をどうやって注入させるか 2つの認証方式に対応させる • ANTHROPIC_API_KEY • 従量課金用 • CLAUDE_CODE_OAUTH_TOKEN • Claudeのサブスクリプションで使える認証方式 • ヘッドレスやCI環境向けのトークン 25

Slide 24

Slide 24 text

どうやって認証情報を注入するか ホストの環境変数か、下記ファイルの情報を読み込む • $HOME/.anthropic_api_key • $HOME/.claude_code_oauth_token VM上の特定ファイルに認証情報を書き込み • ~/.augur-env • ~/.zshenvにsourceを追加して認証 26

Slide 25

Slide 25 text

ホストのディレクトリをどうやって参照させるか • Virtualization Frameworkが提供するVirtioFS共有を使う • タグを指定して、ゲストVMが自動でマウントする • VZVirtioFileSystemDeviceConfiguration.macOSGuest AutomountTag 27

Slide 26

Slide 26 text

4. デーモンに会いに行こう!

Slide 27

Slide 27 text

よし!Xcodeが使えるmacOS VMを 準備した!UnitTestを実行しよう!

Slide 28

Slide 28 text

admin@admins-Virtual-Machine workspace-avow % xcodebuild -project Avow.xcodeproj -scheme Avow -destination 'platform=macOS' CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" test 〜〜〜中略〜〜〜 Testing started 2026-08-25 22:23:23.975 xcodebuild[1499:6717] IDETestOperationsObserverDebug: Failure collecting logarchive: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.testmanagerd.control was invalidated: Connection init failed at lookup with error 3 - No such process." UserInfo={NSDebugDescription=The connection to service named com.apple.testmanagerd.control was invalidated: Connection init failed at lookup with error 3 No such process.} 2026-08-25 22:23:23.977 xcodebuild[1499:6707] [MT] IDETestOperationsObserverDebug: 0.136 elapsed -- Testing started completed. 2026-08-25 22:23:23.977 xcodebuild[1499:6707] [MT] IDETestOperationsObserverDebug: 0.000 sec, +0.000 sec -- start 2026-08-25 22:23:23.977 xcodebuild[1499:6707] [MT] IDETestOperationsObserverDebug: 0.136 sec, +0.136 sec -- end Test session results, code coverage, and logs: /Users/admin/Library/Developer/Xcode/DerivedData/Avow-bcpwjhzdopisbhfdmuzjlzybcxfh/Logs/Test/TestAvow-2026.08.25_22-23-23-+0900.xcresult Testing failed: Avow encountered an error (Failed to establish communication with the test runner. (Underlying Error: Couldn’t communicate with a helper application. Try your operation again. If that fails, quit and relaunch the application and try again. The connection to service named com.apple.testmanagerd.control was invalidated: Connection init failed at lookup with error 3 - No such process.)) ** TEST FAILED **

Slide 29

Slide 29 text

** TEST FAILED **

Slide 30

Slide 30 text

実行できません #

Slide 31

Slide 31 text

エラーを読み解く NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.testmanagerd.control was invalidated: Connection init failed at lookup with error 3 No such process." 33

Slide 32

Slide 32 text

NSCocoaErrorDomainCode=4099とは • XPC接続に失敗したときのエラー ※1 • XPC通信とは、Appleプラットフォームにおけるプロセス間通 信の標準的な仕組み ※2 ※1: https://developer.apple.com/documentation/foundation/nsxpcconnectioninvalid-swift.var ※2: https://developer.apple.com/documentation/xpc 34

Slide 33

Slide 33 text

“Aqua session” はxcodebuildの実行に必須 AppleのDocumentation Archiveからの引用※ SSH経由のリモートログイン(またはLaunch Daemon)か ら `xcodebuild` を実行する場合、ホスト上で適切なセッ ション環境が構築されていないと失敗します。 Invoking xcodebuild from a remote login with ssh (or from a launch demon) fails unless the correct session environment is created on the host. 「Aquaセッション」環境は、ユーザーとしてmacOSシステ ムにインタラクティブにログインした際に作成されます。 An “Aqua session” environment is created when you interactively log into your macOS system as a user. ホストシステム上でユーザーが動作している状態であれば、 SSHログイン経由で `xcodebuild` を実行し、あらゆる種類 のテストを行うことが可能です。 Once there is a user running on the host system, running xcodebuild from an ssh login works for all types of tests. 35 https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/testing_with_xcode/chapters/08-automation.html

Slide 34

Slide 34 text

launchctlのセッションとの関連 man launchctlの記述 特定のコンテキストでのみ意味を持つジョブもありま す。 … 関連するセッションには、Aqua(デフォルト)、 Background、LoginWindowがあります。Background エージェントは、GUIへのログインとは無関係に読み込ま れる場合があります。一方、Aquaエージェントは、ユー ザーがGUIにログインしたときにのみ読み込まれます。 jobs only make sense in certain contexts. ... Relevant sessions are Aqua (the default), Background and LoginWindow. Background agents may be loaded independently of a GUI login. Aqua agents are loaded only when a user has logged in at the GUI. 36

Slide 35

Slide 35 text

つまり… • com.apple.testmanagerd.control との通信に失敗 • xcodebuildにはAquaセッションが必須 → おそらくcom.apple.testmanagerd.control はAquaセッショ ンが無いとロードされないのでは? Aquaセッションの構築にはログインが必須なのでは? 37

Slide 36

Slide 36 text

GUIログインさせた状態で やってみる

Slide 37

Slide 37 text

admin@admins-Virtual-Machine workspace-avow % xcodebuild -project Avow.xcodeproj -scheme Avow -destination 'platform=macOS' CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" test 〜〜〜中略〜〜〜 Testing started Test suite 'DataAdminServiceTests' started on 'My Mac - Avow (1131)' Test suite 'QuickPanelSelectionTests' started on 'My Mac - Avow (1131)' Test suite 'SwiftDataProjectRepositoryTests' started on 'My Mac - Avow (1131)’ 〜〜〜中略〜〜〜 2026-08-29 22:17:07.143 xcodebuild[966:6252] [MT] IDETestOperationsObserverDebug: 2.172 elapsed -- Testing started completed. 2026-08-29 22:17:07.143 xcodebuild[966:6252] [MT] IDETestOperationsObserverDebug: 0.000 sec, +0.000 sec -start 2026-08-29 22:17:07.143 xcodebuild[966:6252] [MT] IDETestOperationsObserverDebug: 2.172 sec, +2.172 sec -- end Test session results, code coverage, and logs: /Users/admin/Library/Developer/Xcode/DerivedData/Avow-bcpwjhzdopisbhfdmuzjlzybcxfh/Logs/Test/TestAvow-2026.08.29_22-16-44-+0900.xcresult ** TEST SUCCEEDED **

Slide 38

Slide 38 text

** TEST SUCCEEDED **

Slide 39

Slide 39 text

実行できた〜$

Slide 40

Slide 40 text

仮説を確かめよう 42

Slide 41

Slide 41 text

macOSにおける常駐サービス • Daemon: システム全体で常駐 • UIを表示したり、ログインセッションとやり取りしてはならない • Agent: ユーザーごとに常駐 • ユーザーとのやり取りを行うあらゆる処理を担当 → これらはlaunchdで管理される 43

Slide 42

Slide 42 text

macOSにおける常駐サービス man launchdの記述 launchdの用語において、Daemonとは定義上、す べてのクライアントに対して単一のインスタンスの みが存在するシステム全体のサービスを指します。 一方、Agentはユーザーごとに実行されるサービス です。Daemonは、UIを表示したり、ユーザーのロ グインセッションと直接やり取りしたりするべきで はありません。ユーザーとのやり取りを伴うあらゆ る処理は、Agentを介して行う必要があります。 In the launchd lexicon, a daemon is, by definition, a system-wide service of which there is one instance for all clients. An agent is a service that runs on a per-user basis. Daemons should not attempt to display UI or interact directly with a user's login session. Any and all work that involves interacting with a user should be done through agents. 44

Slide 43

Slide 43 text

MachServicesとLimitLoadToSessionType MachServices launchdがDaemon/Agentを登録するときの名前です。この キーの値でXPC接続が行われます LimitLoadToSessionType Agentをどのようなときにロードするかの指定です。

Slide 44

Slide 44 text

testmanagerdがふたつ…. % ls /System/Library/LaunchDaemons | grep -i testmanager com.apple.testmanagerd.plist % ls /System/Library/LaunchAgents | grep -i testmanager com.apple.testmanagerd.plist → DaemonにもAgentにもtestmanagerdが存在する # # # 46

Slide 45

Slide 45 text

違いをチェック com.apple.testmanagerd.plist (Daemon) com.apple.testmanagerd.plist (Agent) Location /System/Library/LaunchDaemons/ com.apple.testmanagerd.plist /System/Library/LaunchAgents/ com.apple.testmanagerd.plist Label com.apple.testmanagerd.remote com.apple.testmanagerd MachServices com.apple.dt.xctestd.remote.runner com.apple.dt.xctestd.remote.target com.apple.dt.xctestd.target com.apple.testmanagerd com.apple.testmanagerd.control Program /usr/libexec/testmanagerd /usr/libexec/testmanagerd LimitLoadToSessionType (なし) [LoginWindow, Aqua] 47

Slide 46

Slide 46 text

[再掲] エラーを読み解く NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.testmanagerd.control was invalidated: Connection init failed at lookup with error 3 No such process." 48

Slide 47

Slide 47 text

結論 • xcodebuildが探したもの……. → com.apple.testmanagerd.control • それがいるのは………………… → LaunchAgents • Agent がロードされるのは… → LoginWindow / Aqua のみ • macOS VMでは……………….. → ログインしてなかった → Aquaセッションがないのでロードされず、Agentがいなかった

Slide 48

Slide 48 text

5. まとめ 50

Slide 49

Slide 49 text

まとめ% • Virtualization Frameworkを利用して、macOS VM環境をMac上に立ち 上げ、Xcodeをインストールして利用可能にすることができた • 隔離環境にClaude Codeを導入し、利用可能な状況にできた • xcodebuild testの実行にはAquaもしくはLoginWindowセッションが必須 • macOS VMにGUIログインした結果、Aquaセッションが生まれ、 LaunchAgentsのAgentがロードされ、隔離環境でもxcodebuild testが実 行できた 51

Slide 50

Slide 50 text

6. 参考資料 52

Slide 51

Slide 51 text

参考資料 • https://www.github.com/h1d3mun3/augur • man launchctl • man launchd • https://developer.apple.com/documentation/foundation/nsxpcconnectioninvalidswift.var • https://developer.apple.com/documentation/xpc • https://developer.apple.com/library/archive/documentation/DeveloperTools/ Conceptual/testing_with_xcode/chapters/08-automation.html 53