Skip to content

feat(env): PLAN03-1 PR1 devbase env export (Local + Stdio)#14

Merged
takemi-ohama merged 11 commits into
release/PLAN03-1from
feature/PLAN03-1-export-local
May 21, 2026
Merged

feat(env): PLAN03-1 PR1 devbase env export (Local + Stdio)#14
takemi-ohama merged 11 commits into
release/PLAN03-1from
feature/PLAN03-1-export-local

Conversation

@takemi-ohama
Copy link
Copy Markdown
Contributor

Summary

  • plan: issues/PLAN03-1.md
  • release PR: release: PLAN03-1 devbase env export / import #13
  • 担当範囲:
    • lib/devbase/env/bundle.py — manifest 生成 / tar.gz パック / sha256 検証
    • lib/devbase/env/cipher.py — age 暗号化 (pyrage: recipient / passphrase)
    • lib/devbase/env/storage.py — Local + Stdio backend
    • lib/devbase/env/io_export.py — export 高レベル実装
    • commands/env.pyexport ハンドラ追加 + cli.py のサブコマンド登録
    • pyrage を依存に追加

Test plan

  • bundle.py ラウンドトリップ (dict→bundle→dict 内容一致 + sha256 検証)
  • cipher.py passphrase / recipient ラウンドトリップ + 破損データのエラー
  • storage.py Local / Stdio ラウンドトリップ
  • tests/cli/test_env_export.py 統合テスト (擬似 DEVBASE_ROOT で devbase env export を実行)
  • --force-unencrypted 未指定で平文 export が拒否されること
  • DEST='-'--passphrase-stdin の併用がエラーになること
  • 出力ファイルのパーミッションが 0600 であること

takemi-ohama and others added 2 commits May 21, 2026 10:31
- lib/devbase/env/bundle.py: tar.gz + manifest.yml バンドル構築/展開、sha256 検証、未知 version 拒否、パストラバーサル拒否
- lib/devbase/env/cipher.py: pyrage 経由の age 暗号化/復号 (X25519 / OpenSSH ed25519,rsa / passphrase / @path 参照)
- lib/devbase/env/storage.py: Local + Stdio backend、s3/gs は本 PR では未実装で明示エラー
- lib/devbase/env/io_export.py: 機密キー検知警告、既定鍵 (~/.ssh/id_rsa.pub) 自動利用、--passphrase-stdin と DEST='-' 併用拒否
- cli.py / commands/env.py: env export サブコマンド登録 + SUBCMD_MAP 更新
- pyproject.toml: pyrage>=1.2 を deps、pytest>=8.0 を dev group、tool.pytest.ini_options 追加
- tests/env, tests/cli: ラウンドトリップ + 異常系 28 件

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@takemi-ohama takemi-ohama marked this pull request as ready for review May 21, 2026 01:43
Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 1 | codex | REQUEST_CHANGES

file:// パス処理の不整合と、manifest 検証時の例外ハンドリング欠落を優先修正してください。

Comment thread lib/devbase/env/storage.py Outdated
Comment thread lib/devbase/env/bundle.py
Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 1 | gemini | REQUEST_CHANGES

env export の実装について、1点だけ堅牢性向上のための修正提案をインラインコメントしました。
秘密鍵ファイルの形式判定処理に関するものです。ご確認をお願いします。

Comment thread lib/devbase/env/cipher.py
- storage.py: LocalBackend で file:// URI を url2pathname で実パスへ変換
- bundle.py: manifest.files の要素型 (dict, path: str, sha256: str) を検証
- cipher.py: age 秘密鍵判定をバイト列で行い、UTF-8 デコード失敗を明示エラー化

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

レビュー対応サマリ (round 1/5)

codex review 2件 + gemini review 1件、合計 3件 すべて対応しました (commit f406c8c)。

対応内容

# 重要度 ファイル 内容
1 major / 正確性 lib/devbase/env/storage.py LocalBackendfile:// URI を url2pathname 経由で実ファイルパスへ正規化
2 major / 堅牢性 lib/devbase/env/bundle.py _validate_manifestfiles / 各 entry / path / sha256 の型を検証し、不正時は BundleError
3 minor / 堅牢性 lib/devbase/env/cipher.py _resolve_identity で age 鍵判定を bytes で行い、UTF-8 デコード失敗は明示的に CipherError

