Repository navigation
Fix: OpenBao への接続を OS の信頼ストア(truststore)で検証する(#497) - #498
Conversation
TLS を傍受するプロキシの下で、既定の CA では検証に落ちてキャッシュへ落ちていた。 OpenBaoBackend._http の urlopen に truststore.SSLContext を渡す。プロセス全体へは 注入せず、truststore を読み込めないときは既定のコンテキストで続ける。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NjbAm85zNM1QmoDYNiX5Dy
Item-Id: I-001 Impl-Runtime: claude Impl-Model: default Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fetch 404 の応答の本文から現在の版を取り出す段階を _version_from_404 へ抽出した。 fetch は 404 のときにこのヘルパの版で基準を控えるだけになる。 Item-Id: I-001 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HTTP の失敗応答を表す内部の例外 _HttpStatus を、同じファイルのほかの例外に そろえて _HttpStatusError へ改名した(定義・raise 1 か所・except 4 か所)。 Item-Id: I-002 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oBackend.save 応答の版が整数か (真偽値でない) を確かめる規則を _as_version へまとめ、 _version_of と save の新しい版の読み取りの両方から使う。 Item-Id: I-004 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
失敗の文言の末尾へ「接続先: <URL>」の行を足す処理を _at_server へ抽出し、 接続先の行で終わる文言 (login・_http・_unreachable・_unreadable・_forbidden) を このヘルパで組む。接続先の後ろに案内やパスが続く文言はそのまま残した。 Item-Id: I-005 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…called_only_from_the_openbao_http_helper 関数が urlopen を属性か名前で参照するかの判定を _refers_to_urlopen へ抽出し、 演算子の優先順位に頼っていた条件を 2 つの if に分けた。テスト本体は ファイルと関数の列挙だけになる。補助関数の判定 (属性・名前・入れ子・無関係な名前) を 小さな AST で確かめるテストを足した。 Item-Id: I-007 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…aoBackend login・fetch・save・remove に生のまま散っていた HTTP の状態コード (400・403・404) を _HTTP_BAD_REQUEST・_HTTP_FORBIDDEN・_HTTP_NOT_FOUND とログインの拒否の組 _LOGIN_REJECT_STATUSES に置き換えた。4xx の範囲の判定はそのまま残した。 Item-Id: I-008 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ends_the_whole_dictionary_in_one_post_with_the_read_version KV への POST だけを取り出す内包表記を _kv_posts(openbao) へまとめ、 書き方の揺れ (kv_path is not None と真偽) も 1 つにそろえた。 Item-Id: I-009 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oBackend._unreachable 接続先の行を文面の途中に手で組んでいた 3 か所 (login の認証拒否・_basis_for_write・ save の 4xx 拒否) を _at_server 経由にした。_at_server は接続先の行の後へ続く行を 受け取れるようにし、文面は変えていない。 Item-Id: I-010 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tatus.errors 共通化の前に、書き込みの 400 の本文 (空・不正な JSON・不正な UTF-8・配列・ errors がリストでない・要素が文字列でない) の扱いを現状固定テストで押さえる。 Item-Id: I-011 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
改修計画 — devbasex/devbase #498
改善項目I-001 —
|
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| long_method | extract_method | major | medium | kiro / claude | 採用 | 2 |
なぜ: 本体で最も認知的複雑度が高い (15)。GET の送信・404 の本文再解釈による版の復元・403 の封筒・取得成功時の secrets と版の解釈が 1 つの関数に同居し、部分だけをテストできない。404 の分岐は e.body を再度 json.loads して _version_of を引く独立した段階である
手順: 1. 404 応答から版を取り出す段階を _version_from_404(e.body) として抽出する
2. fetch 本体では except _HttpStatus 内でそのヘルパを呼ぶだけにする
3. 既存テスト (test_save_after_a_soft_delete_uses_the_current_version_not_zero, test_empty_reference_is_absent) で版の復元が変わらないことを確認する
I-002 — lib/devbase/env/openbao.py#_HttpStatus
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| inconsistent_naming | rename | minor | medium | claude | 採用 | 1 |
なぜ: _HttpStatus は Exception の派生で raise / except で使われるが、名前が状態の値に読める。同じファイルの例外はすべて ...Error で終わる(SecretUnreachableError など)
手順: 1. _HttpStatus を _HttpStatusError へ改名する(定義・raise 1 か所・except 4 か所)
2. ほかの差分と混ぜず単独のコミットにする
3. テストを通す(テストはこの名前を参照していない)
I-003 — tests/env/test_openbao.py#test_every_openbao_route_uses_the_truststore_context
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| magic_value | introduce_named_constant | minor | medium | claude | 取り消し | 0 |
なぜ: ログインの経路を見分けるのに '/v1/auth/approle/login' を文字列で書いている。本体には同じ値の LOGIN_PATH があり、経路が変わるとテストだけ古い値で 'login' を見分けられなくなる
手順: 1. from devbase.env.openbao の import に LOGIN_PATH を足す
2. 内包表記の比較を path != LOGIN_PATH に置き換える
3. テストを通す
取り消した理由: テストの期待する振る舞いが変わっています(tests/env/test_openbao.py)。構造改善では期待出力を変えません。振る舞いの変更は別の変更に分けてください
I-004 — lib/devbase/env/openbao.py#OpenBaoBackend.save
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| duplication | consolidate_duplication | minor | medium | claude | 採用 | 1 |
なぜ: 応答の版が整数か(isinstance(int) かつ bool でない)を確かめる規則が _version_of と save の新しい版の読み取りに 2 か所ある。版の扱いは CAS の基準そのもので、片方だけ直ると読みと書きで版の解釈が食い違う
手順: 1. モジュールの関数 _as_version(value) -> Optional[int] を足す(int かつ bool でなければ値、ほかは None)
2. _version_of の最後の return を _as_version(version) に置き換える
3. save の new_version を _as_version(_dict_get(inner, 'version')) にし、判定を if new_version is None: に置き換える
4. 保存の版のテスト(2 度目の保存が 1 度目の応答の版を使う)が通ることを確かめる
I-005 — lib/devbase/env/openbao.py#OpenBaoBackend
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| duplication | extract_method | minor | medium | claude | 採用 | 1 |
なぜ: 失敗の文言の末尾の「\n 接続先: {self.url}」が login・_http(3 か所)・_unreachable・_unreadable・_forbidden・_basis_for_write・save の 4xx に 10 か所近く手で書かれている。テストは '\n 接続先: ' の形を確かめており、1 か所の書き損じが利用者の見る文言の揺れになる
手順: 1. _at_server(self, message: str) -> str を足し、f"{message}\n 接続先: {self.url}" を返す
2. 接続先の行で終わる文言だけを _at_server(...) で包む形へ置き換える(接続先の後ろにパスや案内が続く文言は置き換えない)
3. 不達・認証・JSON の不正のテストで文言が変わらないことを確かめる
I-006 — tests/env/test_openbao.py#test_issue_token_logs_in_again_near_expiry
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| test_coupled_to_internals | fix_dependency_direction | minor | medium | codex | 取り消し | 0 |
なぜ: 期限切れのテストが backend._token_expires_at を直接0へ書き換え、内部属性名と期限の保存方法に結合している。同じファイルの test_an_expiring_token_is_renewed_before_the_request は time.monotonic を進めて公開APIで同じ現象を試しており、既存の方法へそろえられる。
手順: 1. 最初の issue_token の前に time.monotonic を制御し、既知の基準時刻でトークンを取得する。
2. _token_expires_at の直接変更を外し、偽サーバのトークン寿命を越える時刻へ時計を進めて再度 issue_token を呼ぶ。
3. openbao.logins == 2 の期待値を維持し、内部状態に触れず再認証を確認する。既存の取得経路の期限テストと合わせて実行する。
取り消した理由: テストの期待する振る舞いが変わっています(tests/env/test_openbao.py)。構造改善では期待出力を変えません。振る舞いの変更は別の変更に分けてください
I-007 — tests/env/test_openbao.py#test_urlopen_is_called_only_from_the_openbao_http_helper
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| deep_nesting | extract_method | major | low | claude / codex / kiro | 採用 | 1 |
なぜ: テストで最も認知的複雑度が高い (18)。rglob → ast.parse → ast.walk の三重の入れ子の中で urlopen の呼び出し元を集める。さらに判定条件 (isinstance(..., Attribute) and inner.attr == 'urlopen' or isinstance(..., Name) and inner.id == 'urlopen') は演算子の優先順位が読みにくく、意図を取り違えやすい。呼び出し元の収集を関数へ切り出すと、入れ子が浅くなりテスト本体はアサートだけになる
手順: 1. 同じテストファイル内にASTの関数ノードを受けてurlopen参照の有無を返す補助関数を抽出する。Attribute と Name の両方、FunctionDef のみを扱う条件、入れ子の関数も走査する現在の意味を保つ。
2. 外側のテストはファイルと関数を列挙して補助関数で絞る形にし、対象ディレクトリと最終的な sorted(set(callers)) の期待値を変えない。
3. 小さなAST入力で属性参照・名前参照・無関係な名前・入れ子を確かめ、既存の配置制約テストと全経路のTLSテストを実行する。
レビューで確かめるテストの差分: tests/env/test_openbao.py(機械で期待値が変わったか決まらなかった)
I-008 — lib/devbase/env/openbao.py#OpenBaoBackend
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| magic_value | introduce_named_constant | minor | low | kiro | 採用 | 1 |
なぜ: HTTP の状態コード 400・403・404・500 と範囲 (400 <= e.status < 500) が login・fetch・save・remove に生のまま散在する。LOGIN_PATH や _CAS_MISMATCH は定数化されているのに状態コードは数値のままで、意味が読めず変更漏れが起きる。特に 403 は「権限不足」、404 は「未作成/論理削除」、400/403 のログイン拒否という固有の意味を持つ
手順: 1. モジュール先頭に _HTTP_FORBIDDEN = 403, _HTTP_NOT_FOUND = 404, _LOGIN_REJECT_STATUSES = (400, 403) を定義する
2. login・fetch・save・remove の該当リテラルを定数へ置き換える (範囲判定 400 <= e.status < 500 はそのまま残すか _is_client_error ヘルパにまとめる)
3. 既存の状態コード別テストが通ることを確認する
I-009 — tests/env/test_openbao.py#test_save_sends_the_whole_dictionary_in_one_post_with_the_read_version
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| duplication | extract_test_helper | minor | low | claude | 採用 | 1 |
なぜ: KV への POST だけを取り出す [r for r in openbao.requests_of('POST') if r.kv_path] が 7 本のテストに書かれている(kv_path is not None と真偽の 2 通りの書き方が混じる)
手順: 1. モジュールの関数 _kv_posts(openbao) を足す(ログインの POST を除いた KV への POST を返す)
2. 7 か所を _kv_posts(openbao) / _kv_posts(openbao)[0] に置き換える。test_write_does_not_touch_the_server_when_the_read_fails の any(...) は not _kv_posts(openbao) にする
3. テストを通す
レビューで確かめるテストの差分: tests/env/test_openbao.py(機械で期待値が変わったか決まらなかった)
I-010 — lib/devbase/env/openbao.py#OpenBaoBackend._unreachable
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| duplication | consolidate_duplication | minor | low | kiro | 採用 | 1 |
なぜ: 不達エラーの文面「OpenBao へ到達できません (...)\n 接続先: {self.url}」が login・_http(到達不能/JSON 不可)・_unreachable・_basis_for_write に別々に組み立てられている。接続先行の形式を変えるとき複数箇所を直す必要があり、片方だけ直す事故が起きる。接続先行の付与は _unreachable に既にある共通化を広げて 1 箇所へ寄せる
手順: 1. 「\n 接続先: {self.url}」を付ける小さなヘルパ(例 _endpoint_line / _with_endpoint(message))を 1 つ用意する
2. login の 2 つの SecretUnreachableError と _http の到達不能・JSON 不可の文面をヘルパ経由に置き換える
3. _basis_for_write の文面もヘルパ経由にする
4. 既存テスト (test_unreachable_server_is_reported_with_the_url ほか) で接続先行が残ることを確認する
I-011 — lib/devbase/env/openbao.py#_HttpStatus.errors
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| duplication | consolidate_duplication | minor | low | codex | 採用 | 1 |
なぜ: _HttpStatus.errors と OpenBaoBackend.fetch の404処理が、同じ失敗応答の bytes をUTF-8でJSONへ変換し、解釈できなければ空として扱う手順を重複して持つ。失敗応答の寛容な読み取りを一か所に寄せると、fetch の例外処理内のネストも減る。成功応答の厳格なJSON処理は目的が異なるため共通化しない。
手順: 1. tests/env/test_openbao.py に、404本文が空・不正JSON・不正UTF-8・有効な版を持つ場合、および400本文が不正な場合の公開API経由の現状固定テストを置く。既存の論理削除とCAS競合のテストも使う。
2. _HttpStatus に、本文を解釈して返し、現在捕捉している例外だけを捕捉して空辞書を返す内部メソッドを抽出する。
3. errors と fetch の404分岐をその呼び出しへ置き換える。errors の文字列化、404で版が無いときの0、正常な非辞書JSONの扱いを保つ。
4. 対象テストと全体テストを実行する。
レビューで確かめるテストの差分: tests/env/test_openbao.py(機械で期待値が変わったか決まらなかった)
指標の測定
- 状態: written / 言語とツールの対応: 既定(.ndf/code-metrics.json は無い) / 所要: 2.2 秒(使えた時間 105 秒 / 上限 105 秒)
- 指標のファイル: /var/folders/qz/qxt0p_y15xv5jg4x77zmtxj80000gp/T/ndf-worktrees/devbasex--devbase/rf498/work/.cross_refactoring/code-metrics-rf498.md
| 言語 | ツール | 版 | ランナー | ファイル | 秒 | 結果 |
|---|---|---|---|---|---|---|
| python | ruff-complexipy | ruff 0.16.9 / complexipy 8.0.1 | uvx | 2 | 0.7 | 測った |
| 重複: python | symilar | pylint 4.0.9 | uvx | 2 | 1.4 | 測った(0 箇所) |
時間の上限
| 値 | 中身 |
|---|---|
| 提案の枠の終わり(監視の上限 = 残り + 余裕) | 2026-10-17T16:19:22+09:00 |
| 改修計画の枠の終わり(同上) | 2026-10-17T16:22:52+09:00 |
| テストの追加の終わり = 実装の終わり − Σ(採っていて未検証の項目の実装の見積り) | 2026-10-17T16:27:44+09:00 |
| 実装の終わり = 最終ゲートの修正の打ち切り − バッファ − Σ(採っていて未検証の項目の検証の見積り) | 2026-10-17T16:28:56+09:00 |
| 直しの試行の打ち切り | 2026-10-17T16:35:38+09:00 |
| 想定最大時間の終わり H(子プロセスはすべてここまでに止まる) | 2026-10-17T16:44:01+09:00 |
| 確かめの開始の締め切り = H − 確かめの見込み(最終ゲート修正と打ち切りの後の取り消しもここまで) | 2026-10-17T16:41:08+09:00 |
| 確かめの見込み(秒。最終ゲートの確かめ 1 回。バッファの最終ゲートの全体テスト) | 173 |
| 最終ゲート修正 1 回の見込み(秒。バッファの final_fix。起動は今 + この値が確かめの開始の締め切り以前のときだけ) | 330 |
| 指標の測定の上限(秒。提案の枠の中から割く) | 105 |
| 着手前のテスト 1 回の上限(秒) | 420 |
| 範囲テスト 1 回の上限(秒) | 518 |
| 手元の全体テスト 1 回の上限(秒) | 420 |
| CI の待ちの上限(秒) | 324 |
| 余裕(秒。手順の上限と CLI の上限に足す) | 105 |
入力: 予算 35 分 / 全体テストの所要 w 139.8(ndf-record) / 着手前の実測 x 172.4 / CI の壁時計 c 108.0 / 範囲テストの所要 s None(—) / 戦略 local-full
無音の打ち切りは手順の監視の上限と同じ値である。項目ごとの期限は持たない(実装を止めるのは実装の終わりだけ)。
見送った提案
| 対象 | 兆候 | 理由 | 根拠(MVV) | 補足 |
|---|---|---|---|---|
lib/devbase/env/openbao.py#OpenBaoBackend.fetch |
duplication | duplicate | Vision | C-004 と同じ変更 |
lib/devbase/env/openbao.py#OpenBaoBackend.save |
long_method | no_target | C3 / Value 2 / Vision / Value 3 | 範囲テストを組み立てられない(test_targets が --scope のテストの置き場所に無いか、雛形を持つ suite が無い) |
tests/env/test_openbao.py#test_group_layout_reads_and_writes_the_group_paths |
duplication | budget | Vision | 見積り 1.2 分が残りに入らない |
lib/devbase/env/openbao.py#OpenBaoBackend._http |
long_method | budget | Value 3 | 見積り 1.4 分が残りに入らない |
lib/devbase/env/openbao.py#OpenBaoBackend.remove |
duplication | budget | C3 / Vision | 見積り 2.1 分が残りに入らない |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | codex | REQUEST_CHANGES
6ファイルをレビューし、修正が必要な指摘は major 1件です。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | kiro | APPROVE
6 ファイルすべてを確認した。openbao.py の構造改善(_at_server への文言の集約・_as_version・_version_from_404 の抽出・状態コードの定数化・例外名の改名)は、メッセージの行順・例外の型・HTTP の状態の扱いを保っており、振る舞いを変えていない。#497 の TLS 変更は意図した新機能で、4 経路すべてへ同じ SSL コンテキストを渡し、検証を緩めず(CERT_REQUIRED・check_hostname・inject_into_ssl 不使用)、truststore 不在時は既定コンテキストへ退避する。CHANGELOG と secret-backend.md はトラストストアでの検証の前提(OS に CA を足せる者は接続先を偽れる)を明記し、実装と整合している。依存 truststore>=0.10 は lock で 0.10.5 に固定。critical/major の基準に該当する指摘は見つからなかった。
truststore.SSLContext(PROTOCOL_TLS_CLIENT) は、Python 3.13 の ssl.create_default_context() が立てる VERIFY_X509_STRICT と VERIFY_X509_PARTIAL_CHAIN を立てない。今までの urlopen が拒んだ不適合な 証明書チェーンを受け入れないよう、その Python の既定の verify_flags を写す。 3.10・3.13 で truststore の SSLContext が verify_flags の設定を受けることを 確かめ、版によらず写されることを見る回帰テストを足した。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NjbAm85zNM1QmoDYNiX5Dy
🔧 /ndf:fix サマリ | round 1 | commit bca2cc6対応件数: critical=0 / major=1 / minor=0(合計 1 件) |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | claude | APPROVE
6 ファイルを確認し、critical / major の基準に当たる指摘は無い。Refactor のコミットはエラーの型・文言の行順・HTTP の状態の扱い・トークンの再取得を変えておらず、round 1 の VERIFY_X509_STRICT の指摘は bca2cc6 で既定の verify_flags を写す形に直り回帰テストもある。urlopen の呼び出しは _http の 1 か所で、4 経路すべてに同じコンテキストが渡る。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | kiro | APPROVE
6 ファイルすべてを確認した。round 1 の唯一の major(takemi-ohama: truststore.SSLContext が create_default_context の VERIFY_X509_STRICT を立てず、Linux/OpenSSL で不適合な証明書チェーンを受け入れ得る)は bca2cc6 で context.verify_flags = ssl.create_default_context().verify_flags により解消されている。truststore の実装(_api.py)で verify_flags のセッターは _ctx に書き込み、その _ctx が wrap_socket 時の _configure_context で使われるため、写した検証フラグは実際のハンドシェイクに効く。test_truststore_context_copies_the_default_verify_flags が Python の版に依らず写しを確認する回帰テストになっている。構造改善のコミット(_at_server への文言集約・_as_version・_version_from_404 の抽出・HTTP 状態コードの定数化・_HttpStatus→_HttpStatusError の改名・テストヘルパ _kv_posts)は、例外の型・文言の行順・HTTP 状態の分岐・トークン再取得の振る舞いを保っている。truststore の SSL コンテキストは _http の 1 経路から 4 つの urlopen 呼び出しすべてへ _tls_context() 経由で渡り(test_every_openbao_route_uses_the_truststore_context が id 一致を確認)、検証は緩めず(CERT_REQUIRED・check_hostname・inject_into_ssl 不使用)、truststore 不在時は None へ退避して既定コンテキストで続ける。依存 truststore>=0.10 は lock で 0.10.5 に固定。critical/major の基準に該当する指摘は見つからなかった。
🔧 /ndf:fix サマリ | commit (なし)対応件数: critical=0 / major=0 / minor=0(合計 0 件) |
配布の記録段階: 本番(2026-10-17、
リリース後テスト対象の版: main
合否: 合格 |
Closes #497
何を変えたか
TLS を傍受するプロキシ(Netskope など)の下で、ホストの devbase が OpenBao へ繋がらずキャッシュへ落ちていた。OpenBao への HTTP だけ、OS の信頼ストア(
truststore)の SSL コンテキストで検証する。lib/devbase/env/openbao.py_tls_context()(1 度だけ作って使い回す)を足し、OpenBaoBackend._httpのurlopenにcontext=で渡す。truststoreを import できなければNone(既定のコンテキスト)。verify_flagsはssl.create_default_context()のものを写す(Python 3.13 のVERIFY_X509_STRICT・VERIFY_X509_PARTIAL_CHAINを落とさない。レビューの指摘で足した)。構造改善でOpenBaoBackendの重複(HTTP の状態の扱い・到達できない旨のエラーの組み立て・保存の送り方)をまとめ、振る舞いは変えていないpyproject.toml・uv.locktruststore>=0.10(0.10.5 を固定)tests/env/test_openbao.pydocs/specifications/secret-backend.mdCHANGELOG.md[Unreleased]の Fixedurlopenを呼ぶのはlib/devbaseの中でOpenBaoBackend._httpだけである(認証・取得・保存・削除の 4 経路はすべてここを通る)。bootstrap.pyは HTTP を持たない。受け入れ条件との対応
test_every_openbao_route_uses_the_truststore_context(偽サーバに 4 経路を通し、contextが 1 つのtruststore.SSLContext・CERT_REQUIRED・ホスト名照合あり・既定と同じverify_flagsを確かめる)、test_truststore_context_copies_the_default_verify_flags、test_urlopen_is_called_only_from_the_openbao_http_helper(AST でurlopenの呼び出し元を挙げる)test_truststore_is_not_injected_into_the_process(ssl.SSLContextが差し替わらない)test_missing_truststore_falls_back_to_the_default_contextSecretUnreachableError、メッセージの形は同じtest_certificate_verification_failure_is_unreachableuv.lock、uv sync --lockeduv sync --lockedが通る設計の決定との差
無し(設計 PR なし)
テスト
env -u DEVBASE_ROOT uv run --locked pytest tests/ -q— 4510 passed, 32 skipped(2026-10-17、HEAD bca2cc6)uvx ruff check --select=E9,F63,F7,F82 lib— 通るpython3 .github/scripts/proper_term_check.py— 手元は語の一覧が無いため飛ばした(検査はしていない)SSL_CERT_FILE・REQUESTS_CA_BUNDLEを外して AppRole のログインと 1 参照のGETだけ)mainCERTIFICATE_VERIFY_FAILED ... self-signed certificate in certificate chainで到達できない構造改善とレビュー
verify_flags)を bca2cc6 で直した。未解決 0リリース後テスト
mainへのマージ後、回避の環境変数を付けずにbin/devbaseの読むだけの操作で OpenBao から取得できる(devbase upは使わない)🤖 Generated with Claude Code
https://claude.ai/code/session_01NjbAm85zNM1QmoDYNiX5Dy