feat: 別ホストの Docker に dev コンテナを立ち上げ、VS Code もそこへ接続する (PLAN52) - #164
Conversation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
- --context を lifecycle サブコマンドと env exec に追加 - _dispatch_lifecycle の前後で接続先を reset、切替後に機密を読み直してから解決 - up / scale は接続先を確定して DOCKER_CONTEXT / DOCKER_GID を反映、リモート扱いでは自動スナップショットを飛ばす - _inject_secrets の後に再適用、_run_build は --context を引数で渡す Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
…ask 4) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
… env exec 経由にする (PLAN52 Task 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
…る (PLAN52 Task 6) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
Add characterization tests for untracked child environments, explicit open-index boundaries, and remote settings propagation in cmd_scale. Item-Id: R1-001 Round: 1 Impl-Runtime: codex Impl-Model: default
改修計画 — devbasex/devbase #164
ラウンド 1(実装 codex / レビュー agy / kiro)R1-001 —
|
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| branch | unit | — | codex / agy | 採用 | 1 |
なぜ: 既存テストは通常の apply/reapply/reset と、追跡中の対象がない状態での env exec を固定している。追跡中の対象がある状態で別の辞書へ track=False を適用し、その後 reapply/reset する経路は未固定。実行では子辞書だけに別 context/GID が適用され、親の追跡対象と最初の復元値が保持された。
手順: 1. DOCKER_CONTEXT・DOCKER_HOST・DOCKER_GID に初期値を持つ親辞書と、異なる値を持つ子辞書を用意する。
2. 親辞書へリモート DockerTarget A を通常適用し、子辞書へ別のリモート DockerTarget B を track=False で適用する。
3. 子辞書の context/GID が B の値となり DOCKER_HOST が除去され、無関係なキーが保持されることを固定する。
4. 親辞書の保護対象キーを別値で上書きして reapply し、A の context/GID と DOCKER_HOST 除去が復元されることを固定する。
5. reset 後の親辞書が最初の値に戻り、子辞書は手順3の状態を保つことを固定する。状態の後始末にも公開 reset を使い、private な状態や呼び出し回数は検証しない。
R1-002 — lib/devbase/utils/docker_context.py#ensure_remote_gid
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| error | unit | — | codex / agy | 採用 | 1 |
なぜ: 既存の test_gid_probe_failure_raises_with_stderr_and_hint と test_gid_probe_non_integer_raises は非ゼロ終了と整数でない出力を固定しているが、runner 自体が FileNotFoundError / TimeoutExpired を送出する経路は固定していない。公開入口の実行ではどちらも DevbaseError となり、context 名と docker.gid の案内を含み、キャッシュを作成しなかった。
手順: 1. gid 未指定の DockerTarget と空の一時キャッシュディレクトリを用意する。
2. FileNotFoundError または subprocess.TimeoutExpired を送出する runner をパラメータ化して ensure_remote_gid へ渡す。
3. 実測した DevbaseError 型と、メッセージに対象 context 名・docker.gid が含まれることを固定する。文言全体は比較しない。
4. 対象 context のキャッシュファイルが作成されていないことを確認する。内部関数は直接呼ばない。
R1-003 — lib/devbase/commands/container.py#_resolve_open_index
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| boundary | unit | — | kiro | 採用 | 1 |
なぜ: 1<=open_index<=scale の範囲外 (0・scale 超過) を 1 へ倒す条件式は、範囲チェックの書き換えで壊れやすいが、この経路を固定したテストが無い (dispatch テストは引数伝播だけを見ており clamp を通っていない)。
手順: 1. open_index を明示指定して呼ぶ (env フォールバックを経由させない)
2. 0・scale (境界)・scale+1 (上限超過) を渡し、戻り値がそれぞれ 1・scale・1 になることを比較する
3. 検証は戻り値のみ (警告文言には結合しない)
R1-004 — lib/devbase/commands/container.py#_resolve_open_index
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| branch | unit | — | kiro | 採用 | 1 |
なぜ: open_index=None のとき env DEVBASE_OPEN_INDEX を int 変換し、非整数値を ValueError で握って 1 へ倒す分岐が固定されていない。env パースの書き換えで既定値の決まり方が変わっても検出できない。
手順: 1. monkeypatch で DEVBASE_OPEN_INDEX を未設定・整数文字列・非整数文字列に設定する
2. open_index=None・scale を十分大きくして呼ぶ
3. 未設定→1、'2'→2、'abc'→1 と戻り値を比較する (戻り値のみ検証)
R1-005 — lib/devbase/commands/container.py#cmd_scale
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| branch | unit | — | agy | 採用 | 1 |
なぜ: cmd_up や cmd_down などの各 lifecycle コマンドで context 伝播がテストされている一方、cmd_scale に追加された context 引数の解決・反映および構成生成へのリモート設定(docker_home, remote)伝播がテストされていない
手順: 1. project.local.yml にリモートの docker 設定(context, home, gid)を用意する
2. 外部呼び出しをモックした環境で cmd_scale を実行する
3. DOCKER_CONTEXT と DOCKER_GID が環境に反映され、構成生成処理に docker_home と remote=True が渡ることを検証する
ラウンド 2(実装 agy / レビュー codex / kiro)
R2-001 — lib/devbase/volume/compose.py#generate_scaled_compose
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| long_method | extract_method | major | codex / agy / kiro | 採用 | 1 |
なぜ: 構成の読込、機密・認証環境の整備、サービス生成、bind mount の変換・警告、YAML 保存を1関数が担っている。特に末尾のリモート mount 処理は scaled_services・docker_home・remote だけに依存する独立した段階であり、構成生成の進行と詳細な警告方針が混在している。tests/volume/test_compose_remote_home.py が公開入口からローカルの保持、HOME 指定時の変換と相対パス警告、HOME 未指定時の保持と警告を検証している。
手順: 1. generate_scaled_compose 内の if docker_home / elif remote と両方の警告処理を、同じ compose.py の _prepare_remote_mounts(services, docker_home, remote) -> None にそのまま抽出する。
2. dev_excluded の除去後、scaled_config の組立て前という現在の位置を維持し、抽出関数への1回の呼び出しに置き換える。bind_mounts.expand_home 自体は変更しない。
3. docker_home の真偽判定が remote より優先すること、サービスの破壊的更新、警告対象の順序、文言とログレベルを維持する。新たな検証や条件変更は加えない。
4. tests/volume/test_compose_remote_home.py と tests/volume/test_bind_mounts.py、および tests/volume の既存生成テストを実行し、その後 uv run pytest -q を実行する。見積り65行はコメントを含む本体の移動、関数定義、説明、呼び出しと引数受け渡しを含む。
R2-002 — lib/devbase/utils/docker_context.py#ensure_remote_gid
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| long_method | extract_method | major | codex / agy | 採用 | 1 |
なぜ: 明示 GID・キャッシュの優先順位と永続化を管理する処理に、Docker 用環境の構築、subprocess 実行、失敗の例外変換、標準出力の整数化、GID 0 の警告が同居している。キャッシュ方針を追う際にもプローブの実装詳細を読む必要がある。tests/utils/test_docker_context.py には明示値、キャッシュ再利用・破損、非ゼロ終了、不正出力、実行例外、GID 0 の各経路を ensure_remote_gid 経由で確認するテストがある。
手順: 1. Docker 用環境のコピーから整数化と GID 0 の警告までを、同じモジュールの _probe_remote_gid(target, environ, runner) -> int に抽出する。
2. ensure_remote_gid には明示値とキャッシュによる早期 return、プローブ呼び出し、キャッシュの保存、保存後のログだけを残す。既存の _read_cached_gid と _gid_failure_message を再利用する。
3. コマンド引数、タイムアウト、DOCKER_HOST の除去、例外の型・文言・cause、警告とキャッシュ保存の順序をそのまま保つ。公開シグネチャと runner の注入口は変えない。
4. tests/utils/test_docker_context.py と tests/commands/test_container_context.py を実行し、その後 uv run pytest -q を実行する。見積り85行は本体の移動による追加・削除、抽出関数の定義・説明、呼び出しと引数受け渡しを含む。
R2-003 — lib/devbase/editor/opener.py#open_editor
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| long_method | extract_method | major | kiro | 採用 | 1 |
なぜ: IPC ソケットの拾い直しとログ・stale 警告・editor/display 解決・decide_action・skip 早期 return・container 名解決・ssh_host と docker_context の解決・workspace/uri_flag/uri 組み立て・直接 attach 案内・print_command/launch 分岐を 1 関数で行う。URI 構築と起動判定という別関心が混在する。
手順: 1. ssh_host + docker_context + workspace + uri_flag + uri の組み立てを _build_open_uri(ctx, env, container, workdir, workspace, docker_context) -> (uri, uri_flag, display, ...) へ抽出
2. IPC ソケット拾い直しと 2 種の警告ログを _prepare_ipc_env(env) -> (env, ctx) へ抽出
3. open_editor は「ctx 準備 → plan 判定 → skip 早期 return → uri 構築 → print/launch 分岐」に縮める
4. tests/editor/test_opener.py で launch/print_command/skip とネスト URI を退行確認
R2-004 — lib/devbase/commands/container.py#cmd_up
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| long_method | extract_method | major | kiro | 採用 | 1 |
なぜ: 1 関数が context 確定・env/hook/image の事前確認・snapshot・volume/network 準備・compose 生成と既存停止・起動・ready 待ち・不足 repo 報告・deploy スクリプト・window title・editor 起動と、6 段以上の異なる関心を通しで持つ。段ごとにテストできず、失敗経路 (DevbaseError / CalledProcessError) が末尾に集約されている。
手順: 1. [1/6]〜[5/6] の try 本体 (volume/network/compose 生成/down/up/wait) を _run_deploy_pipeline(project_name, scale, config, target, dev_service_name) として抽出
2. 事前確認 3 つ (_ensure_env_files/_run_pre_up_hook/_ensure_images) の並びを _run_pre_up_checks(config) -> bool へ抽出
3. cmd_up は「context 確定 → 事前確認 → snapshot → pipeline → 後処理 (report/deploy/title/editor)」の呼び出し列に縮める
4. 既存 tests/commands/test_container_up_order.py で段の順序と早期 return を確認
R2-005 — lib/devbase/commands/container.py#_choose_context
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| duplication | consolidate_duplication | minor | agy | 採用 | 1 |
なぜ: cmd_down, cmd_login, cmd_build, cmd_rebuild, _compose_run の各所で docker_context.apply(_choose_context(context)) という同一の呼び出しが重複している。また _resolve_docker_target 内でも _choose_context を使わずに同等の設定取得処理が重複記述されている。
手順: 1. _resolve_docker_target 内の choice 取得を _choose_context(cli_context) の呼び出しに統一する。
2. docker_context.apply(_choose_context(context)) を集約する _apply_context(context=None) ヘルパーを定義する。
3. cmd_down, cmd_login, cmd_build, cmd_rebuild, _compose_run 内の重複呼び出しを _apply_context(context) に置き換える。
4. tests/commands/test_container_context.py を実行して確認する。
ラウンド 3(実装 kiro / レビュー codex / agy)
R3-001 — lib/devbase/volume/compose.py#generate_scaled_compose
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| long_method | extract_method | major | agy / kiro | 取り消し | 1 |
なぜ: ラウンド2でリモートマウント処理 (_prepare_remote_mounts) が抽出されたものの、generate_scaled_compose は依然として150行超あり、複数の責務・フェーズが1つの関数に同居している。具体的には、(1) GCP認証関連の除外変数名の算出と _SecretNames の構築、(2) VS Code Server用ボリュームの決定 (_declares_target 判定とボリューム名解決)、(3) dev インスタンスごとの _drop_env_names 適用ループ、(4) サービス構築と設定ファイル出力、が直列に記述されている。各フェーズはインラインコメントで明確に区切られており、それぞれ小さなプライベート関数に抽出可能である。既存テスト (tests/volume/test_compose_secret_env.py, tests/volume/test_compose_gcp_auth.py, tests/volume/test_compose_vscode.py) により公開挙動が十分に保護されている。
手順: 1. GCP 除外集合と _SecretNames の構築 (auth_mode の取り出し・enumerated の収集・gcp_auth.dev_excluded_env_names・_SecretNames 生成) を _build_secret_names(dev_service, dev_environment, secret_env_names, global_env_names, project_env_names) -> tuple[_SecretNames, set] へ抽出
2. vscode volume の決定 (_declares_target 判定と get_vscode_volume_for 内包) を _resolve_vscode_volumes(dev_service, scale) -> list へ抽出
3. dev インスタンスの _drop_env_names ループを _drop_dev_excluded(scaled_services, dev_service_name, scale, dev_excluded) へ抽出
4. generate_scaled_compose を「読込 → dev/受信者/グループ解決 → _build_secret_names → _resolve_vscode_volumes → _build_scaled_services → _drop_dev_excluded → prepare_remote_mounts → assemble/write」の呼び出し列へ縮める
5. tests/volume/test_compose*.py 群で退行確認
R3-002 — bin/devbase#cmd_build
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| duplication | consolidate_duplication | major | codex / agy | 取り消し | 1 |
なぜ: bin/devbase の cmd_build 関数内において、通常ビルド (236-245行)、--no-cache 指定時 (203-212行)、--project-no-cache 指定時 (181-190行) の3つの実行経路で、compose_with_secrets docker compose build "${DEV_SERVICE_NAME:-dev}" の実行、成功・失敗メッセージの出力、および失敗時の exit 1 処理がほぼ完全に重複している。プロジェクトビルドの実行ロジックや成否判定の変更時に3箇所を同期して修正する必要があり、修正漏れのリスクがある。なお、既存の tests/cli/test_wrapper_secrets.py はスクリプト内の特定コマンド記述箇所数を固定しており、ハーネス側で cmd_build を差し替えるテストもあるため、重複集約にあたってはテスト側での呼び出し契約の確認と追従が必要となる。
手順: 1. tests/cli に実物の bin/devbase を一時ルートへ複製して実行する現状固定テストを先に追加する。PATH 上の uv を記録用スタブにして外部実行境界で引数を観測し、cmd_build と compose_with_secrets は実物を通す。通常・--no-cache・--project-no-cache(両フラグ併用を含む)について、base→project の順序、--context の伝達、引数の順序と重複、成功表示、base 失敗時の打ち切り、project 失敗時の表示と終了値1を固定する。
2. 同じ bin/devbase 内に build_project_image を抽出する。既存の compose_with_secrets docker compose build と結果表示、失敗時 exit 1 をそのまま移し、追加のビルド引数は "$@" で受け取る。モード別の進捗表示とbase側の判断・引数加工は各呼び出し元に残す。
3. 3箇所を共通関数呼び出しへ置き換える。project-no-cache 経路は現状どおり --no-cache を先頭へ追加し、それ以外の引数と既存の return/exit の位置・意味を保つ。
4. test_wrapper_secrets.py の3箇所固定と test_base_image_staleness.py の具体的コマンド文字列固定を、手順1の実行結果検査へ置き換える。機密注入経由という契約とモードごとの挙動は維持する。
5. 対象CLIテスト、bash -n bin/devbase、uv run pytest -q を実行する。事前実行の snapshot 復元テスト1件の失敗は別記し、構造変更の退行と区別する。見積220行は、本体の削除・抽出・3呼び出し元の書換え約60行、現状固定ハーネス/テスト追加と既存テスト変更約160行の合計。
R3-003 — lib/devbase/volume/compose.py#_mask_secret_environment
| 兆候・経路 | 手法・階層 | 重要度 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|
| duplication | consolidate_duplication | minor | agy / kiro | 検証中 | 1 |
なぜ: lib/devbase/volume/compose.py 内の _mask_secret_environment (194-250行), _service_env_names (253-267行), _drop_env_names (269-305行), _apply_dev_environment (370-398行) の4関数において、Compose の service['environment'] の表現形式 (辞書形式 / KEY=VALUE のリスト形式 / その他) を判定し走査するロジックが重複している。特にリスト形式の各要素からキー名を取り出す処理 (item.split('=', 1)[0].strip()) は複数箇所に散在しており、_apply_dev_environment では .strip() が適用されていないなど微小な実装の乖離も発生している。環境変数定義の走査・キー抽出ロジックを一元化することで、Compose 仕様変更時の保守性を高め、解釈のブレを解消できる。既存の tests/volume/test_compose_dev_environment.py や tests/volume/test_compose_secret_env.py で各形式の挙動が網羅されている。
手順: 1. environment のキー名を列挙する走査を _iter_env_names(existing) へ 1 本化し、_service_env_names をその薄いラッパにする (item.split('=', 1)[0].strip() に統一)
2. dict / list / その他を判定して形態を返す小さな分類ヘルパ (_env_shape など) を導入し、_mask_secret_environment・_drop_env_names・apply_dev_environment の分岐頭をそれで揃える (各関数の書き込み方針・警告文言・戻り値は現状のまま)
3. 各関数を 1 手ずつ置き換え、その都度 tests/volume/test_compose*.py を実行して退行が無いことを確認
4. list 形態のキー抽出の .strip() 有無の差は現状の _drop_env_names 側 (.strip() あり) に寄せ、変化を固定テストで確認
見送った項目
| ラウンド | 対象 | 兆候・経路 | 理由 |
|---|---|---|---|
| 1 | lib/devbase/editor/opener.py#resolve_docker_context |
branch | 1 ラウンドの採用上限 5 件を超えた |
| 1 | lib/devbase/project/local_config.py#load_project_local_config |
error | 1 ラウンドの採用上限 5 件を超えた |
| 1 | lib/devbase/volume/bind_mounts.py#expand_home |
branch | 1 ラウンドの採用上限 5 件を超えた |
| 2 | lib/devbase/volume/bind_mounts.py#collect_remote_warnings |
duplication | 1 ラウンドの採用上限 5 件を超えた |
| 2 | lib/devbase/commands/container.py#_ensure_images |
long_method | 1 ラウンドの採用上限 5 件を超えた |
| 2 | lib/devbase/commands/env.py#_update_source_metadata |
long_method | 1 ラウンドの採用上限 5 件を超えた |
| 3 | lib/devbase/volume/compose.py#generate_scaled_compose |
long_method | テストの期待する振る舞いが変わっています(tests/cli/test_base_image_staleness.py, tests/cli/test_wrapper_secrets.py)。構造改善では期待出力を変えません。振る舞いの変更は別の変更に分けてください |
| 3 | bin/devbase#cmd_build |
duplication | テストの期待する振る舞いが変わっています(tests/cli/test_base_image_staleness.py, tests/cli/test_wrapper_secrets.py)。構造改善では期待出力を変えません。振る舞いの変更は別の変更に分けてください |
…ndex fallback Add characterization tests for ensure_remote_gid runner exceptions and _resolve_open_index DEVBASE_OPEN_INDEX fallback. Item-Id: R1-002 Round: 1 Impl-Runtime: agy Impl-Model: default
振る舞いを変えずに 4 つの long_method から段階を抽出した。 - lib/devbase/volume/compose.py#generate_scaled_compose: リモート mount の展開・警告を _prepare_remote_mounts へ抽出 - lib/devbase/utils/docker_context.py#ensure_remote_gid: Docker 実行・例外変換・整数化・GID 0 警告を _probe_remote_gid へ抽出 - lib/devbase/editor/opener.py#open_editor: IPC ソケット準備を _prepare_ipc_env、URI 組立てを _build_open_uri へ抽出 - lib/devbase/commands/container.py#cmd_up: 起動前チェックを _run_pre_up_checks、[1/6]〜[5/6] を _run_deploy_pipeline へ抽出 Item-Id: R2-001 Round: 2 Impl-Runtime: kiro Impl-Model: default
…#_choose_context docker_context.apply(_choose_context(context)) が cmd_down / cmd_login / cmd_build / cmd_rebuild / _compose_run に同じ形で 5 回並んでいたのを _apply_context(context) ヘルパーへ集約する。_resolve_docker_target で _choose_context を使わず同じ設定取得 + choose_context を書き直していた箇所も _choose_context(cli_context) の呼び出しへ統一する (resolve_target が settings を要るため、ローカル設定の読み込みはそこに残る)。振る舞いは変えない。 Item-Id: R2-005 Round: 2 Impl-Runtime: claude Impl-Model: default Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Extract secret-name preparation, VS Code volume resolution, and dev environment exclusions from generate_scaled_compose (R3-001). Consolidate project build execution and result handling, protected by real-wrapper characterization tests for build modes, context forwarding, argument order, and failures (R3-002). Item-Id: R3-001 Round: 3 Impl-Runtime: codex Impl-Model: default
This reverts commit ff50d5b.
…sk_secret_environment Compose の service['environment'] の走査およびキー抽出処理を一元化。 - _env_shape による environment 形式判定の統一 - _env_item_name による list 項目からのキー抽出 (.strip() 適用) の一元化 - _iter_env_names による環境変数名列挙の一元化と _service_env_names の薄いラッパ化 - _mask_secret_environment, _drop_env_names, _apply_dev_environment の分岐統一 Item-Id: R3-003 Round: 3 Impl-Runtime: agy Impl-Model: default
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | kiro | APPROVE
リモート docker context の解決・反映(DOCKER_CONTEXT 経由)・gid 取得・bind mount の ~ 展開・エディタ attach への伝播まで、責務分割と特性化テストが揃っている。env exec --context の引数展開(空文脈で -- のみ、文脈名の空白は _parse_context で拒否)、リモート扱いでの自動スナップショット抑止、機密注入後の reapply による接続先の再適用(決定 13)も検証できた。設計・正確性・セキュリティ(外部コマンドへの文脈伝播、秘密のログ非出力)の観点で新たに修正を要する actionable な指摘は見当たらない。長メソッド/重複の構造的項目は既存の改修計画コメント(rf164)で追跡済みのため重複指摘しない。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | agy | REQUEST_CHANGES
PLAN52(リモート Docker context 対応)の全体的な実装およびテストともに非常に高い完成度ですが、opener.py におけるコンテキスト解決の重複実装・環境変数漏れ、および bin/devbase の空文字 context バリデーションについて改善を提案します。
…の空値を拒む) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | kiro | APPROVE
context 解決 (choose→resolve→apply/reapply/reset) の状態管理、DOCKER_HOST 除去とリモート判定、bind mount の ~ 展開、gid の取得・キャッシュ・失敗変換、env exec --context の子プロセス反映まで一貫しており、TUI での操作間リセットや機密注入後の再適用も含めて経路ごとにテストで固定されている。関連テスト (docker_context / bind_mounts / container_context / env_exec_context / opener) はローカルで 175 passed。構造面 (generate_scaled_compose / cmd_up などの長関数・重複) は既存の改修計画コメントで追跡済みのため重複指摘はしない。修正を要する正確性・セキュリティ・設計上の問題は見つからなかった。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | codex | REQUEST_CHANGES
修正が必要な指摘は 2 件です。
…urce を警告) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 3 | codex | REQUEST_CHANGES
仕様適合: 接続先の伝達に関する修正が 2 件あります。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 3 | agy | APPROVE
前ラウンドまでの指摘(エディタ推測の context 一致、長い書式 bind の相対パス警告、空 context の拒否、接続先確定の最適化)が適切に反映され、全テストの通過を確認しました。修正アクションを要する指摘事項はありません。
…l をプロジェクト直下から読む) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 4 | kiro | REQUEST_CHANGES
uv run pytest -q を worktree で実行すると 3 failed / 1917 passed(PR 記載の「1900 passed」と不一致 = 現状 CI は red)。原因はコード側ではなく、新規テストの状態リーク(順序依存)です。個別実行では全 pass するため見落としやすい。
修正提案(インライン参照):
tests/commands/test_container_context.py:test_dispatch_clears_source_secrets_before_loading_target_envがDEVBASE_DOCKER_CONTEXTを実os.environへ残したまま終了し、tests/commands/test_container_up_order.pyの 2 件とtests/commands/test_env_exec_context.py::test_env_exec_does_not_keep_module_stateを巻き込みます。monkeypatch.setenv化 + autouse_clean_envの teardown で当該 env を掃除してください。tests/commands/test_container_up_order.py:up_harnessにDOCKER_CONTEXT/DEVBASE_DOCKER_CONTEXTの delenv とdocker_context.reset()を足すと順序非依存になり、漏れの二重防御になります。
再現: uv run pytest -q -p no:randomly tests/commands/test_container_context.py tests/commands/test_container_up_order.py → 2 failed。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 5 | codex | APPROVE
新規の修正指摘はありません。関連テスト 343 件と bash -n が成功しました(実機接続は未検証)。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 5 | kiro | APPROVE
ラウンド 1〜2 と R3-003 のリファクタリングは適用済みで、対象テスト 348 件が通過。R3-001 / R3-002 は「振る舞い変更を含む」として意図的に取り消し済み(別変更へ分離する判断で妥当)。新設モジュール(local_config.py / docker_context.py / bind_mounts.py)は責務が単一で検証・文書化も十分。bin/devbase の --context 抜き取りは空白・空値・スペース入り context 名を含めて期待どおり展開されることを確認。env exec の context 解決経路も設計コメントどおりで、bind mount の ~ 展開(短/長形式・:ro・named volume・~user・相対パス)と apply/reset の二重適用順序に不整合なし。修正を要する正確性・セキュリティ・保守性の問題は検出せず。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X
リリース後テスト対象の版: v3.3.0(2026-09-13 16:50 タグ、GitHub Release あり)
合否: 合格(10 件中 7 件を実施、3 件は保留。保留 3 件は実機の別ホスト構成が要る) |
Pull Request
概要
projects/<name>/project.local.yml(gitignore 対象の個人・機材ごとの設定)にdocker.context/docker.home/docker.gidを書くと、devbase up/down/ps/logs/login/scale/build/rebuildがその docker context の daemon を相手に動き、devbase upが開く VS Code がそのホストのコンテナへ attach します。設計は #163(マージ済み)、確定仕様はdocs/specifications/remote-docker-context.mdにあります。関連 Issue
変更点
project/local_config.py(新設):project.local.ymlの読み込みと検証。project.ymlのdocker:は移す案内付きで拒むutils/docker_context.py(新設): context の解決(CLI > env > ファイル > 未指定)、docker context showとの比較によるリモート判定(DOCKER_CONTEXT/DOCKER_HOSTを外した環境で問い合わせ)、DOCKER_CONTEXT/DOCKER_GIDの反映(冪等・機密注入後に再適用・操作前後で reset)、DOCKER_HOSTの除去、gid の自動取得と.cache/docker-gid/<context>への控えcommands/container.py:--contextを全 lifecycle コマンドへ。up/scaleは接続先を確定し、リモート扱いでは自動スナップショットを飛ばす。プロジェクト切替時は切替元の機密を落としてから切替先の env を読む。_run_buildは--contextを引数で渡すvolume/bind_mounts.py(新設)+compose.py: リモート扱いの生成で bind mount の~をdocker.homeで展開し、書き換えられない mount(~user・相対パス・長い書式の素の相対 source)を警告bin/devbase:build --context NAMEを先頭で抜き取り(空値は exit 2)、env exec --context NAMEへ引数で渡す。docker buildx build/docker image inspectもenv exec経由にcommands/env.py+cli.py:env exec --context(プロジェクト直下のproject.local.ymlを読む)editor/opener.py: 解決した context をsettings.contextに載せ、Remote-SSH ではフラット URI も提示。推測は docker が実際に使う context に合わせるcmd_up/open_editor/generate_scaled_compose/ensure_remote_gidの抽出、環境変数の形の判定の共通化)と現状固定テスト 5 件。改修計画: feat: 別ホストの Docker に dev コンテナを立ち上げ、VS Code もそこへ接続する (PLAN52) #164 (comment)project-yml.md(project.local.ymlの節)、environment-variables.md(「リモート Docker」)、CLI リファレンス、CHANGELOG、確定仕様docs/specifications/remote-docker-context.md。PLAN52 はissues/old/へ動作確認
検証結果
uv run pytest -q <PLAN52 の新規・変更テスト 8 ファイル>uv run pytest -quvx ruff check --select=E9,F63,F7,F82 liblibuvx --from shellcheck-py shellcheck --severity=error bin/devbasebin/devbasepython3 -m compileall -q lib binlibbindevbase ps --context desktop-linux/--context nope/env exec --context desktop-linux -- sh -c 'echo $DOCKER_CONTEXT'CTX=desktop-linuxカバレッジツールの設定は無いため測定していない。
受け入れ条件: 49 件のうち 46 件をテストで確認(対応は
docs/specifications/remote-docker-context.mdの「テスト観点」)。未検証の項目(リリース後テストで行う): 実 daemon での buildx リモートビルド、ローカル VS Code の
settings.contextでの attach、Remote-SSH + リモート context のネスト URI。既存の失敗: なし。
範囲外と判断したもの: devbase-samples の
.gitignoreにproject.local.ymlを足す → devbasex/devbase-samples#7 に起票。./bin/devbase --helpが正常に動作するdocs/,CHANGELOG.md) を更新した補足
docker.home/docker.gidは CLI / env でファイルと別の context へ向けたときは使いませんdevbase statusの複数 daemon 集約、DOCKER_HOST直接指定は対象外🤖 Generated with Claude Code
https://claude.ai/code/session_01MpE7aJufCtCacsm1Z3o83X