1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

初めてのCI/CD。AIレビューは仕込んだ問題を全部見つけたが、修正案の半分以上は壊れた(GitHub Actions + Claude Code)

1
Last updated at Posted at 2026-11-06

1. はじめに

会社では、PRを出すとAIが自動でコードレビューをしてくれます。初めて見たときは「なにこれ、すごい!」と思いました。

ところが、前の記事でCI/CDを勉強してからワークフローのファイルを見たら、なんと読めたんです。すごいと思っていたものも、基本は前回勉強したことと同じでした。

そうなると気になるのが、「これ、本当にどこまで見てくれるの?」です。これはもう、自分で試すしかありません。

PRを出すと、AIが自動でコードレビューをしてくれるしくみを、自分のリポジトリに入れて試しました。

知りたかったのは、次の3つです。

  • AIは、問題を見つけられるのか
  • その指摘は、正確なのか
  • チェックツールと併用したほうがいいのか

問題を9個仕込んだPRを出し、指摘された修正案を実際に適用して確かめました。

この記事は、初めてのCI/CDとチェックの記事の続きです。イベントやランナーなどの基本は、前の記事に書きました。

CI/CDとAIレビューは初心者です。間違いなどがあれば、コメントで教えていただけるとうれしいです。この記事の検証と執筆には、AI(Claude Code)の手も借りました。

2. 先に結論

AIのレビューは頼りになりました。ただし、修正案は人の確認が必要です。チェックツールとの併用もおすすめです。

知りたかったこと 結果
問題を見つけられるか 仕込んだ問題を9個すべて指摘した(約1分)
指摘は正確か 指摘の内容は正確だが、小さな誤りはある。適用できる修正案は9個中5個が、そのままでは壊れた
ツールと併用すべきか 併用したほうがいい。壊れた修正案は、html-validateとESLintが止めた

今回の小さな検証で見えた棲み分けは、次のとおりです。

担当 得意なこと 気をつけること
チェックツール 決まった間違いを、毎回同じように止める ツールの範囲しか見ない
AI 意味の食い違いに気づき、理由まで説明する 結果は毎回同じではなく、修正案も間違える
人 修正案を確かめ、仕様を決める AIの文章がもっともらしくても、そのまま信じない

小さなページを1つ使っただけの検証なので、「9個すべて」「9個中5個」といった結果が、ほかのコードでも同じになるとは限りません。自分の環境ではこうなった、という記録です。

3. 環境

前回の記事で作った、Cloudflare Workersへ公開するリポジトリに追加しました。

項目 内容
リポジトリ GitHubのPrivateリポジトリ(無料プラン)
レビュー anthropics/claude-code-action@v1
認証 Claudeの有料プラン(Pro・Maxなど)で作ったトークン(claude setup-token)

ルールのチェックに使ったツールは、次の3つです。

  • html-validate 11.18.0(最初から)
  • ESLint 10.14.0(7章で追加)
  • gitleaks 8.30.1(7章で追加)

機能の追加は、check.ymlとdeploy.ymlに手を入れずに、ワークフローをファイル1つ足すだけです。AIのレビューは意見なので、needs:にはつなぎませんでした。指摘があっても公開は止まりません。

4. 手順

(1) Claude GitHub Appを入れる

https://github.com/apps/claude を開いて、インストールします。このページは、自分のGitHubのメニューからはたどれませんでした。

最初はAll repositoriesが選ばれています。権限が広いので、Only select repositoriesに変えて、使うリポジトリだけを選びました。

01_select-repository.png

インストール後にGitHub の接続を完了という画面が出ましたが、これはclaude.aiとつなぐためのものです。押さずに進めても、レビューは動きました。

(2) トークンを作ってSecretsに入れる

Pro・Maxなどの有料プランの契約があれば、次のコマンドでトークンを作れます。API契約は使いませんでした。

claude setup-token

表示されたトークンを、リポジトリのSettings → Secrets and variables → Actionsに、CLAUDE_CODE_OAUTH_TOKENという名前で入れます。トークンはコードには書きません。

このトークンは、作った人のClaudeの契約に結び付いていて、レビューの実行にはその契約の利用枠が使われます。複数のリポジトリでSecretを共有する場合や、商品・サービスに組み込む場合は、公式はAPIキーを案内しています。条件は変わることがあるので、GitHub Actionsの公式ドキュメントと利用条件のページを確認してください。

(3) ワークフローを足す

公式の例を元に、.github/workflows/claude-code-review.ymlを作りました。

name: Claude Code Review

on:
  pull_request:
    branches: [main]
    types: [opened, synchronize, ready_for_review, reopened]

