Watermは、iPhoneやiPadからVPS、Raspberry Pi、NAS、自宅Linuxサーバーへ接続するSSHクライアントとして開発している。PCの完全な代替ではなく、外出先でログ確認やDocker・Git操作などの軽微な保守を行えることを目標にした。今回の開発では、SSH接続そのものへ進む前に、iOS 17対応のアプリ基盤と設計上の安全境界を整えた。
最初にiOSアプリの土台を整理する
初期状態はHello Worldに近く、macOSやvisionOSも対象に含まれ、テストターゲットや外部依存はなかった。M01では対象をiOS/iPadOS 17、iPhone/iPadへ絞り、AppとFeaturesを中心とした構成へ移行した。アプリ名をWatermAppへ整理し、Servers、Snippets、Settingsの3タブ、Dark表示、Cyanアクセント、String Catalog、共有scheme、Swift Testingのテストターゲットを追加した。
iOS 17を最低OSにするため、M01のタブは新しいAPIではなく標準のtabItemを使った。将来のSSH機能を見越して空の抽象層を大量に作るのではなく、Feature単位のSwiftUI構成と、Rootが所有する単一のTerminal Sessionを基本方針にしている。
SSH機能より先に安全な境界を決める
MVPではServerの追加・編集・削除、PasswordまたはSSH Key認証、Host Key検証、対話的PTY Terminal、補助キー、手動再接続、Snippetの送信前編集を提供する予定である。一方、Flow、AI、SFTP、複数Terminal、常時バックグラウンドSSH、アカウントやCloud同期は対象外にした。
通常のServer情報はSwiftDataへ保存するが、Password、秘密鍵、PassphraseはKeychainへ分離する。秘密情報をSwiftData、ログ、テスト成果物、広告へ入れない。Keychainは端末内に限定し、別端末へ復元する場合は認証情報を再入力する方針である。
Host Keyも安全性の中心になる。HostとPortに対して公開鍵の完全一致を保存し、未知の鍵は承認待ち、変更された鍵は接続中止とする。接続ライブラリのサンプルにある無条件のHost Key承認は採用しない。Snippetも選択しただけでは送信せず、ローカル編集と明示送信を分ける。改行や制御文字を含む任意のコマンドを、便利さだけを理由に自動実行しないためである。
CitadelとSwiftTermは検証後に固定する
SSH transportの第一候補にはCitadel、Terminal表示にはSwiftTermを選定した。ただし、ライブラリ名を決めただけで実装を開始するのではなく、M02を技術ゲートにした。iOS 17でのビルド、依存関係とライセンス、Password・Ed25519・Passphrase付き鍵の認証、Host Key検証、PTY、リサイズ、キャンセル、切断、バックプレッシャーを独立した検証環境で確認する。
特にCitadelの依存先や鍵形式の対応は、現在の調査だけで成功を断言できない。Ed25519やPassphrase付き鍵、Host Key変更検知、PTYの終了処理のいずれかが未達なら、本接続UIへ進まない。ライブラリの採用可否と固定版は、検証結果をもとに改めて判断する。
ビルドは成功しても画面確認は終わらない
2026年9月23日時点で、Watermは署名なしのgeneric iOS Debug/Releaseビルドに成功し、Swift TestingのUnit test 1件も成功した。変更したSwiftファイルのXcode診断も0件だった。SimulatorではServers、Snippets、Settings間の遷移を操作し、クラッシュしないことを確認した。
しかし、3つのタブでタブバー以外の主コンテンツが黒い空白になり、UI階層にも主コンテンツが現れない問題が残っている。ビルド成功や画面遷移成功だけでは、画面が正しく表示されているとは言えない。現在の次の作業はRootViewと各Feature Viewの表示経路を調べ、修正後にSimulatorで再確認することだ。iPadと実機、iOS 17での実行はまだ確認していない。
現在地
Watermは、SSHクライアントとして完成した段階ではなく、安全な接続機能を実装するためのM01基盤を整えた段階にある。今後は表示問題を解消したうえで、CitadelとSwiftTermの実証、Server情報とKeychainの保存、Host Key管理、SSH Session、Terminal入出力へ進む。
最初に接続機能を作り始めなかったのは、機能を遅らせるためではない。秘密情報の保存先、Host Keyの信頼単位、切断時の再送禁止、Snippetの明示送信などを先に決めておくことで、後から安全性を付け足すのではなく、最初から接続機能の境界に組み込めるからである。