テスト

tests/env/ 既存 19 件 PASS。

deferred / rejected はありません。

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

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

lib/devbase/env/storage.pyfile://<host>/... 解釈と、lib/devbase/env/bundle.py の tar 重複エントリ未検知は、入力によって誤動作または曖昧な復元を招くため、先に塞ぐのが安全です。

Comment thread lib/devbase/env/storage.py Outdated
Comment thread lib/devbase/env/bundle.py Outdated
Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 2 | gemini | REQUEST_CHANGES

This PR introduces new features for environment management, including bundling, storage abstraction, and encryption. The implementation is solid and the previous review comments have been addressed correctly.

I have a few minor suggestions for improving test coverage and robustness against edge cases. Please see the inline comments.

Comment thread lib/devbase/env/storage.py
Comment thread lib/devbase/env/bundle.py
Comment thread lib/devbase/env/cipher.py Outdated
- storage: file:// URI の netloc が空/localhost 以外なら StorageError で拒否 (codex major)
- bundle: tar 内の重複エントリを BundleError で検出 (codex major)
- cipher: _resolve_recipient の @path 再帰に深さ制限 (上限 5) を追加 (gemini minor)
- tests/storage: file:// URI roundtrip と remote host 拒否の test を追加 (gemini minor)
- tests/bundle: _validate_manifest 不正系 (files が list でない / entry が dict でない /
  path 不正 / sha256 不正) + 重複エントリの test を追加 (gemini minor)
- tests/cipher: @path 循環参照で CipherError を返す test を追加 (gemini minor)
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

/ndf:fix round 2 サマリ

レビュー指摘 5 件すべてを修正しました (commit 8baca0c)。

修正内訳

  • major×2 (codex):
    • storage.py: file:// URI で netloc が空/localhost 以外なら StorageError で拒否
    • bundle.py: tar 内の重複エントリを検出して BundleError
  • minor×3 (gemini):
    • cipher.py: _resolve_recipient@PATH 再帰に深さ制限 (上限=5) を追加
    • tests/storage: file:// URI の roundtrip + remote host 拒否の test を追加
    • tests/bundle: _validate_manifest の不正系 test (files が list でない / entry が dict でない / path 不正 / sha256 不正) + 重複エントリ test を追加
    • tests/cipher: @PATH 循環参照で CipherError を返す test を追加

テスト

uv run pytest tests/env/ tests/cli/ → 36 passed

deferred / rejected: 0 件

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

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 | REQUEST_CHANGES

manifest の完全性検証をバイパスできる経路が 1 件あるため、sha256 を必須検証にしてください。

Comment thread lib/devbase/env/bundle.py Outdated
Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 3 | gemini | APPROVE

This PR is well-implemented and addresses all previous feedback with corresponding tests. I have one minor suggestion to improve default key discovery, but it doesn't block approval.

Comment thread lib/devbase/env/cipher.py Outdated
- bundle.py: manifest.files[*].sha256 を必須の 64 文字 16 進文字列として検証
  None / 欠落 / 長さ違い / 非 16 進は BundleError。完全性チェック迂回を防止
- cipher.py: default_recipient_paths / default_identity_paths に
  ed25519 (id_ed25519.pub / id_ed25519) を追加し、rsa より優先
- tests: sha256 欠落 / None / 長さ違い / 非 16 進の異常系テストを追加
- tests: ed25519 がデフォルトパス候補に含まれ rsa より優先されることを検証

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

Round 3 修正サマリ

round 3 の 2 件のレビュー指摘に対応しました (commit: cbb98ca)。

修正内容

# 重要度 ファイル 指摘 対応
1 major (codex) lib/devbase/env/bundle.py sha256: None で完全性チェック迂回可能 必須の 64 文字 16 進文字列として検証。不正/欠落/None/非16進いずれも BundleError
2 minor (gemini) lib/devbase/env/cipher.py ed25519 鍵がデフォルト候補に無い default_recipient_paths / default_identity_paths に ed25519 を追加し rsa より優先

