Repository navigation
feat: I225 GitHub の鍵が画面に出る・漏れたときの手順と、テスト用のセッションの抜け道を塞ぐ - #416
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
計画書レビュー [I225] ── [2026-11-06 12:00]
判定: 差し戻し(Blocker 1件)
レビュー指摘一覧
| 重大度 | 観点 | 指摘内容 | 該当箇所 | 対応 |
|---|---|---|---|---|
| Blocker | P1 要件適合性 | F13 の確定事項と受け入れ条件 3 は「漏れた鍵そのものを GH_TOKEN に入れて DELETE /installation/token する」ことです。計画の revoke.sh は控えの鍵だけを失効させ、画面に出た鍵の値は受け取りません(§9)。控えが取り直された後に漏れた鍵が見つかった場合、その鍵は失効しません。計画は「10 分未満で切れる」と書いています。これは F13 の再現ケース(期限間際に取り直された鍵)をそのまま残します。これは技術的な具体化ではなく、確定事項からの逸脱です。逸脱の理由は「鍵の値を引数や入力に渡すと再び記録に出る」です。この理由は、値を標準入力や read -s で受ける形にすれば避けられます。この選択肢が検討されていません。 |
plan §4-2、§9「revoke.sh は控えの鍵だけを失効させ」。イシュー受け入れ条件 3 |
次のどちらかにします。(a) 漏れた鍵を標準入力などで受けて失効させる口を revoke.sh に足します(値は引数や画面に出さず、テストの G9 に入れます)。(b) 受け入れ条件 3 と確定事項の側を、控えの鍵に絞る形に直し、残るリスク(取り直し後の古い鍵)を明記してユーザーの了承を得ます。 |
| Warning | P1 / 運用 | イシューは Danger Ops を「無(鍵の失効はこのイシューの作業では行わない)」としています。一方、手動テスト M-02 は本物の GitHub で revoke.sh を流し、書き込みの鍵を失効させます。記述が矛盾しており、並行セッションの鍵も失効させます。 |
I225.md「Danger Ops」と manual M-02 | イシューの Danger Ops 記述を、M-02 で控えの鍵を失効させる旨に合わせて直します。 |
| Warning | 外部挙動依存の未実証 | --strict-mcp-config と --mcp-config .mcp.json の併用、および tmux の中の claude の /mcp 表示は、実装後の M-03・M-04 で初めて確かめる流れです。計画段階のスパイクがなく、実装ステップの前倒しもありません。稼働中のセッションで確かめられます。 |
plan §4-5、§8 のリスク表、manual M-03・M-04 | 実装の最初のステップで M-04 相当を実証し、結果を調査結果に記録します。 |
| Warning | コマンド衛生 | M-01 は複数コマンドを → でつなぎ、リダイレクトと grep -c を組み合わせています。M-01 の合否は grep -c ghs_ の出力値が 0 かどうかの目視です。合格時に非ゼロ終了する判定になります。 |
manual M-01 | ! grep -q ghs_ <file>(合格=exit 0)に直し、コマンドを分けます。 |
| Info | 保守 | 台帳 backlog(I223 F11・F12、I195 F5)の削除と、adversarial-review.sh の編集が同梱されています。範囲外ではありませんが、変更点が散らばります。 |
plan §4-7 | 対応は任意です。 |
セキュリティ、P3(DB)、P9 の観点は、次のとおり問題ありません。
- 入口の判定は argv で行い、鍵の欄を取らず、
error欄も出さない設計です。 - P3 は DB 変更なしのため対象外です。
- P9 は個人情報を扱わないため対象外です。
- 新しい安全装置の作り込み(P8)はなく、見張りも変えない設計です。
高リスク判定
判定: No
該当条件: なし。変更対象は scripts/claude/gh-app/ と scripts/claude/ のハーネスと runbook です。.github/*・pretooluse_guard.py・.claude/settings*.json には触れません。
指摘を直してから計画レビュー(plan-review 段階)をやり直す。
VERDICT: BLOCKER
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
計画書レビュー [I225] ── 2026-11-06 00:00
判定: ✅ 完了
レビュー指摘一覧
| 重大度 | 観点 | 指摘内容 | 該当箇所 | 対応 |
|---|---|---|---|---|
| Warning | P4 | TC-03 の合否に「標準エラーに jq のエラーが無い」という目視の項目がある。合否は exit code だけにするほうがよい。例: GH_APP_READONLY= GH_APP_DISABLE=1 gh auth status --json hosts --jq '…' 2>&1 >/dev/null の出力が空で、かつ exit 0。出力の中身(osushi0404-bot … error)もこの端末の保存されたログインに依存する。 |
auto_test TC-03 | 修正推奨 |
| Warning | P4 | M-03 の期待結果が「No MCP servers configured などの表示」で曖昧。tmux の中の claude(対話)で --strict-mcp-config が効く点は、計画自身が M-03 で初めて実証すると書いている。実証手段と実施環境は明記されているので Blocker にはしない。判定文言を、実際に出た文言を実結果に転記して決める形にしたほうがよい。 |
manual_test M-03 / plan 調査結果 | 修正推奨 |
| Warning | P1 | 4-1 の入口の判定は gh auth status が引数の 1・2 番目にあるときだけ見る。gh -R x auth status のようにグローバルオプションが前にあると置き換えが効かない。普通の書き方の事故が対象で、静的な検査(G10)も併用するので許容できる。未対応であることを一文残すとよい。 |
plan 4-1 | 修正推奨 |
| Info | BP | tmux の -e は 3.2 以上が必要。この端末は 3.4 で、tmux 3.2 未満は台帳 F10 として残す扱い。判断は妥当。 |
plan 4-6 / §9 | 対応任意 |
| Info | P5 | M-02 は本物の GitHub に流して控えの鍵を失効させる。他セッションへの影響は、イシューの Danger Ops と M-02 の備考に明記済み。 | I225 Danger Ops / M-02 | 対応不要 |
観点ごとの確認:
- P1(要件適合性): 問題なし。
revoke.sh(--stdinを含む)は F13 の具体化で、イシューの実装対象にも載っている。受け入れ条件 2 の範囲の絞り込みは §9 に理由つきで記録されている。 - ベストプラクティス: 問題なし。
- 入口の判定は argv で行い、シェルの文字列を読まない。見張りは変えない。
- 検査対象は決まりの置き場に絞られている。
- 決定論テストは、壊れても気づきにくい所(G7〜G10・T1)に限られている。
- 検証コマンドは単体で、
git checkoutによる取り消しもない。
- セキュリティ:
- 鍵の値は引数・画面に出さない(環境変数と標準入力で渡す)。
errorの欄は出さない。- 失効が確認できなければ控えを消さず exit 1 にする。
--strict-mcp-configで最小権限にする。- 新規パッケージの追加はない。
- P4(テスト妥当性): G7〜G10 に FG があり、偽物の
ghで鍵の漏れと終了コードの 0・1・2 を確かめている。 - P3(データ整合性): 対象外(DB・API なし)。
- P5(運用性): 切り戻しは
install.shのバックアップから戻せる。 - P8(コスト・保守負荷): 入口は単純な argv の規則だけにしてあり、精密なガードを作り込んでいない。GitHub 側の最後の守りは変わらない。
- P9(プライバシー): 対象外。
- Claude Code ベストプラクティス:
.claude/skills/などの指示ファイルの変更はないので対象外。
高リスク判定
判定: No
該当条件: なし(変更は scripts/claude/・docs/runbooks/ のハーネスだけ。.github/*・.pre-commit-config.yaml・.secrets.baseline・pretooluse_guard.py・.claude/settings*.json は触らない)
推奨: 実装(implement 段階)へ。
VERDICT: OK
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
決定論ゲート実行結果(code-review.sh 自動注入)
(決定論ゲート宣言なし)- 高リスク判定: NO(計画レビュー=NO / path=NO / 台帳の目印=NO)
-
台帳(full・1 周目): OK(code-reviewer の VERDICT=OK・合否に使わない)
-
omission-lint: HIGH
-
FINAL VERDICT(gate/omission/LLM 合成): HIGH
コードレビュー [I225] ── [2026-11-06 12:00]
受け入れ条件の照合
| # | 受け入れ条件 | 実装状況 | 備考 |
|---|---|---|---|
| 1 | --json・-t なしの gh auth status を入口で流すと、鍵の欄が出ず名義・出どころ・状態だけが出る |
✅ 実装済み | gh-app/gh の置き換えを確認した。G8 の実走結果は決定論ゲート欄に無い。ゲート欄は「決定論ゲート宣言なし」で、omission-lint: HIGH とだけ出ている。 |
| 2 | 決まりの置き場に --json なしの gh auth status を書くと静的な検査で落ちる |
✅ 実装済み | G10 を追加した。ただし gh auth token と複数行の書き方は検査の対象外(F6)。 |
| 3 | 失効の手順が漏れた鍵そのものを失効させ、2 つの控えを消す形になっている | revoke.sh と --stdin を実装した。ただし失効の確認が 401 だけを根拠にしており、DELETE の成否を見ていない(F1)。 |
|
| 4 | 古い鍵の点検コマンドをそのままコピーして流せる | ✅ 実装済み | 表の外のコードブロックに出し、GH_APP_READONLY= と .tokenSource を足した。 |
| 5 | claude -p・tui-capture.sh が MCP・PATH の違いで読み取りだけの鍵を迂回しない |
✅ 実装済み | 起動の行に --strict-mcp-config を足し、tmux に -e PATH= を足した。 |
| 6 | 既存のハーネステスト・CI がすべて pass する | 注入された決定論ゲート欄に実 exit code の記録が無く、omission-lint: HIGH とだけ出ている。この内容は読み取れていない。CI の結果で確認が要る(F7)。 |
台帳
FINDING: F1 SEV=Medium STATUS=open FILE=scripts/claude/gh-app/revoke.sh LINE=20-25 SECURITY=yes STOP=- | revoke_one は DELETE の成否を見ず、続く読み取りが HTTP 401 なら「失効を確認」とする。一度も有効でなかった鍵(末尾を伏せた・打ち間違い・すでに失効済み)でも成功扱いになる | 再現: revoke.sh --stdin に末尾を欠いた鍵を渡す → DELETE は失敗し、読み取りは 401 → 「渡された鍵: 失効を確認しました」と出て exit 0。本物の鍵は有効なまま残る
FINDING: F2 SEV=Low STATUS=open FILE=scripts/claude/gh-app/gh LINE=28-37 SECURITY=no STOP=- | 置き換えた auth status は hosts が空(ログインなし)のとき、何も出さず exit 0 になる。元の gh は「ログインしていない」と出して exit 1 にする | 再現: GH_APP_DISABLE=1・保存されたログインなしで gh auth status → 出力なし・exit 0
FINDING: F3 SEV=Low STATUS=open FILE=scripts/claude/gh-app/gh LINE=22-23 SECURITY=no STOP=- | json="$(… --json hosts)" || exit $? により、本物の gh が非 0 で終わると取得済みの JSON を捨てる。空や JSON でない出力のときは Python のトレースバックが出る | 再現: 本物の gh が --json 付きで exit 1 を返すと、標準エラーの案内 1 行だけで状態の行が出ない
FINDING: F4 SEV=Low STATUS=open FILE=docs/runbooks/plan-writing-rules.md LINE=- SECURITY=no STOP=- | github-app-setup.md は決まりの正を plan-writing-rules.md としている。しかしその側に --strict-mcp-config・tmux の PATH・G7 の記述が足されていない | 再現: 新しい起動の行を足す人が plan-writing-rules.md だけを読むと --strict-mcp-config を付け忘れ、CI の G7 で初めて気づく
FINDING: F5 SEV=Low STATUS=open FILE=scripts/claude/gh-app/revoke.sh LINE=46-52 SECURITY=yes STOP=- | 失効の確認後に rm -f で控えを消すまでの間に、並行する gh が控えを取り直して書き込むと、失効していない新しい鍵の控えを消してしまう | 再現: 失効の確認と rm の間に別の gh 呼び出しが token を書き換える → 新しい鍵の控えが消えて「失効を確認」と表示される
FINDING: F6 SEV=Low STATUS=open FILE=scripts/claude/tests/test_i223_gh_app.sh LINE=- SECURITY=yes STOP=- | G10 は文字列 gh auth status だけを見る。鍵を丸ごと出す gh auth token や、\ で複数行に分けた --json 付きの書き方は扱えない。前者は取りこぼし、後者は誤検出になる | 再現: 手順書に `gh auth token` を書いても G10 は通る
FINDING: F7 SEV=Medium STATUS=open FILE=- LINE=- SECURITY=no STOP=- | 決定論ゲート欄が「宣言なし」で、omission-lint: HIGH の内容が分からない。ゲートの実 exit code の証跡が無い | 再現: ゲート欄に実 exit code が無いため確認できない。omission-lint の指摘を確認する
REVIEWED_COMMIT: 446e786
RISK: NO
VERDICT: HIGH
台帳(累積・スクリプトが書く)
LEDGER: F1 SEV=Medium STATUS=open SCOPE=delta KIND=harness STOP=- REPRO=yes RISK=- SECURITY=yes FILE=scripts/claude/gh-app/revoke.sh | revoke_one は DELETE の成否を見ず、続く読み取りが HTTP 401 なら「失効を確認」とする。一度も有効でなかった鍵(末尾を伏せた・打ち間違い・すでに失効済み)でも成功扱いになる
LEDGER: F2 SEV=Low STATUS=open SCOPE=delta KIND=harness STOP=- REPRO=yes RISK=- SECURITY=no FILE=scripts/claude/gh-app/gh | 置き換えた auth status は hosts が空(ログインなし)のとき、何も出さず exit 0 になる。元の gh は「ログインしていない」と出して exit 1 にする
LEDGER: F3 SEV=Low STATUS=open SCOPE=delta KIND=harness STOP=- REPRO=yes RISK=- SECURITY=no FILE=scripts/claude/gh-app/gh | json="$(… --json hosts)" || exit $? により、本物の gh が非 0 で終わると取得済みの JSON を捨てる。空や JSON でない出力のときは Python のトレースバックが出る
LEDGER: F4 SEV=Low STATUS=open SCOPE=delta KIND=harness STOP=- REPRO=yes RISK=- SECURITY=no FILE=docs/runbooks/plan-writing-rules.md | github-app-setup.md は決まりの正を plan-writing-rules.md としている。しかしその側に --strict-mcp-config・tmux の PATH・G7 の記述が足されていない
LEDGER: F5 SEV=Low STATUS=open SCOPE=delta KIND=harness STOP=- REPRO=yes RISK=- SECURITY=yes FILE=scripts/claude/gh-app/revoke.sh | 失効の確認後に rm -f で控えを消すまでの間に、並行する gh が控えを取り直して書き込むと、失効していない新しい鍵の控えを消してしまう
LEDGER: F6 SEV=Low STATUS=open SCOPE=delta KIND=harness STOP=- REPRO=yes RISK=- SECURITY=yes FILE=scripts/claude/tests/test_i223_gh_app.sh | G10 は文字列 gh auth status だけを見る。鍵を丸ごと出す gh auth token や、\ で複数行に分けた --json 付きの書き方は扱えない。前者は取りこぼし、後者は誤検出になる
LEDGER: F7 SEV=Medium STATUS=open SCOPE=delta KIND=harness STOP=- REPRO=yes RISK=- SECURITY=no FILE=- | 決定論ゲート欄が「宣言なし」で、omission-lint: HIGH の内容が分からない。ゲートの実 exit code の証跡が無い
LEDGER_ROUND: 1
止める指摘(スクリプトが決めた・fix-loop が直すのはこれだけ)
(再現は本文の同じ番号の FINDING 行)
組み込みのレビューの出力(公式・参考)
組み込み /code-review の指摘
Permission allow rule "Read()" adds nothing to Read's default, which already runs without asking in the working directories. "Read" alone allows every path. Older versions of Claude Code treat "Read()" as "Read", and this version will too if Anthropic turns this change off.
Permission allow rule "Grep()" adds nothing to Grep's default, which already runs without asking in the working directories. "Grep" alone allows every path. Older versions of Claude Code treat "Grep()" as "Grep", and this version will too if Anthropic turns this change off.
Permission allow rule "Glob()" adds nothing to Glob's default, which already runs without asking in the working directories. "Glob" alone allows every path. Older versions of Claude Code treat "Glob()" as "Glob", and this version will too if Anthropic turns this change off.
[
{
"file": "scripts/claude/gh-app/revoke.sh",
"line": 22,
"summary": "revoke_one counts any HTTP 401 on the follow-up read as proof the token was revoked, and it ignores the result of the DELETE. A string that was never a valid token (truncated, masked or mistyped) therefore 'passes' too.",
"failure_scenario": "The leak this script exists for is `gh auth status`, which masks the tail of the token. The user pastes the visible part, or makes a typo, into `revoke.sh --stdin`. DELETE fails because the token is invalid, the GET returns 401, and the script prints '渡された鍵: 失効を確認しました' with exit 0. The real leaked token stays valid for up to an hour. Fix: require the DELETE to return 204, or check that the token works (200) before revoking it."
},
{
"file": "scripts/claude/gh-app/gh",
"line": 32,
"summary": "The rewritten `auth status` exits 0 with no output when the JSON has no accounts. Plain `gh auth status` prints 'You are not logged into any GitHub hosts' and exits 1.",
"failure_scenario": "With `GH_APP_DISABLE=1` and no stored login, `gh auth status` returns `{\"hosts\":{}}`. The wrapper prints nothing and exits 0, so scripts or people reading the exit code think authentication succeeded."
},
{
"file": "scripts/claude/gh-app/gh",
"line": 23,
"summary": "`json=$(... --json hosts) || exit $?` throws away the captured JSON whenever the real gh exits non-zero. Empty or non-JSON output also crashes `json.load` with a Python traceback.",
"failure_scenario": "If gh exits 1 in --json mode because an account is in the error state (or a host is unreachable), the user sees only the stderr banner, with no host/login/state lines. That is exactly the case they need to diagnose. G8's stub always exits 0, so this path is never tested."
},
{
"file": "scripts/claude/tui-capture.sh",
"line": 47,
"summary": "Passing `--strict-mcp-config` with no `--mcp-config` also drops the project's `.mcp.json` (Playwright), so the session that is supposed to show what a real interactive session looks like now differs from one.",
"failure_scenario": "A test-gate check uses tui-capture to look at MCP-related screens: the `/` suggestions for MCP prompts, the MCP server status, or Playwright tool approval dialogs. None of it appears, so the result is wrong or falsely reported as 'not present'."
},
{
"file": "scripts/claude/test-session.sh",
"line": 8,
"summary": "test-session.sh now always passes `--strict-mcp-config`, which silently turns off the project `.mcp.json` (Playwright MCP) for every manual test session.",
"failure_scenario": "Running `bash scripts/claude/test-session.sh \"<a prompt that uses Playwright MCP>\"` as before (frontend-verify style) now fails with the tool unavailable or denied. The runbook does not say that `--mcp-config .mcp.json` must now be passed explicitly."
},
{
"file": "docs/runbooks/plan-writing-rules.md",
"line": 90,
"summary": "github-app-setup.md says the authoritative rule lives in plan-writing-rules.md, but that file was not updated: it still says only GH_APP_READONLY=1 and G6, with nothing about `--strict-mcp-config`, the tmux PATH, or G7.",
"failure_scenario": "Someone adding a new Claude launch line reads the rule's authoritative source (plan-writing-rules.md), adds only GH_APP_READONLY=1, and leaves out `--strict-mcp-config`. They only find out when G7 fails in CI. The two documents disagree on what the rule is."
},
{
"file": "scripts/claude/gh-app/revoke.sh",
"line": 50,
"summary": "The cache file is deleted with `rm -f` after the revocation check. If another gh call (via gh-app-token) rewrites the cache in that window, the new valid token's cache is deleted without being revoked.",
"failure_scenario": "A session that is running gh concurrently gets a 401 and refetches, and gh-app-token writes the new token in the gap between revoke_one and rm. revoke.sh deletes that fresh cache and reports it as '失効を確認して控えを消しました'. A token that was never revoked stays live, and the message is not accurate. Fix: check that the cache contents are unchanged before deleting."
},
{
"file": "scripts/claude/tests/test_i223_gh_app.sh",
"line": 381,
"summary": "G10 only matches the literal string `gh auth status` and checks flags only up to the end of the line. `gh auth token`, which prints the whole token, and invocations through a variable such as `\"$GH\" auth status` are not covered. A multi-line command continued with `\\` gets flagged even when it does have --json.",
"failure_scenario": "If `gh auth token` is added to a runbook or script, G10 passes and the full token can end up on screen or in the transcript. Meanwhile, a correct command split across lines as `gh auth status \\` / ` --json hosts` fails CI."
},
{
"file": "scripts/claude/check-permission-prompt.sh",
"line": 72,
"summary": "For mcp-kind checks, `--strict-mcp-config` drops the user-level MCP settings, so approval prompts for MCP tools defined there can no longer be judged.",
"failure_scenario": "Running `check-permission-prompt.sh mcp mcp__<a user-level server>__tool` now returns 'cannot judge' (2) or a wrong result because the tool does not exist. Before this change it judged it under the same conditions as a real session."
}
]組み込み /security-review の指摘
(実行していない: パス判定 NO)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
診断レビュー [I225]
指摘一覧
| 重大度 | 観点 | 指摘内容 | 該当箇所 |
|---|---|---|---|
| Info | 対応方針 | 見出しを直すと、6 本のテストがそれぞれ GATE_TIMEOUT の既定値 120 秒の制限付きで実走される。test_i193_official_flow.sh(174 件)と test_i197_adversarial_process.sh(113 件)は件数が多く、遅いマシンでは時間切れ(exit 124)になりうる。implement で手元の所要時間を測った記録は診断メモに無い。時間切れも「正しい止まり方」ではあるが、見出しを直す前に所要時間を確かめておくと手戻りを減らせる。 |
code-review.sh:381(GATE_TIMEOUT 既定 120 秒)、I225_auto_test.md:19-26 |
| Info | 根本原因 | 根本原因は実コードで確認できた。I225_auto_test.md:18 は ## 決定論ゲート で、code-review.sh:330 と :421 は ## 決定論ゲート(自動実走) で探す。見出しが一致しないので「宣言なし」になる(:412)。宣言の外の bash scripts/claude/tests/*.sh は omission-lint が HIGH にする。症状の言い換えにはなっていない。 |
code-review.sh:330,412,421 |
| Info | 対応方針 | 案 A(見出しを 1 行直す)が最小で、テンプレートどおりで、台帳 F7(証跡が無い)も同時に解ける。案 B(証跡が無くなる)と案 C(範囲外)を採らない理由も妥当。6 本はすべて bash scripts/claude/tests/*.sh の形で、classify_gate の ALLOW に入る(メタ文字なし・../ なし)。 |
code-review.sh:363 |
影響調査の網羅性評価
- 同型バグ(同じ見出しの書き間違い)は
grep "^## 決定論ゲート" docs/testsで確認した。誤っているのはdocs/tests/open/I225_auto_test.md:18の 1 件だけだった。closedの約 45 件とテンプレートはすべて(自動実走)付きで、他に漏れはない。 - 呼び出し箇所は、見出しを読む
code-review.shの 2 か所(:330、:421)が診断メモと一致する。gate-check.sh と test-gate への波及も確認済みで、見出しの直しは記録の変更として次の review-gate が見直す。 - 関連機能への波及はない。
- 欠落は、上の Info にある所要時間の確認だけで、重大なものではない。
VERDICT: OK
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
概要
I225: I223 のレビューの残り(F7・F9・F13・F14・F15)を直す。GitHub App の長い鍵が
--jsonなしのgh auth statusで画面に出る問題を、入口の置き換えと CI の静的な検査の 2 か所で止める。鍵が出たときの失効をスクリプトにし、テスト用のセッションが MCP・PATHの違いで読み取りだけの鍵を迂回する抜け道を塞ぐ。関連イシュー
Closes #415
変更点
scripts/claude/gh-app/gh:--json・-t/--show-tokenなしのauth statusを、鍵の欄の無い--json hostsの表示に置き換える(stateがすべて success なら 0)scripts/claude/gh-app/revoke.sh(新規): 控えの 2 つの鍵(token・token-readonly)を失効させ、HTTP 401 を確かめてから控えを消す。--stdinで控えに無い鍵も失効させるscripts/claude/の Claude の起動の行すべてに--strict-mcp-config。tui-capture.shは tmux に入口のあるPATHも渡すtest_i223_gh_app.shに G7(MCP の制限の付け忘れ)・G8(置き換え)・G9(失効)・G10(鍵を出す書き方の静的な検査)と各 FG。test_tui_capture.shの T1・FG-T1bgithub-app-setup.md(鍵が出たときの手順)・harness-audit.md(古い鍵の点検コマンドを表の外へ)pretooluse_guard.py・.claude/settings.json・.github/は変えていないテスト確認
docs/reviews/closed/I225_code_review_20261106_0057.md)docs/tests/closed/I225_manual_test.md・M-01〜M-04 すべて OK・すべて Claude が実施)ロールバック手順
この PR を revert し、
bash scripts/claude/gh-app/install.shを流し直す(前の版は~/.cache/github-app/backup/)。参照ドキュメント
docs/plans/closed/plan_I225.mddocs/reviews/closed/I225_review.md🤖 Generated with Claude Code