Skip to content

feat(PLAN62): 機密の置き場に書いた DEVBASE_ACCOUNT_GROUP を注入しない (#185) - #206

Merged
takemi-ohama merged 8 commits into
mainfrom
fix/plan62-inject-account-group
Sep 19, 2026
Merged

takemi-ohama merged 8 commits into
mainfrom
fix/plan62-inject-account-group

Conversation

@takemi-ohama

Copy link
Copy Markdown
Contributor

Summary

機密の置き場(.env / age / OpenBao)に書いた DEVBASE_ACCOUNT_GROUP を機密の合成(runtime.resolve)から外し、プロセスの環境変数・子プロセス・コンテナの列挙のどれにも載せない。version: 1 でも外す。

  • 置き場に値があれば、置き場の種類と消し方(devbase env delete DEVBASE_ACCOUNT_GROUP [-p] [--user] [--group])を添えて 1 プロセスに 1 回警告する(値は出さない)
  • devbase env set DEVBASE_ACCOUNT_GROUP=... は置き場を開く前に拒否し、env ファイルへ書くよう案内する(終了コード 1)
  • 利用者向け文書(environment-variables / env-backend / cli-reference 03-env)と CHANGELOG を新しい挙動に合わせる

要求と受け入れ条件: issues/PLAN62_inject-account-group.md(9 件、検証手段つき)/ 設計: issues/PLAN62_inject-account-group-design.md(#205 でマージ済み)

Closes #185

Test plan

  • uv run --locked pytest -q tests/ → 2717 passed、exit=0
  • uvx ruff check --select=E9,F63,F7,F82 lib → exit=0
  • cross-refactoring → cross-review → quality-gates(この PR で実施)
  • リリース後テスト: 検証用のプロジェクトで置き場に値を入れ、devbase ps で警告が出ること、devbase env set が拒否することを実機で見る

🤖 Generated with Claude Code

takemi-ohama and others added 5 commits September 19, 2026 09:22
)

runtime.resolve が 4 つの置き場から読んだ直後にキーを除くため、inject / child_env /
コンテナへ列挙する変数名のどれにも置き場の値が載らない。version: 1 でも外す。
外した置き場は SecretRef を鍵にしたモジュールの集合で控え、release_store をまたいでも
警告は 1 プロセスで 1 回にする。警告には置き場の種類と env delete の引数を添え、値は出さない。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
置き場の値はアカウントグループの決定に使われないため、書いても使われない値を新たに
作らない。_open_target_env より前に返すので、書き込み・ファイルの作成・fresh の読み出し・
--group の検査のどれも起きず、どの宛先でも終了コード 1 で env ファイルへ書くよう案内する。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…書く (#185)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Preserve secret values and origins when project env reading raises PermissionError.

Item-Id: R1-001
Round: 1
Impl-Runtime: codex
Impl-Model: default
@takemi-ohama

takemi-ohama commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor Author

改修計画 — devbasex/devbase #206

/ndf:cross-refactoring が提案し、適用した改善項目の記録である。
理由と手順は提案の時点でしか残らないため、公開の直前に書き出している。

  • 対象範囲: lib/devbase/env/runtime.py, lib/devbase/commands/env.py, tests/env/test_runtime.py, tests/commands/test_env_account_group.py, tests/commands/test_container_up_order.py
  • 着手前のテスト: uv run --locked pytest -q tests/

ラウンド 1(実装 codex / レビュー agy / kiro)

R1-001 — lib/devbase/env/runtime.py#resolve

兆候・経路 手法・階層 重要度 提案元 状態 コミット
error unit — codex / kiro 採用 1

なぜ: _project_env_overrides の OSError 分岐 (projects//env を read_bytes できないとき警告を出して {} を返し、上書きを無視する) が固定されていない。隣の UnicodeDecodeError 分岐は test_invalid_utf8_project_env_preserves_secret_values_and_origins で固定済みだが、読み取り不能の分岐は resolve のどの経路でも固定されていない

手順: 1. 共通機密に TOKEN=secret、プロジェクト機密に PROJECT_ONLY=p を返すストアの疑似実装を用意し、環境変数には TOKEN=override を設定する。
2. projects/web/env がファイルとして存在すると判定され、そのパスの読み取りだけが PermissionError を送出するようファイルI/O境界をスタブ化する。OSの権限や実行ユーザーには依存させない。
3. 公開入口 resolve(root, "web", store=store) を実行して現在の結果を記録する。
4. 例外にならず values が TOKEN=secret と PROJECT_ONLY=p を保持し、global_names・project_names・names の集合も機密の由来に一致することを固定する。内部関数の直接呼び出しや表示文言の完全一致は使わない。

R1-002 — lib/devbase/env/runtime.py#inject

兆候・経路 手法・階層 重要度 提案元 状態 コミット
error unit — codex 検証中 1

なぜ: 既存テストは注入成功後の解除・再注入・マッピング間の分離を固定しているが、共通機密を取得した後にプロジェクト機密の取得が失敗する経路は固定していない。現状は例外を伝播し、注入対象と既存の復元履歴を変更しないため、合成と注入の構造改善時に部分的な注入を検出できるようにする。

手順: 1. 共通参照には TOKEN=new-secret を返し、プロジェクト参照で DevbaseError を送出するストアの疑似実装を用意する。内部関数は置き換えず store 引数で渡す。
2. 初回注入の場合と、別の正常なストアで TOKEN=old-secret を注入済みの場合をパラメータ化する。注入前の対象辞書には TOKEN=shell と無関係なキーを設定する。
3. 公開入口 inject(root, "web", environ=target, store=failing_store) を実行し、実測した例外型と対象辞書の不変を固定する。
4. 公開入口 clear_injected(target) を呼び、初回失敗なら空の解除結果、注入済みなら TOKEN の解除結果となり、いずれも TOKEN=shell と無関係なキーが残る現状を固定する。private な履歴にはアクセスしない。

見送った項目

(なし)

共通機密の取得後にプロジェクト機密の取得が失敗する経路の現状を固定する。
例外を伝播し、対象マッピングと既存の復元履歴を変更しないこと、初回失敗では
clear_injected が空、注入済みでは TOKEN を注入前へ戻すこと、いずれも
TOKEN=shell と無関係なキーが残ることを記録する。

Item-Id: R1-002
Round: 1
Impl-Runtime: kiro
Impl-Model: default

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 1 | kiro | APPROVE

置き場の DEVBASE_ACCOUNT_GROUP を読み取り直後の 1 か所 (_without_account_group) で外す設計は合成経路 (resolve → inject/child_env/列挙) を一元化できており、重ね順 3 の非破壊も names 基準の values 構成で保たれている。env set の事前拒否・警告のプロセス単位デデュープ・env delete ヒントの 3 軸対応、docs/CHANGELOG も実装と一致。受け入れ条件 1〜5 と警告・拒否がテストで固定され、対象 3 ファイルの 92 件が pass。修正を要する指摘なし。

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 1 | agy | APPROVE

PLAN62 の受け入れ条件(機密置き場からの除外・置き場ごとの重複抑止警告・env set の拒否・文書更新)および R1-001 / R1-002 の現状固定テストが要件通り実装され、テストが全て通過することを確認しました。

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 2 | kiro | APPROVE

読み取り境界(resolve 内の load)でキーを外す実装で、inject / child_env / コンテナ列挙の共通経路を 1 か所で押さえられており、重ね順 3(projects/<name>/env)も壊していない。env set 拒否と env delete 許可・警告の消し方ヒントが整合し、受け入れ条件 1〜9 と警告の重複抑止・空値・グループ付き参照まで 92 件のテストで固定されている。round1 の候補(読み取り不能な project env / プロジェクト機密取得失敗時の注入)も本 PR の新規テストで固定済み。修正提案なし。

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 2 | codex | REQUEST_CHANGES

追加テストの環境変数の復元について修正をお願いします(minor 1 件)。

Comment thread tests/env/test_runtime.py Outdated
PLAN62 で足したテストは environ を渡さずに runtime.inject() を呼ぶため、
機密 (TOKEN / K) が本物の os.environ へ載ったまま残り、後続テストとその
子プロセスへ漏れていた。_isolate_injection_state は注入履歴を差し替える
だけで、環境変数は戻さない。

account_group_root を yield 付きにし、注入履歴が monkeypatch の後始末で
戻るより前に runtime.clear_injected() を通す。autouse の
_isolate_injection_state が先に組み立てられるので、この fixture の後始末
はそれより先に走る。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@takemi-ohama

Copy link
Copy Markdown
Contributor Author

🔧 /ndf:fix サマリ (round 2)

対応件数: critical=0 / major=0 / minor=1 (合計 1 件)
deferred: 0 件 / rejected: 0 件
commit: df0b23a
CI: IN_PROGRESS(push 直後、完了待ちはしない)

詳細

  • tests/env/test_runtime.py:651 [minor / テストの独立性] 追加テストの runtime.inject() が os.environ へ載せた TOKEN / K を復元していない
    → account_group_root を yield 付き fixture にし、_isolate_injection_state が差し替えた注入履歴が monkeypatch の後始末で戻るより前に runtime.clear_injected() を通す。autouse の _isolate_injection_state が先に組み立てられる分、この fixture の後始末はそれより先に走る。

修正前はファイル末尾に残留検査を足すと TOKEN: 't' / K: 'v' が os.environ に残って落ちること、修正後は通ることを確認(検査そのものは恒久化せず、fixture の責務に寄せた)。
tests/commands/test_container_up_order.py の追加分は既に try/finally で runtime.clear_injected() を通しており、同じ残留は無し。

検証

  • uv run --locked pytest -q tests/ → 2720 passed in 106.28s、exit=0
  • uvx ruff check --select=E9,F63,F7,F82 lib tests → All checks passed!、exit=0
  • pr-body-decisions.sh sync 206 → exit=0(対象外: head が design/ で始まらない)

未解決スレッド残数: 0

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 3 | codex | APPROVE

新規の修正指摘はありません。関連テスト 137 件と git diff --check が通過しました。

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 3 | agy | APPROVE

PLAN62 の受け入れ条件・仕様変更・テスト(round 2 の account_group_root クリーンアップを含む)をすべて確認しました。指摘事項はありません。

@takemi-ohama

Copy link
Copy Markdown
Contributor Author

検証結果(quality-gates / standard)

段階 コマンド 対象範囲 実行時刻 結果
限定的な検証 uv run --locked pytest -q tests/env/test_runtime.py tests/commands/test_env_account_group.py tests/commands/test_container_up_order.py 変更した振る舞い 実装中(tdd-cycle の各サイクル) 各サイクルで失敗 → 実装 → 通過を確認
全体テスト uv run --locked pytest -q tests/ 全体 2026-09-19 10:41 2720 passed / exit=0
静的解析 uvx ruff check --select=E9,F63,F7,F82 lib lib 以下 2026-09-19 10:43 All checks passed! / exit=0
結合(CI) gh pr checks 206(head df0b23a) Pytest 3.10 / 3.13・syntax 3 版・ruff・shellcheck(Linux) 2026-09-19 10:43 すべて pass

構造改善: cross-refactoring(提案 3 件 → 採用 2 件、テスト整備ラウンドで現状固定テスト 2 件を追加、最終ゲートの全体テストを通過)
実装レビュー: cross-review approved(3 ラウンド、codex / agy / kiro が承認、未解決の指摘 0 件)

受け入れ条件(issues/PLAN62_inject-account-group.md): 9/9 満たす。条件ごとの検証手段は同ファイルのチェックリストに記載(テスト名つき)。

未検証の項目: 警告の見え方(CLI の標準エラーと TUI の画面で操作の出力に埋もれずに読めるか)→ リリース後テストで確かめる
既存の失敗: なし
範囲外と判断したもの:

@takemi-ohama

Copy link
Copy Markdown
Contributor Author

main を取り込み(CHANGELOG のコンフリクトは両方の項目を残す形で解消)、マージ後の状態で全体テストを回し直した: uv run --locked pytest -q tests/ → 2863 passed、exit=0(2026-09-19 11:23)。

@takemi-ohama
takemi-ohama merged commit 8a60e12 into main Sep 19, 2026
7 checks passed
@takemi-ohama takemi-ohama mentioned this pull request Sep 19, 2026
3 tasks
@takemi-ohama
takemi-ohama deleted the fix/plan62-inject-account-group branch September 22, 2026 20:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

機密の置き場に書いた DEVBASE_ACCOUNT_GROUP が注入でプロセスへ載り、ボリュームのグループを変えうる

1 participant