OpenAPI セルフブートストラップ
Shepherd の実行中 HTTP API を Shepherd 自身の機能(API 定義、ケース、シナリオオーケストレーション、実行)でテストします。
実行
# A. シングルチェーンブートストラップ(ログイン → 抽出 → 認証済みチェーン + ネガティブ 401):
# 実際のチェーン実行機構を検証します
python3 .claude/skills/openapi-bootstrap/selftest.py
# B. 全モジュールシナリオカバレッジ:OpenAPI タグごとに 1 つの CRUD/ライフサイクルシナリオを
# モジュールごとのレポート付きで実行します
python3 .claude/skills/openapi-bootstrap/scenarios_all.py
# C. テスト計画操作のセルフチェック(計画 CRUD、計画ドキュメント、ケースリンク、
# 計画実行、単一ケースの再実行、スケジュール)
python3 .claude/skills/openapi-bootstrap/plans_selftest.py
scenarios_all.py は、ビジネスモジュールごとに 1 つの実際のチェーンシナリオ(20 モジュール)を構築し、API ケース(種類=CASE、認証ヘッダー/変数抽出/アサーション付き)を参照し、CRUD/ライフサイクルチェーンとして順序付けられ、環境内でインプロセス実行されます。失敗戦略 CONTINUE → 1 回の実行でモジュールごとにステップ単位の合格/不合格 + 理由が得られます。現在すべてグリーン:20/20 モジュール、114/114 ステップ。「ケース更新」エンドポイントはありません → 実行ごとに古いホルダー定義(そのケースをカスケード削除)を削除し、再構築します。永続リソース(プロジェクト/ユーザー/要件)には実行ごとに一意のサフィックスが付与され、繰り返し実行しても一意性制約に違反しません。
構築中に確認された実際の制約(チェーンに組み込み済み。バックエンドの列挙型が変更された場合は同期を維持すること):
- リソースプール
poolType∈ {Node,Kubernetes}(LOCAL なし)。allOrg=falseの場合、orgIdsは空であってはなりません。 - タスク作成
POST /decomposition/{id}/taskは{"taskId": <slug>}(idではない)を返します。ポイント/ステータスエンドポイントはその taskId を使用します。 - 配信エグゼキュータ
CLAUDE_CODE/CODEXは同期スタブです:POST /deliveryは 1 ステップで完了し、直接DELIVEREDとして作成されます(実行中/完了の非同期遷移なし)。 /runner/probeと/runner-agent/{id}/runはオンラインのランナーエージェントが必要です(それ以外の場合は 502)。ローカルチェーンは管理プレーンのみをカバーします。- いくつかのリストエンドポイントは
?projectId=が必要です(要件/スキル/機能ケース/ケースレビュー)。 - 作成は 201、削除/部分更新は 204 を返します → 厳密な
StatusIs(200)ではなく、汎用的なResponseCode < 400成功アサーションを使用してください。
| 環境変数 | デフォルト | 説明 |
|---|---|---|
SHEPHERD_BASE | http://127.0.0.1:9180 | バックエンドアドレス |
SHEPHERD_USER / SHEPHERD_PASS | admin / s3cret | ログイン認証情報(SHEPHERD_ADMIN_PASSWORD) |
SHEPHERD_PROJECT_ID | 自動解決 | 対象プロジェクト。デフォルトは最初の組織の最初のプロジェクト。存在しない場合は作成 |
スクリプト、環境、定義、ケース、シナリオはすべて名前で作成または再利用されます。繰り返し実行しても蓄積されません。
(自举环境 / 自举链路 などの既存リソース名は中国語のまま保持されます。これらは名前による再利用キーとして永続化されており、名前を変更すると既存の行が孤立します。)
フロー(7 ステップ)
- トークンのログイン(リソース設定のみ管理者呼び出し)
- 組織 → プロジェクトの解決/作成
- このシステムの OpenAPI を取得(
GET /api-docs/openapi.json)→ 冪等インポート(POST /api/definition/import。同じメソッド+パスはスペックを上書き、重複なし)。サンプルチェックでスペックが設定され、各インターフェースにアサーションを持つケースがあることを確認 - このホストを指す環境を作成または再利用(
baseUrl= このサーバー) - ブートストラップチェーン定義の下に 4 つの実際のケースを作成または再利用
- それらのケースをステップとして参照するシナリオを作成または再利用(
kind=CASE)、順序を整え、環境で実行 - レポートを取得。ステップごとの ✅/❌ + 抽出された変数 + アサーション数を出力
これは実際のチェーンであり、ハードコードされた GET ではありません
シナリオは、ハードコードされたリクエストをインライン化する代わりに、API ケースを参照します(kind=CASE)。ケースは POST + GET + 認証ヘッダー + 変数抽出 + クロスステップ連鎖をカバーします:
① ログインしてトークンを抽出 POST /auth/login assert status 200 + contains "token" → extract token = $.token
② 認証済み組織一覧 GET /organization header Authorization: Bearer ${token} → extract orgId = $.items[0].id
③ 認証済みプロジェクト一覧(orgId 別) GET /project?organizationId=${orgId} (token と orgId の両方が置換)
④ ネガティブ:トークンなし拒否 GET /organization assert status 401
主要な実行機構(crates/api-test/src/adapters/{plan,local,pg}.rs、crates/api-runner/src/domain/runner.rs を参照):
- CASE ステップはインプロセスで実行され、ケースの完全なメソッド/URL/ボディ/ヘッダー/認証/アサーション/プロセッサをロードします。リソースプールは不要です(インライン
REQUESTステップはヘッダーをドロップするため、CASE を使用)。 - EXTRACT プロセッサは
$.tokenなどを実行変数に書き込み、ステップ間で渡されます。 ${var}シングルブレース置換は、URL / ヘッダー値 / ボディに適用されます({{}}ではありません)。- 環境の baseUrl は相対 URL の前に付加されます。デフォルトヘッダーはギャップを埋めます(同じ名前のケースヘッダーが優先されます)。
- 既知の制限:
Variableアサーションはシナリオ内部の実行変数を参照できません(plan.rsはアサーション評価に変数を渡しません)。そのため、このスクリプトはVariableアサーションの代わりにStatusIs/BodyContainsを使用します。
テスト計画操作のセルフチェック
plans_selftest.py は、HTTP API を通じてテスト計画操作をエンドツーエンドで検証します。計画の作成/再利用(計画 ID はローカル状態ファイル .plan_selftest_id に保持されます。計画一覧/削除エンドポイントがないため)、PUT 更新ラウンドトリップ(説明/タグ/passThreshold)、計画ドキュメント保存 + リンク同期、ケースリンク(1 シナリオ + 1 API ケース)、完全な計画実行(すべての行が SUCCESS、シナリオ行には reportId があり、そのステップはすべて SUCCESS)、単一ケースの再実行、スケジュールの作成/削除(201/204/404)、ケースのリンク解除(204 + リスト縮小)。冪等:連続して 2 回実行しても、両方とも完全にグリーンである必要があります。
バックエンドインポーターの拡張(同時に出荷)
POST /api/definition/import は現在:
- 各操作の
parameters(クエリ/ヘッダー/パス。必須フラグはリマークにエンコード)、requestBody($ref/allOfをcomponentsに対して解決し、bodySchema ツリー + サンプルに展開)、responses(ステータスコード + スキーマサンプル)を解析 → 定義specに書き込みます。 - 各新しいインターフェースに対してデフォルトケース(ステータスコード + 基本的なビジネスアサーション)を生成します。
- 冪等です:既存のプロジェクト+メソッド+パスは、スペックのみが上書きされます(ユーザー編集済みケースは保持)。
{created, updated, skipped}を返します。
コード:crates/api-definition/src/domain/import.rs、application/import_api_definitions.rs、domain/api_definition.rs(with_spec)。
終了コード
0 すべてグリーン。1 一部のステップが失敗。2 ブートストラップフロー自体がエラー。