GitHub Actionsのpermissions過剰設定をレビューでどう見抜くか
GitHub Actionsのpermissions過剰設定をレビューでどう見抜くか
GitHub Actionsのworkflowでは、GITHUB_TOKEN に与える権限を permissions で制御できる。
しかし実務では、動かすことを優先して広い権限を付けたままになっている構成をよく見る。
レビューで危ないのは、次のような設定だ。
- repository全体で
write-allを指定している contents: writeが不要なjobにも付いている- PR検証とリリース処理が同じ権限で動いている
- workflow内で外部Actionを使っているのに権限が広い
- 権限が必要な理由がコメントやjob名から読めない
この記事ではGitHub Actionsの使い方ではなく、
CI/CD構成の権限境界をレビューでどう確認するかを整理する。
まず止めたい設定
name: ci
on:
pull_request:
push:
branches: [main]
permissions: write-all
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run release@Reviewer: workflow全体で `permissions: write-all` が指定されており、test jobにも不要なwrite権限が付与されています。jobごとに必要最小限のpermissionsへ分けてください。この設定は、CIを動かすだけなら問題が見えにくい。
しかし、テストjobに書き込み権限は不要である。
レビューでは、workflowが成功するかだけでなく、
どのjobがどのリソースへ書き込めるべきかを確認する必要がある。
なぜ危ないのか
CI/CDはリポジトリの外側にあるように見えるが、実際には強い実行権限を持つ。
GITHUB_TOKEN の権限が広いと、workflow内のスクリプトやActionが次の操作をできてしまう。
- リポジトリ内容の書き換え
- releaseやtagの作成
- issueやpull requestへの書き込み
- packageの公開
- deploymentの更新
もちろん、これらが必要なjobもある。
問題は、必要なjobと不要なjobが同じ権限で動くことだ。
レビューで見るべきなのは、
成功させるための権限ではなく、失敗しても被害が広がらない権限である。
レビューで見たい3つの判断線
1. workflow全体ではなくjob単位で絞っているか
権限が必要なのは、一部のjobだけであることが多い。
テスト、lint、型チェックは通常 contents: read で足りる。
jobs:
test:
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
release:
permissions:
contents: write
packages: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run release@Reviewer: write権限が必要なのはrelease jobだけに見えます。workflow全体に付与せず、test jobは `contents: read`、release jobだけ `contents: write` のように分けてください。2. pull_requestで動くjobにwrite権限がないか
PR由来のコードを実行するjobは、特に慎重に見る。
外部コントリビューターやfork PRを扱うリポジトリでは、権限境界の意味が大きい。
@Reviewer: `pull_request` で実行されるjobにwrite権限が付いています。PRの差分コードが実行される前提では、検証jobは読み取り権限に限定してください。pull_request_target を使っている場合はさらに注意が必要だ。
これはベースリポジトリ側の権限で動くため、checkoutするコードと権限の関係を必ず確認したい。
3. 外部Actionに広い権限を渡していないか
workflow内で外部Actionを使う場合、そのActionはjobに付与された GITHUB_TOKEN 権限の影響を受ける。
そのため、権限を広くするほど信頼境界も広がる。
@Reviewer: 外部Actionを使うjobに `contents: write` が付与されています。このActionが書き込み権限を必要とする理由が読み取れないため、権限を絞るか、利用Actionの固定と必要権限を明示してください。Actionのバージョン固定も合わせて見るとよい。
@main や @master は変更され得るため、権限の広いjobでは特に避けたい。
改善例
PR検証とリリースを分け、権限をjob単位にする。
name: ci
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
release:
if: github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run releaseこの構成なら、レビューアーは次を確認しやすい。
- デフォルト権限が読み取りに寄っている
- PR検証jobにwrite権限がない
- release jobはpush時だけ実行される
- 書き込み権限の理由がjob名と処理内容から読める
- 権限変更の影響範囲がjob単位に閉じている
コメントで理由を残すべきケース
権限を絞っても、なぜその権限が必要か分かりにくい場合がある。
たとえば pull-requests: write は、コメント投稿やラベル更新に必要なことがある。
permissions:
contents: read
pull-requests: write # PRにテスト結果コメントを投稿するため@Reviewer: `pull-requests: write` が必要な理由がコメントで明示されている点は良いです。実際にPRコメント投稿以外に使っていないか、job内のActionと合わせて確認してください。権限は設定値だけでは文脈が見えにくい。
必要な場合は、短いコメントで理由を残すとレビューしやすい。
レビュー観点チェックリスト
permissions: write-allが使われていないか- workflow全体ではなくjob単位で権限を絞っているか
- test / lint / build jobは原則
contents: readにできないか pull_requestで動くjobにwrite権限がないかpull_request_targetとcheckout対象の組み合わせが安全か- 外部Actionに広い権限を渡していないか
- write権限が必要な理由がjob名やコメントで説明されているか
まとめ
GitHub Actionsの permissions は、CI/CDの安全性を決める重要な構成である。
レビューでは、workflowが動くかだけでなく、どのjobにどの権限が必要なのかを確認したい。
広い権限は、問題が起きたときの被害範囲を広げる。
読み取りで足りるjobは読み取りに絞り、書き込みが必要なjobだけに明示的に権限を与える構成を基本にしたい。