テスト

uv run pytest tests/env/ tests/cli/42 passed

追加テスト:

  • test_unpack_rejects_missing_sha256_field (sha256 欠落)
  • test_unpack_rejects_sha256_none (sha256 が None)
  • test_unpack_rejects_sha256_wrong_length (長さ違い)
  • test_unpack_rejects_sha256_non_hex (非 16 進文字)
  • test_default_recipient_paths_includes_ed25519
  • test_default_identity_paths_includes_ed25519

両スレッドとも resolve 済みです。再レビューをお願いします。

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 4 | codex | REQUEST_CHANGES

例外系で DevbaseError 派生に正規化されていない経路が残っているため、失敗時の挙動を一貫させる修正を提案します。

Comment thread lib/devbase/env/bundle.py
Comment thread lib/devbase/env/cipher.py Outdated
Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 4 | gemini | REQUEST_CHANGES

Windows 環境での移植性に関する軽微な問題を1点インラインコメントしました。ご確認をお願いします。他は問題ないため、これの対応をもって承認とさせてください。

Comment thread lib/devbase/env/storage.py
- bundle: yaml.safe_load の結果が dict でない場合に BundleError を送出
  (top-level が list/str/数値の場合に AttributeError が漏れるのを防止)
- cipher: @path 参照ファイルが UTF-8 でない場合 CipherError に包んで再送出
  (UnicodeDecodeError が呼び出し側に漏れていた)
- storage.resolve: Windows ドライブレター (C:\path 等) を urlparse が
  scheme と誤認する問題に対応し LocalBackend にフォールバック

各修正に対応する異常系 test を追加 (合計 +5 test)。
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

Round 4 修正サマリ (commit 2c09ae7)

codex 2 件 (major) + gemini 1 件 (minor) の計 3 件すべてを修正し、各々異常系 test を追加しました。

# 指摘元 重要度 ファイル 対応
1 codex major lib/devbase/env/bundle.py:124 _validate_manifest 先頭で isinstance(manifest, dict) チェックを追加。非 dict の manifest を BundleError に統一
2 codex major lib/devbase/env/cipher.py:42 @PATHread_text(encoding='utf-8') を try/except でラップし UnicodeDecodeErrorCipherError に包む
3 gemini minor lib/devbase/env/storage.py:83 Windows ドライブレター (C:\path 等) を urlparse がスキームと誤認する問題に対応。1 文字 alpha かつ :// を含まなければ LocalBackend にフォールバック

追加した test (+5)

  • test_unpack_rejects_non_mapping_manifest (parametrize: list / string / scalar)
  • test_recipient_at_file_reference_rejects_non_utf8
  • test_resolve_windows_drive_letter_falls_back_to_local (parametrize: C:\..., c:\..., D:/...)

test 結果

uv run pytest tests/env/ tests/cli/ -q
49 passed in 14.15s

deferred / rejected: なし。次ラウンドのレビューをお願いします。

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 5 | codex | APPROVE

追加の修正アクションはありません。

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 5 | gemini | COMMENT

REQUEST_CHANGES

堅牢性の観点で2点、改善提案があります。

  1. bundle.pyunpack における競合状態: extractfiletarfile.TarInfo オブジェクトを引数に取りますが、これはアーカイブ内のメタデータのみを参照し、実際のファイル内容は tarfile オブジェクトから遅延して読み込まれます。現状の実装では、members 辞書にファイル内容を読み込むループ (for info in tf.getmembers():) と、その後の manifest 検証が分離しています。もし巧妙に細工された tar アーカイブ(例えば、manifest.yml の後に同じ名前で異なる内容のファイルが再度含まれるなど)を与えられた場合、getmembers() が返すリストの順序によっては、意図しない manifest.yml を使って検証し、その後の処理で別の内容が使われるという競合状態が発生する可能性があります。tf.extractfile(info) で取得したファイルオブジェクトをすぐに read() して内容を確定させることで、この曖昧さを排除できます。

  2. cipher.py_resolve_identity におけるファイルハンドルリーク: pyrage.ssh.Identity.from_buffer(raw) が例外を送出した場合、raw = path.read_bytes() で開かれたファイルハンドルが適切にクローズされない可能性があります。read_bytes は内部で openclose を行いますが、プロセスが予期せず終了した場合などにリソースリークの懸念が残ります。with open(path, "rb") as f: を使って明示的にファイルコンテキストを管理することで、例外発生時でも確実にファイルがクローズされることを保証でき、より堅牢な実装になります。

