Skip to content

fix: devbase のプロジェクト名解決が projects/ の外へ出られる #146

Description

@takemi-ohama

何を見つけたか

bin/devbase の maybe_cd_project() は、name 候補を $DEVBASE_ROOT/projects/<name> へそのまま連結してディレクトリの存在を見ます。弾いているのは - 始まりと空文字だけで、.. を含む値がそのまま通ります。

maybe_cd_project() {
    local name="${1:-}"
    case "$name" in -*|"") return 1 ;; esac   # フラグ・空は name ではない
    local target="${DEVBASE_ROOT}/projects/${name}"
    [ -d "$target" ] || return 1
    cd "$target" || return 1

$DEVBASE_ROOT/projects/../etc は $DEVBASE_ROOT/etc に解決され、実在するため cd されます。v3.1.0 の実機で確認しました。

$ devbase build ../etc
=== Building devbase images ===
[1/2] devbase-base already exists (use --no-cache to rebuild)

[2/2] Building project image...
no configuration file provided: not found

✗ Failed to build project image

$DEVBASE_ROOT/etc へ移動して compose ビルドを試み、compose.yml が無いため落ちています。引数は name として消費されるため、下流の Python には届きません。

cd の直後に対象ディレクトリの env を source します(maybe_cd_project 内、現プロセスで source)。projects/ の外にある env という名前のファイルも、この経路で読まれます。

どこで見つけたか

bin/devbase の maybe_cd_project()(320-351 行、v3.3.0 + #171 時点)。#139 の修正で _build_single_image に image 名の検証([A-Za-z0-9][A-Za-z0-9._-]*)を入れた後、v3.1.0 のリリース後テストで devbase build ../etc を実行して気づきました。Python 側の検証は name 解決より後段にあるため、この経路には効きません。

なぜこの変更の範囲外なのか

#139 の受け入れ条件は devbase build <image> が正しい docker コマンドを組み立てることで、name 解決の仕組みは対象外です(issues/old/PLAN49_build-image-argument.md の前提 2 と「対象範囲(含まない)」)。この挙動は #139 の修正より前から同じで、今回の変更が持ち込んだものではありません。

直さないと何が起きるか

影響は build だけではありません。name 解決を通るのは次のすべてです。

  • トップレベルショートカット: up / down / ps / scale / login / build / rebuild
  • project <sub> <name> / container <sub> <name> の up / down / ps / logs / scale / rebuild

いずれも .. を含む値で projects/ の外のディレクトリを対象にできます。打ち間違い(devbase up ../foo)や、name を組み立てて渡すスクリプトが、意図しないディレクトリで compose 操作を行い、そこの env を読みます。

権限の境界を越えるものではありません(利用者が自分の devbase に自分で引数を渡しているだけです)。ただし「projects/<name> の 1 つを指す」という前提が破れており、下流の Python 側だけを検証しても塞げない位置にあります。

対処の候補:

  • maybe_cd_project の入口で、name を 1 セグメントに限定する(/ \ .. . を弾く)。_build_single_image に入れたのと同じ形の許可リストが使えます
  • あわせて _resolve_project_name(lib/devbase/commands/container.py)も同じ検証を持つ。Python 側の chdir フォールバックも同じ連結を行うため
  • cli._named_lifecycle_project(lib/devbase/cli.py)も同じ検証を持つ。グループ別の置き場(backend.yml の version: 2)で、名前を指定したライフサイクル操作の dispatch 前の注入先を (root / 'projects' / name).is_dir() で決め、groups.declared_group(root, name) が projects/<name>/env を読む。.. を含む名前では projects/ の外の env を読んだ後に、SecretRef.for_project の検証(プロジェクト名にパス区切りは使えません)で注入が止まる

由来

issue #139

進行

モード: standard / 作業ツリー: .worktrees/fix/plan61-name-resolution / 計画: issues/PLAN61_name-resolution.md

  • 要求と受け入れ条件 — 2026-09-18 20:34
  • 作業場所の用意 — 2026-09-18 20:37
  • 設計 — 2026-09-18 20:38
  • 素材の収集と出典の確定
  • ドキュメント再構成 — 2026-09-18 20:50
  • ドキュメントレビュー — 2026-09-18 20:50
  • 計画 — 2026-09-19 09:11
  • 実装 — 2026-09-19 09:39
  • 構造改善 — 2026-09-19 10:13
  • 実装レビュー — 2026-09-19 10:50
  • 完了判定 — 2026-09-19 10:57
  • Pull Request — 2026-09-19 09:39
  • 確定仕様化 — 2026-09-19 11:13
  • 後片付け
  • 配布 — 2026-09-19 13:36
  • 体裁レビュー
  • リリース後テスト — 2026-09-19 13:38
  • 振り返り — 2026-09-19 13:39

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions