v1.0.0 試験結果
試験概要
| 項目 | 内容 |
|---|---|
| 対象アプリ | AI KeyChain |
| バージョン | v1.0.0 |
| 試験日 | 2026-03-24 |
| 試験実施者 | Claude Code (claude-opus-4-6) |
| GitHub Issue | #28 |
試験環境
| 項目 | 内容 |
|---|---|
| OS | macOS 26.2 (Build 25C56) |
| アーキテクチャ | arm64 (Apple Silicon) |
| Swift | 6.0.3 (swiftlang-6.0.3.1.10) |
| ビルドツール | Swift Package Manager |
| コミット | 08c7f4e7 (main) |
| テスト対象 | Release ビルド + DMG配布物 |
総合結果
| 区分 | テスト数 | 合格 | 不合格 | 合格率 |
|---|---|---|---|---|
| ユニットテスト | 46 | 46 | 0 | 100% |
| ビルド・配布テスト | 4 | 4 | 0 | 100% |
| 機能テスト | 12 | 12 | 0 | 100% |
| セキュリティテスト | 4 | 4 | 0 | 100% |
| 合計 | 66 | 66 | 0 | 100% |
判定: ALL PASS
全 66 件のテストに合格しました。
エビデンス
障害発生時のスクリーンショット
localhost:9999 にプロキシ設定された状態で Claude が ECONNREFUSED エラーとなった障害の記録。
※ スクリーンショットは個人情報保護のため削除済み
エラー内容:
API Error: Unable to connect to API (ECONNREFUSED)原因: AIkeychain の SetupManager が .zshrc に ANTHROPIC_BASE_URL=http://localhost:9999 を自動書き込みしたが、プロキシサーバー(AIkeychain アプリ)が起動していなかったため、Claude の API 接続が全て失敗。
ユニットテスト実行結果
✔ Test run with 46 tests passed after 0.625 seconds.全テスト結果(クリックで展開)
◇ Test run started.
↳ Testing Library Version: 102 (arm64e-apple-macos13.0)
✔ Test "Loads all service types as keys" passed after 0.003 seconds.
✔ Test "Configured count updates after save" passed after 0.003 seconds.
✔ Test "All keys start as unconfigured" passed after 0.003 seconds.
✔ Test "Category count is 5" passed after 0.003 seconds.
✔ Test "Server initializes with default port" passed after 0.003 seconds.
✔ Test "OpenAI route found" passed after 0.003 seconds.
✔ Test "Anthropic route found" passed after 0.003 seconds.
✔ Test "xAI route found" passed after 0.003 seconds.
✔ Test "All services have system images" passed after 0.003 seconds.
✔ Test "All services have env var names" passed after 0.003 seconds.
✔ Test "Filter by category" passed after 0.003 seconds.
✔ Test "Unknown host returns nil" passed after 0.003 seconds.
✔ Test "Category count returns correct number" passed after 0.003 seconds.
✔ Test "All categories have unique colors" passed after 0.003 seconds.
✔ Test "All services have categories" passed after 0.003 seconds.
✔ Test "Token prefix format is correct" passed after 0.003 seconds.
✔ Test "Default port is 18121" passed after 0.001 seconds.
✔ Test "All services have display names" passed after 0.003 seconds.
✔ Test "Route header value is correctly formatted for Anthropic" passed after 0.003 seconds.
✔ Test "Config block contains BASE_URL for all supported services" passed after 0.001 seconds.
✔ Test "Retrieve non-existent key returns nil" passed after 0.003 seconds.
✔ Test "Save overwrites existing value" passed after 0.003 seconds.
✔ Test "Save and retrieve a key" passed after 0.003 seconds.
✔ Test "ProxyRoute covers all configured BASE_URLs" passed after 0.001 seconds.
✔ Test "Exists returns true for saved key" passed after 0.003 seconds.
✔ Test "Delete key makes it unconfigured" passed after 0.003 seconds.
✔ Test "New editor defaults to anthropic" passed after 0.003 seconds.
✔ Test "Prefix warning shows for wrong prefix" passed after 0.003 seconds.
✔ Test "Setup URLs are valid" passed after 0.003 seconds.
✔ Test "Can save with valid token" passed after 0.003 seconds.
✔ Test "Service change updates env var name" passed after 0.003 seconds.
✔ Test "Cannot save with empty token" passed after 0.003 seconds.
✔ Test "No prefix warning for correct prefix" passed after 0.003 seconds.
✔ Test "Save stores value in keychain" passed after 0.003 seconds.
✔ Test "Invalid request returns nil" passed after 0.003 seconds.
✔ Test "Parse extracts all headers" passed after 0.003 seconds.
✔ Test "Route header value is correctly formatted for OpenAI" passed after 0.003 seconds.
✔ Test "Delete removes key" passed after 0.003 seconds.
✔ Test "Editing key loads existing value" passed after 0.002 seconds.
✔ Test "Parse simple GET request" passed after 0.003 seconds.
✔ Test "Exists returns false for missing key" passed after 0.003 seconds.
✔ Test "Search filters by env var name" passed after 0.007 seconds.
✔ Test "Search filters by display name" passed after 0.007 seconds.
✔ Test "Starting twice does not crash" passed after 0.311 seconds.
✔ Test "Server can start and stop" passed after 0.607 seconds.
✔ Test run with 46 tests passed after 0.625 seconds.Release ビルド結果
Building for production...
Build complete! (8.36s)DMG 作成・マウント検証
$ hdiutil create -volname "AI KeyChain" ... -format UDZO evidence/AIKeyChain-v1.0.0.dmg
created: evidence/AIKeyChain-v1.0.0.dmg (355KB)
$ hdiutil attach evidence/AIKeyChain-v1.0.0.dmg
/dev/disk4s1 /Volumes/AI KeyChain
$ ls "/Volumes/AI KeyChain/"
AI KeyChain.app Applications@
$ file "/Volumes/AI KeyChain/AI KeyChain.app/Contents/MacOS/AIkeychain"
Mach-O 64-bit executable arm649999 ハードコード除去検証
$ grep -rn "9999" AIkeychain/ Tests/ --include="*.swift"
(0 matches - ALL CLEAR)
$ grep "9999" ~/.zshrc
(0 matches - ALL CLEAR)セキュリティ検証
# localhost 限定
$ grep "acceptLocalOnly" AIkeychain/Services/ProxyServer.swift
28: params.acceptLocalOnly = true // localhost のみ
# auth ヘッダ除去
$ grep "authorization\|x-api-key" AIkeychain/Services/ProxyServer.swift
126: if lower == "host" || lower == "authorization" || lower == "x-api-key" { continue }試験詳細
UT: ユニットテスト(自動テスト 46件)
UT-001: ProxyRoute テスト
| No | テスト項目 | 期待結果 | 結果 |
|---|---|---|---|
| UT-001-1 | Anthropic route の検出 | host=api.anthropic.com → headerName=x-api-key | OK |
| UT-001-2 | OpenAI route の検出 | host=api.openai.com → headerName=Authorization, prefix=Bearer | OK |
| UT-001-3 | xAI route の検出 | host=api.x.ai → ルートが見つかる | OK |
| UT-001-4 | 未知ホストは nil を返す | host=example.com → nil | OK |
UT-002: HTTPRequestParser テスト
| No | テスト項目 | 期待結果 | 結果 |
|---|---|---|---|
| UT-002-1 | GET リクエストのパース | method=GET, path=/v1/models, host=api.anthropic.com | OK |
| UT-002-2 | POST リクエストのパース (body付き) | method=POST, body にモデル名を含む | OK |
| UT-002-3 | ヘッダの全件抽出 | headers.count == 3 | OK |
| UT-002-4 | 不正リクエストのハンドリング | クラッシュせずに処理される | OK |
UT-003: ProxyServer テスト
| No | テスト項目 | 期待結果 | 結果 |
|---|---|---|---|
| UT-003-1 | デフォルトポート | port == 18121, isRunning == false, requestCount == 0 | OK |
| UT-003-2 | 起動・停止 | start() → stop() でクラッシュせず、isRunning == false | OK |
| UT-003-3 | 二重起動 | 2回 start() してもクラッシュしない | OK |
UT-004: ヘッダインジェクション セキュリティテスト
| No | テスト項目 | 期待結果 | 結果 |
|---|---|---|---|
| UT-004-1 | Anthropic ヘッダ形式 | prefix なし ("sk-ant-test123") | OK |
| UT-004-2 | OpenAI ヘッダ形式 | "Bearer " prefix 付き | OK |
UT-005: SetupManager テスト
| No | テスト項目 | 期待結果 | 結果 |
|---|---|---|---|
| UT-005-1 | 全ルートに BASE_URL がある | configBlock に全ホスト分の export 行 | OK |
| UT-005-2 | デフォルトポート整合性 | ProxyServer と SetupManager が一致 (18121) | OK |
UT-006: モデル・ViewModel テスト
| No | テスト項目 | 期待結果 | 結果 |
|---|---|---|---|
| UT-006-1 | KeyCategory は 5 カテゴリ | allCases.count == 5 | OK |
| UT-006-2 | 各カテゴリは一意のカラー | 色の重複なし | OK |
| UT-006-3 | ServiceType の envVarName | 全件に envVarName 設定あり | OK |
| UT-006-4 | 検索 (envVarName) | フィルタリングが正しく動作 | OK |
| UT-006-5 | 検索 (displayName) | フィルタリングが正しく動作 | OK |
UT-007: その他の自動テスト (26件)
| No | テスト項目 | 結果 | No | テスト項目 | 結果 |
|---|---|---|---|---|---|
| 01 | Loads all service types as keys | OK | 14 | Exists returns true for saved key | OK |
| 02 | All keys start as unconfigured | OK | 15 | Exists returns false for missing key | OK |
| 03 | Configured count updates after save | OK | 16 | Delete removes key | OK |
| 04 | Delete key makes it unconfigured | OK | 17 | New editor defaults to anthropic | OK |
| 05 | Filter by category | OK | 18 | Editing key loads existing value | OK |
| 06 | Category count returns correct number | OK | 19 | Can save with valid token | OK |
| 07 | All services have system images | OK | 20 | Cannot save with empty token | OK |
| 08 | All services have display names | OK | 21 | Prefix warning shows for wrong prefix | OK |
| 09 | All services have categories | OK | 22 | No prefix warning for correct prefix | OK |
| 10 | Token prefix format is correct | OK | 23 | Service change updates env var name | OK |
| 11 | Save and retrieve a key | OK | 24 | Save stores value in keychain | OK |
| 12 | Retrieve non-existent key returns nil | OK | 25 | Setup URLs are valid | OK |
| 13 | Save overwrites existing value | OK | 26 | ProxyRoute covers all configured BASE_URLs | OK |
BT: ビルド・配布テスト (4件)
| No | テスト項目 | 期待結果 | 結果 | 備考 |
|---|---|---|---|---|
| BT-001-1 | Debug ビルド | エラーなしで成功 | OK | swift build (3.78s) |
| BT-001-2 | Release ビルド | エラーなしで成功 | OK | swift build -c release (8.36s) |
| BT-001-3 | DMG 作成 | DMGファイル生成 | OK | 355KB, UDZO圧縮 |
| BT-001-4 | DMG マウント確認 | .app + Applications リンク | OK | Mach-O 64-bit arm64 |
FT: 機能テスト (12件)
FT-001: デフォルトポート変更
| No | テスト項目 | 期待結果 | 結果 | 根拠 |
|---|---|---|---|---|
| FT-001-1 | ProxyServer デフォルトポート | 18121 | OK | var port: UInt16 = AppState.defaultPort |
| FT-001-2 | SetupManager デフォルトポート | 18121 | OK | port: UInt16 = AppState.defaultPort |
| FT-001-3 | .zshrc に 9999 なし | grep 0件 | OK | grep "9999" ~/.zshrc → 0 matches |
FT-002: ポート番号永続化
| No | テスト項目 | 期待結果 | 結果 | 根拠 |
|---|---|---|---|---|
| FT-002-1 | 初期値 | UserDefaults 未設定時 18121 | OK | stored > 0 ? UInt16(clamping: stored) : Self.defaultPort |
| FT-002-2 | UserDefaults 保存 | changePort() で保存 | OK | UserDefaults.standard.set(Int(newValue), ...) |
| FT-002-3 | init() で復元 | proxyServer.port が設定される | OK | proxyServer.port = proxyPort in init() |
FT-003: .zshrc 自動書き込み防止
| No | テスト項目 | 期待結果 | 結果 | 根拠 |
|---|---|---|---|---|
| FT-003-1 | 起動時に自動書き込みしない | configure() 呼び出しなし | OK | startProxyIfNeeded() は ProxyServer.start() のみ |
| FT-003-2 | ユーザー操作時のみ | ボタン経由のみ | OK | SetupView / SetupShellStepView のボタンのみ |
FT-004: ポート番号変更 UI
| No | テスト項目 | 期待結果 | 結果 | 根拠 |
|---|---|---|---|---|
| FT-004-1 | MenuBarView | "Change Port..." あり | OK | Button("Change Port...") |
| FT-004-2 | SetupView | ポート入力 TextField あり | OK | TextField("Port", text: $portText) |
| FT-004-3 | OnboardingView | ポート入力あり | OK | SetupShellStepView に Port TextField |
| FT-004-4 | バリデーション | 1023以下は拒否 | OK | value >= 1024 ガード |
| FT-004-5 | ハードコードなし | 全 View 動的表示 | OK | grep -rn "9999" → 0件 |
ST: セキュリティテスト (4件)
| No | テスト項目 | 期待結果 | 結果 | 根拠 |
|---|---|---|---|---|
| ST-001-1 | API キーのハードコードなし | 実キー値がない | OK | テスト用 prefix パターンのみ |
| ST-001-2 | .zshrc にキー値書き込みなし | BASE_URL のみ出力 | OK | generateConfigBlock() はURL文字列のみ |
| ST-001-3 | localhost 限定 | acceptLocalOnly = true | OK | ProxyServer.swift:28 |
| ST-001-4 | auth ヘッダ除去 | Host/Authorization/x-api-key スキップ | OK | ProxyServer.swift:126 |
修正履歴
| 日時 | 内容 | 対象ファイル |
|---|---|---|
| 2026-03-23 | .zshrc からプロキシ設定ブロック削除(緊急対応) | ~/.zshrc |
| 2026-03-24 | デフォルトポートを 9999 → 18121 に変更 | AppState.swift, ProxyServer.swift, SetupManager.swift |
| 2026-03-24 | .zshrc 自動書き込みを廃止(ユーザー明示操作のみ) | SetupManager.swift |
| 2026-03-24 | ポート番号選択 UI 追加 | MenuBarView.swift, SetupView.swift, OnboardingView.swift |
| 2026-03-24 | ポート番号 UserDefaults 永続化 | AppState.swift |
| 2026-03-24 | HelpView の 9999 ハードコードを動的参照に修正 | HelpView.swift |
| 2026-03-24 | テストのポート番号を AppState.defaultPort 参照に修正 | ProxyTests.swift, SetupManagerTests.swift |
成果物
| ファイル | 説明 |
|---|---|
evidence/AIKeyChain-v1.0.0.dmg | 配布用DMGファイル (355KB) |
evidence/test_specification.md | 試験仕様書(結果記入済み) |
evidence/fix_proxy_removed.md | プロキシ設定修正記録 |
evidence/localhosteror.png | 個人情報保護のため削除済み |