Comment thread lib/devbase/env/bundle.py
Comment thread lib/devbase/env/cipher.py
- lib/devbase/env/cipher.py: path.read_bytes() を try/except OSError で
  ラップし、I/O エラー時も CipherError で統一されたエラー型を返す
- tests/env/test_cipher.py: monkeypatch で read_bytes に OSError を
  発生させて CipherError に包まれることを検証する test を追加

gemini round 5 指摘 (minor / 堅牢性) に対応。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

Round 5 修正 Summary (最終ラウンド)

commit: 776cb8d

codex

APPROVE — 追加修正なし。

gemini (2件)

# 指摘 対応
1 bundle.py unpack: extractfile の結果を即座に bytes 化すべき rejected — 現状コードで line 106-109 にて f = tf.extractfile(info) 直後に f.read() を呼び bytes として確定済み。重複名は info.name in members で BundleError。Resolve しない (説明 reply のみ)
2 cipher.py _resolve_identity: path.read_bytes() の OSError を CipherError に包むべき fix — try/except OSError でラップし CipherError に包んで再送出。test (test_resolve_identity_wraps_oserror) を追加

テスト

uv run pytest tests/env/ tests/cli/50 passed (+1 test from round 5)

変更ファイル

  • lib/devbase/env/cipher.py (+4/-1)
  • tests/env/test_cipher.py (+19/-0)

これで /ndf:fix の 5 ラウンドが完了しました。

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 6 | codex | REQUEST_CHANGES

gzip ヘッダ時刻により「再現性あり」という設計意図と実装が不一致です。加えて recipient 読み込み時の I/O 例外が CipherError に正規化されておらず、エラーハンドリング方針が揺れているため、2 点の修正を提案します。

Comment thread lib/devbase/env/bundle.py Outdated
Comment thread lib/devbase/env/cipher.py
Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 6 | gemini | REQUEST_CHANGES

バンドルの検証処理と、秘密鍵の形式判定ロジックについて、堅牢性・拡張性を向上させるための2点を提案します。

Comment thread lib/devbase/env/bundle.py
Comment thread lib/devbase/env/cipher.py
Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 5 | gemini | APPROVE

1点の軽微な堅牢性に関する修正提案をインラインコメントとしていますが、全体として大きな問題は見受けられませんでした。以前のレビューでの指摘事項は適切に修正されています。

Comment thread lib/devbase/env/cipher.py
- bundle.pack: gzip.GzipFile(mtime=0) でラップし出力を完全に決定的にする
- bundle._validate_manifest: tar 内ファイルセットと manifest の完全一致を
  検証し、manifest に記載のない未知ファイルを BundleError で拒否する
- cipher._resolve_recipient: @path の read_text で発生する OSError を
  CipherError に包んで一貫したエラーハンドリングにする
- cipher._resolve_identity: OpenSSH ヘッダで先に SSH 鍵を判別する分岐を
  追加し、鍵形式判別を明示化 (将来の形式追加もしやすくする)
- tests: pack 決定性 / unknown file 拒否 / @path OSError ラップ /
  OpenSSH ヘッダ優先判別の test を追加