jobs:
  review:
    runs-on: ubuntu-latest

    permissions:
      contents: read
      pull-requests: write
      id-token: write

    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 1

      - name: Review with Claude
        uses: anthropics/claude-code-action@v1
        with:
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

          prompt: |
            REPO: ${{ github.repository }}
            PR NUMBER: ${{ github.event.pull_request.number }}

            このプルリクエストの変更をレビューしてください。
            観点: バグ、セキュリティ、アクセシビリティ、読みやすさ。
            レビューは日本語で書いてください。

            - 特定の行についての指摘は、インラインコメントで書いてください
            - 全体の所感は、gh pr comment で1件だけ書いてください
            - 問題がなければ、無理に指摘を作らないでください

          claude_args: |
            --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)"

前回と違うところは、次の4つです。

書き方 意味
types: PRで何が起きたときに動くか。ready_for_reviewは、下書きのPRをレビュー可能にしたとき
id-token: write ワークフローの札をもらう権限。この札を、Claude GitHub Appの鍵と交換する
prompt: Claudeへの指示。${{ }}は、ランナーに渡る前にGitHubが値へ置き換える
--allowedTools 使ってよい道具。許可ボタンを押す人がいないので、先に書いておく

このファイルを足したPRをmainにマージすると、次のPRからレビューが動きます。追加するPR自体はレビューされません(8章)。

5. AIは問題を見つけられるか(問題を9個仕込んだPR)

割り勘を計算するページを足すPRを作り、わざと問題を入れました。フェアなテストにするため、PRのタイトルには仕込みのことを書いていません。このPRは最後に閉じて、公開していません。APIキーは、作った偽の値です。

const EXCHANGE_API_KEY = "a1b2c3d4e5f60718293a4b5c6d7e8f90";

// サービス料は10%
const SERVICE_RATE = 0.08;

const params = new URLSearchParams(location.search);
const groupName = params.get("group");
if (groupName) {
  document.getElementById("group-title").innerHTML = groupName + "の割り勘";
}

async function showDollar(yen) {
  const res = await fetch("http://api.example.com/rate?base=JPY&key=" + EXCHANGE_API_KEY);
  const data = await res.json();
  document.getElementById("dollar").textContent = "約" + (yen * data.USD).toFixed(2) + "ドル";
}

document.getElementById("calc-button").addEventListener("click", () => {
  const total = document.getElementById("total").value;
  const people = document.getElementById("people").value;

  const service = total * SERVICE_RATE;
  const sum = total + service;
  const each = Math.floor(sum / people);

  document.getElementById("result").textContent = "1人あたり " + each + " 円";
  showDollar(each);
});

結果は、Check / htmlが緑で、Claudeは約1分で指摘を書きました。

02_review-summary.png

03_checks-green.png

指摘があると赤くなると思っていましたが、Claude Code Reviewは緑でした。この緑は、処理が失敗せずに終わったという意味で、問題がなかったという意味ではありません。そのため、重大な指摘があっても、Merge pull requestは押せる状態のままです。

# 仕込んだ問題 Claude
1 URLの値をinnerHTMLに入れるXSS 指摘
2 APIキーの直書き 指摘
3 http://でキーを送る 指摘
4 文字列の連結(total + service) 指摘
5 説明は10%、コードは0.08 指摘
6 divをボタンにしている 指摘
7 人数0・未入力のチェックがない 指摘
8 端数の切り捨て 指摘(インラインコメントの中)
9 通信エラーの処理がない 指摘

さらに、仕込んでいない問題も指摘しました。結果を読み上げソフトに知らせるaria-live、入力欄のminとstep、ボタンの文字のコントラスト不足(2回目のレビューのみ)です。

最後に、問題のないPRも試しました。1行足すだけのPRでは、インラインコメントは0件で、所感に「指摘事項はありません。LGTM」とだけ書かれました。prompt:に書いた「無理に指摘を作らないで」を外した場合とは、比べていません。

6. 指摘は正確か(修正案を適用すると、壊れた)

指摘は正確でしたが、Apply suggestionで適用できる修正案は、9個中5個がそのままでは壊れました。

この記事で一番伝えたいところです。直す内容は合っていますが、当てる行が合っていません。原因は分かっていません。

レビュー 修正案 結果
1回目 SERVICE_RATEを0.1に 問題なし
1回目 innerHTMLをtextContentに 問題なし
1回目 文字列連結の修正 宣言が重複して文法エラー
1回目 divをbuttonに 人数の入力欄が置き換わる
1回目 aria-liveの追加 計算ボタンのdivが消え、IDが重複する
2回目 SERVICE_RATEを0.1に 問題なし
2回目 入力欄の追加 問題なし
2回目 textContentに(8行目に当てた) ifを置き換えて文法エラー
2回目 文字列連結の修正(行を足した) 宣言が重複して文法エラー

PRで実際に適用したのは3個です(SERVICE_RATE、div、2回目の文字列連結)。1回目の文字列連結は、コピーに当ててChromeで文法エラーを確かめました。残りの5個は実際には適用せず、壊れるかどうかをコードを読んで確かめました(問題なし3個、壊れる2個)。

