chrome-release-cls について
Chrome Releases のブログに記載されたセキュリティ修正を、Gerrit の変更リスト(CL)に対応付けるリサーチ用スキルです。リポジトリ履歴、Gitiles、Gerrit を検索し、コンポーネント固有の参照先や非公開変更も扱います。
主な機能
- 01CVE と Bug ID の抽出
- 02ローカルおよびリモート履歴の検索
- 03Gitiles と Gerrit による修正の特定
- 04コンポーネント固有リポジトリへの対応
- 05cherry-pick から元の変更を追跡
- 06深刻度別の修正報告
活用シーン
- 01Chrome のセキュリティリリースに含まれる修正の特定
- 02報告されたバグに対応する上流 CL の検索
- 03Chromium の roll コミット以外にあるコンポーネント修正の追跡
- 04最近の修正や非公開修正の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ electron/ electron --skill chrome-release-clsインストール後、Claude Code で/chrome-release-clsを入力して読み込まれたか確認します。
詳細
Chrome リリース → 修正 CL マッパー
Chrome Releases のブログ投稿にある各セキュリティ修正を、修正した Gerrit CL に対応付けます。
入力
$ARGUMENTS — https://chromereleases.googleblog.com/... の URL です。空の場合は、ユーザーに URL を尋ねてください。
手順
1. ブログ投稿から CVE → バグ ID のペアを抽出する
ブログの HTML では、バグ ID が <a> タグ内に隠れているため、まずタグを取り除きます。次を実行してください。
curl -sL "$URL" | python3 -c '
import sys, re, html
t = re.sub(r"<[^>]+>", " ", sys.stdin.read())
t = re.sub(r"\s+", " ", html.unescape(t))
seen = set()
for m in re.finditer(r"\[\s*(\d{6,})\s*\]\s*(Critical|High|Medium|Low)\s*(CVE-\d{4}-\d+):\s*([^.]+?)\.", t):
if m.group(3) in seen: continue
seen.add(m.group(3))
print(f"{m.group(3)}|{m.group(1)}|{m.group(2)}|{m.group(4).strip()}")
' > /tmp/cve_bugs.txt
cat /tmp/cve_bugs.txt
何も得られない場合は、ページの形式が変更された可能性があります。代わりに grep -oE 'CVE-[0-9]{4}-[0-9]+' と grep -oE 'crbug\.com/[0-9]+' を使い、出現順にペアにしてください。
2. 各バグの修正 CL を見つける
Chromium のチェックアウトと関連サブリポジトリの git 履歴を検索し、Bug: または Fixed: フッターでバグ ID を参照しているコミットを探します。次に Reviewed-on: の Gerrit URL を抽出してください。
コンポーネントのキーワードに基づくリポジトリの選択:
- ANGLE →
third_party/angle - Skia、Graphite →
third_party/skia - PDFium →
third_party/pdfium - Dawn →
third_party/dawn - V8、Turbofan、Maglev、Turboshaft →
v8 - それ以外 →
.(chromium/src)
候補のリポジトリで該当するものがない場合は、必ず . も検索してください。
cd /root/src/electron/src # chromium root (parent of electron/)
lookup() {
local bug="$1" repos="$2"
for repo in $repos . v8 third_party/skia third_party/angle third_party/pdfium third_party/dawn; do
local hits
hits=$(git -C "$repo" log --all --since='6 months ago' -E \
--grep="(Bug|Fixed):.*\\b${bug}\\b" --format='%H' 2>/dev/null | sort -u)
[[ -z "$hits" ]] && continue
while read -r h; do
git -C "$repo" log -1 --format='%B' "$h" | grep '^Reviewed-on:' | sed 's/^/ /'
echo " ↳ $(git -C "$repo" log -1 --format='%s' "$h")"
done <<<"$hits"
return 0
done
echo " (not found locally)"
}
/tmp/cve_bugs.txt を入力として使用します。正規のメイン CL として、[M1xx] がプレフィックスに付いていないコミットの件名を優先してください。[M1xx] が付いたものはブランチへのチェリーピックです。
3. 見つからない場合の対処
ローカルで該当するものが見つからないバグについては、以下を行います。
git -C <repo> fetch originを実行してから、--remotesを指定して再検索します(修正がチェックアウトより新しい可能性があります)。- gitiles の履歴を検索します — チェックアウトがあってもなくても機能し、認証も不要です。
refs/heads/mainとリリースのブランチ参照(chromium/srcの場合はrefs/branch-heads/<Chromium branch number>、v8/v8の場合はrefs/branch-heads/<V8 major.minor>、同様に chromium.googlesource.com 上のangle/angleとskia、さらにpdfium.googlesource.com/pdfium、dawn.googlesource.com/dawn、aomedia.googlesource.com/aom)を照会します。レスポンスは)]}'の行から始まります。gitiles のgrepはコミットメッセージ全体を対象に部分一致検索するため、ヒットした結果のBug:/Fixed:フッターを確認してください。gitiles_grep() { # gitiles_grep <host> <repo> <ref> <bug> e.g. chromium v8/v8 refs/branch-heads/15.2 558734727 curl -s "https://$1.googlesource.com/$2/+log/$3?format=JSON&n=50&grep=$4" | tail -n +2 | python3 -c ' import sys, json, re for c in json.load(sys.stdin).get("log", []): if re.search(r"^(Bug|Fixed):.*\b" + sys.argv[1] + r"\b", c["message"], re.M): print(c["commit"], c["message"].splitlines()[0]) ' "$4" }chromium/srcでは、必ず範囲を指定して履歴をたどってください。履歴全体を対象に範囲を指定せずgrepするとタイムアウトします(HTTP 502)。ref としてrefs/branch-heads/<previous milestone's branch>..refs/branch-heads/<this branch>とrefs/branch-heads/<this branch>..refs/heads/mainを渡します(ブランチ番号は Chrome バージョンの3番目の要素です。例:153.0.8010.x の場合は 8010。前のマイルストーンのブランチ番号はhttps://chromiumdash.appspot.com/fetch_milestones?mstone=<N-1>にあります)。サブリポジトリは範囲を指定せずにたどっても十分小さいため、数秒で完了します。ヒットすると sha、ref、および(コミットメッセージから)Reviewed-on:CL が得られます。Gerrit でその CL を表示できない場合でも、修正として報告してください。 - Gerrit に直接照会します:
curl -s "https://chromium-review.googlesource.com/changes/?q=bug:${BUG}&n=10" | tail -n +2 | python3 -m json.tool(skia-review、pdfium-review、dawn-review、aomedia-reviewも試してください)。 b/バグ形式(Skia、Graphite、Dawn): これらのリポジトリでは、コミットメッセージ内でBug: <id>フッターではなくb/<id>形式でバグを参照します。Gerrit のbug:クエリでは何も返されません。代わりにmessage:<id>検索を使用します。
コンポーネントが Dawn の場合は、curl -s "https://skia-review.googlesource.com/changes/?q=message:${BUG}&n=5" | tail -n +2dawn-review.googlesource.comに対しても同じ方法を適用します。- マージから元の CL をたどる:
[M1xx]のマージ CL しか見つからない場合は、CL の詳細を照会してcherry_pick_of_changeを調べ、元のメイン CL 番号を特定します。curl -s "https://chromium-review.googlesource.com/changes/${CL_NUM}?o=CURRENT_REVISION" | tail -n +2 | python3 -c " import sys, json d = json.load(sys.stdin) print(d.get('cherry_pick_of_change', 'none')) " - Gerrit でアクセス制限されている CL も、git では公開されている場合があります。 変更レコードとリポジトリには別々の ACL があり、変更が main と branch-heads に取り込まれた後も、CL が数日間非表示のままになることがあります。そのため、RESTRICTED と判定してよいのは、git の履歴(ローカルと、fetch 後の
--remotes)および gitiles の両方を調べても見つからない場合だけです。Gerrit で見つからないだけでは不十分です。 - それでも何も見つからず、バグがごく最近報告された場合(特に「Google Threat Intelligence」による報告、または実環境で悪用中とマークされている場合)、CL はまだアクセス制限されている可能性が高いです。推測せず RESTRICTED として報告し、再確認のためのフラグを付けてください(制限は通常、数時間以内に解除されます)。
4. 特殊なケース
-
Roll CL — スキップして上流の修正を探す: 修正が上流リポジトリに取り込まれるコンポーネント(PDFium、Dawn、Skia、Graphite、libaom、libvpx、ffmpeg)では、chromium-review で見つかるのは
Roll src/third_party/...コミットです。Roll CL を修正として報告しないでください。代わりに、コンポーネント独自の Gerrit インスタンスに直接照会し、実際に修正した CL を探します。- PDFium →
pdfium-review.googlesource.com(bug:またはmessage:クエリを使用) - Dawn →
dawn-review.googlesource.com(b/形式を使用するため、message:クエリを使用) - Skia/Graphite →
skia-review.googlesource.com(b/形式を使用するため、message:クエリを使用) - libaom →
aomedia-review.googlesource.com
上流の Gerrit インスタンスで結果が得られなかった場合に限り、Roll CL の報告に切り替えます。その場合は Roll CL を含め、実際の修正は上流で行われたものの、該当する CL を特定できなかったことを記載してください。
- PDFium →
-
1つのコミット本文に複数の
Reviewed-on:行がある場合:チェリーピックでは元の行に新しい行が追加されます。最初のReviewed-on:が元の CL です。 -
バグには、複数の異なる修正 CL(修正と追加の強化対応など)が存在する場合があります。その場合はすべて列挙してください。
5. 出力
重要度レベルごとに、次の形式の Markdown テーブルを作成します:CVE | Bug | Component | Fix CL (main)。バグへのリンクは https://crbug.com/<id> とします。ブランチのマージをすべて含めた生の出力を /tmp/cve_cls.txt に保存し、そのパスを明記します。