recipient ファイルにコメント (# 始まり) や空行が混在していても扱えるよう、
有効な最初の行のみを採用する。テストも追加。
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

Round 6 (final) 対応サマリ

レビュー指摘 6 件にすべて対応しました (commits d357e86, c07b1a7)。

修正内容

# 重要度 ファイル 対応
1 major / 正確性 bundle.py:71 (codex) gzip.GzipFile(mtime=0) でラップし pack 出力を決定的に
2 major / 堅牢性 cipher.py:43 (codex) @path read_text の OSError を CipherError に包む
3 major / 堅牢性 bundle.py (gemini) tar 内ファイルセットと manifest の完全一致を検証 (未知ファイル拒否)
4 minor / 拡張性 cipher.py (gemini) OpenSSH ヘッダ判別を age 鍵判定より先に行う分岐を追加
5 major / 堅牢性 bundle.py:121 (前ラウンド残) 既に round 5 で対応済み (f.read() 即時呼出 + 重複検出) を明示し resolve
6 minor / 堅牢性 cipher.py:59 (gemini) @path ファイルのコメント・空行をスキップして最初の有効行を採用

テスト

  • 4 件の test を新規追加 (test_pack_is_deterministic, test_unpack_rejects_unknown_tar_entries, test_resolve_recipient_at_path_skips_comments_and_blank_lines, test_resolve_recipient_at_path_rejects_only_comments, test_resolve_recipient_at_path_wraps_oserror, test_resolve_identity_prefers_openssh_header)
  • uv run pytest tests/env/ tests/cli/56 passed (全 pass)

deferred / rejected

  • なし

これで round 6 (最終ラウンド) の対応を完了します。再レビューをお願いします。

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 1 | gemini | REQUEST_CHANGES

ストレージ操作時のパーミッション管理や、tar 展開・ファイル収集時の例外処理にいくつかの堅牢性の課題が見つかりました。特に暗号化された機密情報を扱う性質上、作成時のパーミッション競合(race condition)の防止は重要です。

Comment thread lib/devbase/env/storage.py Outdated
Comment thread lib/devbase/env/storage.py
Comment thread lib/devbase/env/bundle.py Outdated
Comment thread lib/devbase/env/bundle.py
Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 1 | codex | REQUEST_CHANGES

インラインコメントの修正項目を確認してください。

Comment thread lib/devbase/env/storage.py Outdated
Comment thread lib/devbase/cli.py
Comment thread lib/devbase/cli.py
Comment thread lib/devbase/env/bundle.py
…mpletion)

- storage.py: LocalBackend.write_bytes を os.open(mode=0o600, O_CREAT|O_TRUNC|O_WRONLY) で
  作成時点から 0600 を強制し、umask に依らない TOCTOU 安全な書き込みに変更
  (codex major / gemini minor — 同一指摘)。既存ファイル上書き時も先に chmod で権限を絞る。
  read_bytes / write_bytes の OSError を StorageError にラップ (gemini minor)。
- bundle.py: unpack() の tarfile.open / getmembers / extractfile で発生する
  tarfile.TarError / OSError を BundleError にラップ (gemini major)。
  make_entries_from_disk の exists() を is_file() に変更し、対象パスが
  ディレクトリだった場合の IsADirectoryError を防止 (gemini minor)。
  _validate_manifest に manifest.files の path 重複検出を追加 (codex minor)。
- cli.py: SUBCMD_PREFIX_PREFERENCES を追加し、`devbase env e` が引き続き edit に
  解決されるように prefix 解決の後方互換を維持 (codex minor)。
- etc/devbase-completion.bash, etc/_devbase: env export サブコマンドと
  各オプションを補完に追加 (codex minor)。
- tests: storage の TOCTOU / OSError ラップ / 既存ファイル 0600 上書き、
  bundle の path 重複 / 壊れた tar / is_file 切替、CLI prefix の後方互換テストを追加。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

/ndf:fix サマリ (round 1)

対応件数: critical=0 / major=3 / minor=5 / nit=0 (合計 8 件)
deferred: 0 件 / rejected: 0 件
commit: 521c28d
CI: NONE (このリポジトリには PR チェックが設定されていません)

--defer-nit 指定でしたが、AI agent ラベルを独自再判定した結果、該当する真の nit は無く、minor のうちパフォーマンス・可読性・堅牢性に該当するものは全て同一コミットで対応しました。重複指摘 (codex storage.py:48 と gemini storage.py:46 の TOCTOU) も両 thread に reply + Resolve 済みです。