具体例です。divの修正案は「divをbuttonに変える」という内容ですが、実際に置き換えていたのは1行上の<input id="people">でした。

04_suggestion-wrong-line.png

これを適用すると、Check / htmlが赤になりました。

22:14  error  Duplicate ID "calc-button"  no-dup-id

AIの修正案の間違いを、前回作ったチェックが止めた形です。

ただし、html-validateが止めたのは重複IDだけです。人数の入力欄が消えたことは、2回目のレビューでClaudeが指摘しました。ボタンを押すとnullのエラーになる、と影響まで書かれています。ただし、自分の修正案が原因とは書いていません。

文章にも、小さな誤りがありました。

  • PRは未マージで、リポジトリもPrivateなのに、「既に公開されている」と書かれていた
  • "1000" + 80の結果が"10000.08"相当と書かれていた(正しくは"100080")

どちらも、2回目のレビューでは直っていました。毎回同じ結果になるわけではない、ということでもあります。

7. ツールと併用すべきか(チェックを増やして比べ直す)

ここまでの比較には、問題がありました。html-validateは.jsを読まないので、JavaScriptの問題を見つけられないのは当たり前です。

「チェックがHTMLだけだからでは?」と気づき、前回の記事の表にあったESLintとgitleaksをcheck.ymlに足して、比べ直しました。

  js:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v5
      - name: Install ESLint
        run: npm install --no-save eslint@10.14.0 @eslint/js@10.0.1
      - name: Lint JavaScript
        run: npx eslint --no-error-on-unmatched-pattern public/

  secrets:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v5
      - name: Install gitleaks
        run: curl -sSL https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_linux_x64.tar.gz | tar xz gitleaks
      - name: Scan for secrets
        run: ./gitleaks dir . --redact --no-banner

deploy.ymlは変えていません。check.yml全体を呼んでいるので、deployは増えたジョブも待ちました。

05_check-to-deploy.png

この状態で、宣言が重複する修正案を適用すると、ESLintが止めました。

21:9  error  Parsing error: Identifier 'total' has already been declared

gitleaksは、偽のAPIキーにも反応しました。ログにはleaks found: 1だけが出ます。同じ版を手元で詳しく動かすと、generic-api-keyというルールが1行目を示していました。本物かどうかは見ていません。

試した結果と、試していない予想を分けます。

問題 ツール 状態 Claude
修正案の宣言重複 ESLint 実測で検出 指摘
重複ID html-validate 実測で検出 指摘
APIキーの直書き gitleaks 実測で検出 指摘
消えた入力欄 html-validate 実測で見つからず 指摘
XSS ESLintのプラグイン 未検証 指摘
文字列の計算 tsc 未検証 指摘
divボタン、コントラスト axeなど 未検証 指摘
10%と0.08 思いつかない 未検証 指摘
端数の扱い 思いつかない 未検証 指摘

ツールを適切に選べば、実際に止められる範囲は広がりました。最後の2つのように、意味や仕様に関わる問題は、AIの得意分野に残りそうです。

8. 補足: 緑でも、レビューされていないことがある

Actionsは緑なのに、レビューが届かない場面は2回ありました。

場面 結果 ログに出ていたこと
ワークフローを追加した最初のPR 11秒で緑、コメントなし Skipping action due to workflow validation
試しに--allowedToolsを外したPR 約1分で緑、コメントなし "permission_denials_count": 5

1つ目は、mainと同じでないワークフローではレビューが飛ばされるためです。ログによると正常な動きで、マージすれば動き始めます。2つ目は、許可されていない操作を5回拒否されても、失敗にはなりませんでした。

06_green-no-review.png

コメントが付かないときは、緑でもログを見るのがおすすめです。

9. まとめ

AIのコードレビューは、問題を見つける相手としてはとても頼りになりました。ただし、ツールの代わりでも、人の代わりでもありません。

実際に使うなら、次の3つに気をつけたいと思います。

  1. 修正案は、赤い行を見てから適用する: 消える行が指摘された行か確かめる
  2. コメントがなければ、緑でもログを見る: スキップやpermission_denials_countを確かめる
  3. pushの回数に気をつける: pushのたびに同じ指摘が投稿し直され、PRが長くなる

AIの修正案をそのまま適用しても問題が解決しなかったときは、思わず「え???」となりました。指摘は頼りになりますが、一度は人が確認しないとダメだなと思いました。

その一方で、チェックツールを適切に選べば、ツールとAIはお互いに補い合えると感じました。

今回はAIへの指示文(prompt:に書いた文章)を変えて比べていません。指示の出し方で結果が変わる可能性はありますが、未検証です。ここは、いつか試してみたいです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?