Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ffe2326
docs: create issue I225
osushi0404-claude[bot] Nov 5, 2026
7ef278d
docs(I225): plan/tests/review 作成
osushi0404-claude[bot] Nov 5, 2026
e036403
docs(I225): Draft PR #416・STAGE_DONE plan
osushi0404-claude[bot] Nov 5, 2026
bb79ee2
docs(I225): plan-review 記録
osushi0404-claude[bot] Nov 5, 2026
2d143eb
docs(I225): 計画レビューの Blocker 対応(revoke.sh --stdin・スパイク・M-01・Danger Ops)
osushi0404-claude[bot] Nov 5, 2026
09c3d2b
docs(I225): plan-review 記録
osushi0404-claude[bot] Nov 5, 2026
9d21976
docs(I225): 計画レビュー OK・Warning 対応・STAGE_DONE plan-review
osushi0404-claude[bot] Nov 5, 2026
faa1455
feat(I225): auth status の置き換え・revoke.sh・起動の MCP 制限と PATH・G7〜G10
osushi0404-claude[bot] Nov 5, 2026
446e786
docs(I225): STAGE_DONE implement
osushi0404-claude[bot] Nov 5, 2026
40478a2
docs(I225): code-review 記録
osushi0404-claude[bot] Nov 5, 2026
13974d0
docs(I225): review-gate HIGH(決定論ゲートの見出し違い)・STAGE_DONE review-gate
osushi0404-claude[bot] Nov 5, 2026
1588032
docs(I225): fix-diagnosis-review 記録
osushi0404-claude[bot] Nov 5, 2026
fb4b563
fix(I225): 決定論ゲートの見出しをテンプレートどおりに直す・STAGE_DONE fix-loop
osushi0404-claude[bot] Nov 5, 2026
2ab45b0
docs(I225): code-review 記録
osushi0404-claude[bot] Nov 5, 2026
22ae10d
docs(I225): review-gate OK・STAGE_DONE review-gate
osushi0404-claude[bot] Nov 5, 2026
52d9d81
docs(I225): test-gate(M-01〜M-04 OK・TC-03 OK)・STAGE_DONE test-gate
osushi0404-claude[bot] Nov 5, 2026
fa3acda
docs(I225): retro(台帳の残りの振り分け・I226 #417 を起票)・STAGE_DONE retro
osushi0404-claude[bot] Nov 5, 2026
8d015a3
close(I225): 記録を closed へ移す
osushi0404-claude[bot] Nov 5, 2026
fe44100
docs(I225): STAGE_DONE close(マージ依頼)
osushi0404-claude[bot] Nov 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions docs/issues/closed/I225.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# I225: I223 のレビューの残り: GitHub の鍵が画面に出る・漏れたときの手順と、テスト用のセッションの抜け道を塞ぐ

## 関連資料
- GitHub Issue: #415
- Draft PR: #416
- 起点: I223(GitHub #412・PR #414)の retro からの起票(2026-11-05)
- 台帳の記録: `docs/reviews/I223_code_review_20261105_1440.md`(F7・F9・F13・F14・F15)
- 経緯: `docs/tests/open/I223_manual_test.md` の M-02(I223 のマージ後は `docs/tests/closed/`)・診断メモ `docs/reviews/I223_fix_diagnosis_20261105_1450.md`
- 優先度: **次のハーネスの作業で最優先**(`SECURITY=yes` の指摘を含むため)

## 設計確認メモ(/grill-me)
- Q: 鍵を画面に出す `--json` なしの `gh auth status` を、どこで止めるか(A: `gh` の入口で断る+手順書の静的な検査/B: 静的な検査だけ/C: 見張りで確認) → A: 「ループエンジニアリング・ハーネスエンジニアリングのベストプラクティスと、開発をサクサク進める観点で問題がないやり方で」(ユーザー・2026-11-06)。Claude が次のとおり確定した:
- 入口 `scripts/claude/gh-app/gh` で、引数が `auth status` で `--json`・`-t`/`--show-token` を含まないときは、断らずに鍵の欄を出さない形(`auth status --json hosts --jq …` で名義・鍵の出どころ・状態だけ)に置き換えて表示し、置き換えたことを 1 行で標準エラーに出す。理由: 断ると打ち直しの往復が要る(ループが止まる)。置き換えなら Claude も人も 1 回で要る情報が得られ、鍵は出ない。`argv` で判定するので、シェルの文字列を読む判定(見張りの作り込み)にならない
- `-t`/`--show-token` の明示はそのまま通す(わざと鍵を見る操作。Claude からは見張りの S23・S35 が確認にする。見張り `pretooluse_guard.py` は変えない)
- 手順書・スキル・エージェント・スクリプト・open のテスト文書に `--json` なしの `gh auth status` が書かれたら落ちる静的な検査を `scripts/claude/tests/test_i223_gh_app.sh` に足す(closed の記録は対象外)。※計画で対象を手順書・スキル・エージェント・ハーネスのスクリプト・テンプレートに絞った(open のテスト文書を含む個々のイシューの記録は外す。理由は plan_I225.md §9)
- 予防策は新しい決まりを増やさず、上の 2 つの決定論のチェックで代える(計画レビュー役・計画の書き方は変えない)
- Q(Claude が決めた技術的な点・ユーザーに聞いていない): F13 は漏れた鍵そのものを `GH_TOKEN` に入れて `DELETE /installation/token` し、`token`・`token-readonly` の両方の控えを消す手順にする。F14 は点検コマンドを表の外のコードブロックに出し、`GH_APP_READONLY` を外し `.tokenSource` を足す。F7 は `claude -p` を起動する `scripts/claude/` のスクリプトに `--strict-mcp-config` を足す(MCP が要る判定は `--mcp-config` で必要なものだけ・既存の Q18 は維持)。2026-11-06 時点で元のリポジトリの `.mcp.json` に github は無い。F9 は `tui-capture.sh` の tmux 起動に `-e PATH=…` を足し、入口の `gh` を必ず通す

## 背景/目的

**背景**: I223 で、Claude が GitHub を操作する名義を GitHub App にし、テスト用のセッション(`claude -p`・tmux の中の `claude`)には読み取りだけの鍵(`GH_APP_READONLY=1`)を渡すようにした。I223 の test-gate で、手順書どおり `gh auth status` を流したところ、App の新しい形式の長い鍵(書き込みのできる 1 時間の鍵)の大部分が画面と会話の記録に出た(`gh` は鍵の最後の部分しか伏せない)。その鍵はすぐに失効させ、手順書の確かめ方は `gh auth status --json …`(要る欄だけを取り出す)に直した。ただし、レビューで次の残りが指摘された(止める条件には当たらず、I223 では直していない)。
**目的**: 鍵が画面に出る書き方を決定論で締め出し、出てしまったときの手順を正しくし、テスト用のセッションが読み取りだけの鍵を迂回する抜け道を塞ぐ。

### 現状の問題(証拠・再現手順)
- **F15(SECURITY=yes)**: `--json` なしの `gh auth status` が鍵の大部分を出す問題を、手順書の決まりだけで防いでいる。見張り(`scripts/claude/hooks/pretooluse_guard.py`)が確認にしているのは `gh auth status -t`・`gh auth token` だけ(`scripts/claude/tests/test_pretooluse_container_guard.sh` の S23・S35)。手順書・スキルに書き戻されると再発しうる
- **F13(Medium・再現あり・SECURITY=yes)**: `docs/runbooks/github-app-setup.md`「5.」の「鍵が出たときの失効手順」`gh api -X DELETE installation/token` は、そのとき入口(`scripts/claude/gh-app/gh`)が渡す鍵を失効させるので、漏れた鍵と同じとは限らない(テスト用のセッションで漏れた読み取りだけの鍵・期限間際に取り直された鍵)。消す控えも `~/.cache/github-app/token` だけで `token-readonly` が抜けている。再現: 読み取りだけの鍵が画面に出た後、通常のシェルで手順を流すと、書き込みの鍵が失効し、漏れた鍵は有効なまま残る
- **F14(Medium・再現あり)**: `docs/runbooks/harness-audit.md` の「手元に残る古い鍵」の行の点検コマンドが、表の中の `\|` のせいでそのままコピーすると jq の構文エラーになる。`GH_APP_READONLY` があると `GH_APP_DISABLE=1` が無視され、保存されたログインを見られない。`.tokenSource` が抜けていて、環境変数の鍵と保存されたログインを区別できない
- **F7(SECURITY=yes)**: `scripts/claude/` の `claude -p` の起動に `--strict-mcp-config` が無い。ワークツリーのセッションは元のリポジトリの `.mcp.json`(develop のまま GitHub の MCP がある)を読む(I223 の M-06 ② で観測)。手元に PAT が残っていると、MCP 経由の書き込みが読み取りだけの鍵を迂回しうる
- **F9(SECURITY=yes)**: `scripts/claude/tui-capture.sh` で、tmux サーバーが先に立っていて、その `PATH` に `~/.local/bin` が無いと、中の `claude` の `gh` が入口を通らない(入口を通らなければ App の鍵自体は渡らないが、本物の `gh` に保存されたログインが有効なら、そちらで書き込める)

### 根本原因
鍵・秘密を扱う手順の確かめ方を決めるときに、そのコマンドが秘密を画面に出すかを確かめる段取りが無く、見張りも一部の書き方しか確認にしていない。テスト用のセッションの守り(読み取りだけの鍵)は `gh` の入口を通ることを前提にしていて、入口を通らない経路(MCP・本物の `gh`・別の `PATH`)を数えていない。

### 解決方針
- F15(確定): 入口 `scripts/claude/gh-app/gh` で、`--json`・`-t`/`--show-token` なしの `gh auth status` を、鍵の欄を出さない `--json` の表示に置き換える(断らない・置き換えたことを標準エラーに 1 行)。あわせて、手順書・スキル・エージェント・ハーネスのスクリプト・テンプレートに `--json` なし(または `-t`/`--show-token` 付き)の `gh auth status` が書かれたら落ちる静的な検査を `scripts/claude/tests/test_i223_gh_app.sh` に足す。見張り `pretooluse_guard.py` は変えない
- F13(確定): 失効の手順を、漏れた鍵そのものを `GH_TOKEN` に入れて `DELETE /installation/token` する形にし、`token`・`token-readonly` の両方の控えを消す手順にする
- F14(確定): 点検コマンドを表の外のコードブロックに出し、`GH_APP_READONLY` を外して流す形・`.tokenSource` を足した形にする
- F7(確定): `scripts/claude/` の `claude -p` の起動に `--strict-mcp-config`(MCP が要る判定では `--mcp-config` で必要なものだけ)を足す。既存のテスト(`test_check_permission_prompt.sh` Q18 など)は維持する
- F9(確定): `tui-capture.sh` の tmux 起動に `-e PATH=…` を足し、入口の `gh` を必ず通す
- 予防策(確定): 新しい決まりは足さず、F15 の入口の置き換えと静的な検査(決定論のチェック)で代える

## 実装対象(既知のもの)
| ファイル | 変更内容 |
|---------|---------|
| `scripts/claude/gh-app/gh` | `--json` なしの `gh auth status` を鍵の欄を出さない表示に置き換える(F15) |
| `scripts/claude/tests/test_i223_gh_app.sh` | 入口の置き換えのテストと、手順書などに `--json` なしの `gh auth status` が無いことの静的な検査(F15) |
| `docs/runbooks/github-app-setup.md` | 失効の手順(F13) |
| `scripts/claude/gh-app/revoke.sh`(新規) | 控えの 2 つの鍵を失効させて確かめ、控えを消す。控えに無い漏れた鍵は `--stdin` で値を受けて失効させる(F13・計画で追加) |
| `docs/runbooks/harness-audit.md` | 古い鍵の点検コマンド(F14) |
| `scripts/claude/` の `claude -p` の起動(`check-permission-prompt.sh`・`review-process-lib.sh`・`code-review.sh`・`plan-issue-review.sh`・`issue-review.sh`・`fix-review-lib.sh`・`test-session.sh`) | `--strict-mcp-config` を足すか(F7) |
| `scripts/claude/tui-capture.sh` | tmux の起動に `PATH` を渡し、入口の `gh` を必ず通す(F9) |

## スコープ
### 含む
- 上の F7・F9・F13・F14・F15 と予防策
### 含まない
- I223 の軽い指摘の一覧(`docs/reviews/backlog/I223.md` の F2〜F6・F8・F10〜F12・B1〜B4)
- GitHub への書き込みの回数を絞る仕組み(I224 #413)

## 関連する品質基準
- 該当なし(ハーネスの運用の仕組み)

## 受け入れ条件(Acceptance Criteria)
- [ ] `--json`・`-t`/`--show-token` なしの `gh auth status` を入口の `gh` で流すと、鍵の欄が出ず、名義・鍵の出どころ・状態だけが表示される(F15)
- [ ] 手順書・スキル・エージェント・ハーネスのスクリプト・テンプレートに `--json` なし(または `-t`/`--show-token` 付き)の `gh auth status` を書くと、静的な検査(CI)で落ちる(F15。個々のイシューの記録は対象外・plan_I225.md §9)
- [ ] 手順書の失効の手順が、漏れた鍵そのものを失効させ、2 つの控え(`token`・`token-readonly`)を消す形になっている(F13)
- [ ] 総点検の一覧の古い鍵の点検コマンドを、そのままコピーして流せる(F14)
- [ ] テスト用のセッション(`scripts/claude/` の `claude -p`・`tui-capture.sh`)が、MCP・`PATH` の違いによって読み取りだけの鍵を迂回しない(F7・F9)
- [ ] 既存のハーネステスト・CI がすべて pass する

## 影響範囲(想定)
- Backend: なし
- Frontend: なし
- DB: なし
- Config/Infra: `scripts/claude/`(`gh-app/gh`・`tui-capture.sh`・`claude -p` の起動・`tests/test_i223_gh_app.sh`)・`docs/runbooks/`(見張り `pretooluse_guard.py`・`.claude/agents/` は変えない)

## 制約・引き継ぎ情報
- 鍵の仕組み(`scripts/claude/gh-app/`)と、テスト用のセッションの読み取りだけの鍵(`GH_APP_READONLY=1`・静的なテスト `scripts/claude/tests/test_i223_gh_app.sh` の G6)は I223 で入った
- ローカルの安全装置は「ふつうの書き方の事故」を止めるもので、わざと回避する書き方は対象外。最後の守りは GitHub の権限(App は develop・main に push・マージできない)
- 見張り(`pretooluse_guard.py`)は変えない(grill-me で確定)。入口 `gh-app/gh` の置き換えは鍵を出さない方向の変更で、ユーザーの一任(2026-11-06)で決めた

## Danger Ops(有/無)
- 無(データ削除・破壊的マイグレーション・強制 push は無い)。ただし手動テスト M-02 で `revoke.sh` を本物の GitHub に流し、控えの 2 つの App の鍵(1 時間の鍵)を失効させる。次の `gh` で取り直すので作業は止まらないが、その時に App の鍵を環境変数で持っている別のセッション・プロセスは GitHub の操作が 401 になる(ほかのセッションが動いていない時に流す。plan_I225.md 計画変更記録 1)
Loading
Loading