詳細

  • [major / gemini] lib/devbase/env/bundle.py unpack()tarfile.TarError / OSErrorBundleError にラップ (test 追加)。
  • [major / codex] lib/devbase/env/storage.py LocalBackend.write_bytesos.open(..., O_CREAT|O_TRUNC|O_WRONLY, 0o600) に置き換え TOCTOU を解消 (test 追加)。
  • [minor / gemini] 同上 (重複指摘 / 同一コミットで対応)。
  • [minor / gemini] LocalBackend.read_bytes / write_bytesOSErrorStorageError にラップ (test 追加)。
  • [minor / gemini] make_entries_from_diskexists()is_file() に変更し、ディレクトリ混入時の IsADirectoryError を防止 (test 追加)。
  • [minor / codex] lib/devbase/cli.pySUBCMD_PREFIX_PREFERENCES を導入し devbase env eedit の後方互換を維持 (test 追加: tests/cli/test_prefix_resolution.py)。
  • [minor / codex] etc/devbase-completion.bash / etc/_devbaseenv export サブコマンド + 各オプション補完を追加。
  • [minor / codex] _validate_manifestmanifest.filespath 重複を検出して BundleError を送出 (test 追加)。

テスト: uv run pytest 70 passed (round 0 比 +14)。

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

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 | APPROVE

修正必須の追加指摘はありません。

Copy link
Copy Markdown
Contributor Author

@takemi-ohama takemi-ohama left a comment

Choose a reason for hiding this comment

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

🤖 cross-review | round 2 | gemini | APPROVE

全体として env export の実装は堅牢で、機密情報の取り扱い(作成時点での 0o600 強制、デフォルト暗号化)やバンドルの再現性(mtime=0, 決定論的 gzip)など、セキュリティと移植性の両面でベストプラクティスに従っています。エラーハンドリングも一貫しており、完成度の高い実装です。

Comment thread lib/devbase/env/io_export.py Outdated
Comment thread lib/devbase/env/io_export.py
Comment thread lib/devbase/cli.py Outdated
- io_export.py: `_resolve_recipients` の docstring を更新し、既定鍵が
  `id_ed25519.pub` → `id_rsa.pub` の優先順で探索される実態に合わせる
- cli.py: `--recipient` の help を `Default: ~/.ssh/id_ed25519.pub, then
  ~/.ssh/id_rsa.pub (first existing one)` に修正
- io_export.py: `--passphrase-stdin` で `sys.stdin.isatty()` の場合に
  `passphrase: ` プロンプトを stderr に表示し、対話実行時のハング感を解消
- 暗号化キー未指定エラーメッセージも ed25519 優先を反映
- tests/cli/test_env_export.py: tty / 非 tty 双方の挙動を検証する 2 ケース追加

Refs: PR #14 review comments 3280597873 / 3280597877 / 3280597881
@takemi-ohama
Copy link
Copy Markdown
Contributor Author

/ndf:fix サマリ (round 2 advisory followup)

対応件数: minor=3 / nit=0 (合計 3 件)
deferred: 0 件 / rejected: 0 件
commit: 01b2208
CI: NONE (このブランチには checks 未設定)

詳細

  • lib/devbase/env/io_export.py:49 docstring 更新 — id_ed25519.pub 優先、id_rsa.pub フォールバックの実態を反映
  • lib/devbase/cli.py:142 --recipient help 更新 — Default: ~/.ssh/id_ed25519.pub, then ~/.ssh/id_rsa.pub (first existing one) に変更
  • lib/devbase/env/io_export.py:69 --passphrase-stdinsys.stdin.isatty() の場合に passphrase: プロンプトを stderr に flush 出力 (パイプ入力時は出力なし)。tty / 非 tty 双方の挙動を検証するテスト 2 件を追加

テスト

  • pytest tests/cli/test_env_export.py: 11 passed
  • pytest 全体: 72 passed

3 件全 thread (#3280597873 / #3280597877 / #3280597881) を Resolve 済みです。

@takemi-ohama takemi-ohama merged commit 9567b3d into release/PLAN03-1 May 21, 2026
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.

1 participant