---
allowed-tools: Bash(gh api *) Bash(gh repo *) Bash(gh auth *) Read
argument-hint: '[--owner <name>] [--allow <repo,repo>] [--json]'
context: fork
description: 'Security-first audit of the per-repo GitHub setting "Allow GitHub Actions to create and approve pull requests" (can_approve_pull_request_reviews) across an account. Flags repos where Actions CAN approve PRs — a required-review bypass risk (OpenSSF) — unless you intentionally allow them. Read-only: it never changes settings; it prints the exact gh command for you to run. Use when you ask: "audit Actions PR permissions", "can GitHub Actions approve PRs?", "PR approval setting check", "Actions PR 権限監査", "review-bypass チェック". DO NOT USE FOR: creating PRs, changing branch protection, or writing code.'
effort: medium
license: MIT
model: claude-sonnet-4-6
name: gh-pr-perm-audit
---
# GitHub Actions PR-Approval Permission Audit

Find every repo where GitHub Actions can **create and approve** pull requests — a known way to
bypass required reviews — and report it security-first. `false` is the secure default; `true` is
an exposure to justify per repo. **Read-only**: this skill never changes settings; it prints the
exact command for you to run. See `references/openssf.md` for the why + sources.

## Setup Check

Run `gh auth status` — if not authenticated, output:
```
⚠️ gh CLI not authenticated. Run: gh auth login
```
and stop.

## Step 1: Resolve scope

- `--owner <name>`: audit that account. Otherwise: `OWNER=$(gh api user --jq .login)`.
- `--allow <repo,repo>`: comma-separated repos you INTENTIONALLY allow to have the setting `true`
  (e.g. a repo whose CI legitimately opens PRs via `GITHUB_TOKEN`). Anything not listed is expected
  to be `false`.

List repos (skip archived; they can't be changed):
```bash
gh repo list "$OWNER" --no-archived --limit 200 --json name --jq '.[].name'
```

## Step 2: Read the setting per repo

For each repo:
```bash
gh api "repos/$OWNER/$REPO/actions/permissions/workflow" \
  --jq '[.default_workflow_permissions, (.can_approve_pull_request_reviews|tostring)] | @tsv'
```
The second field is the audited flag.

## Step 3: Classify

| can_approve | in --allow? | Status |
|---|---|---|
| `true`  | no  | **RISK(unexpected)** — review-bypass exposure |
| `true`  | yes | OK(allowlisted) — intentional |
| `false` | —   | OK(secure-default) |
| (error) | —   | ERR(skip) — no access / archived |

## Step 4: Report

```markdown
# Actions PR-Approval Audit — <owner> — <DATE>

> Generated by github-flow-kit/gh-pr-perm-audit
> `false` = secure default. `true` = a workflow can self-approve PRs and bypass required reviews.

| Repo | default perms | can approve PR | Status |
|---|---|---|---|
| <repo> | read | false | OK(secure-default) |
| <repo> | read | true  | 🔴 RISK(unexpected) |

## 🔴 Exposed repos (un-allowlisted `true`): <N>
- <repo> — a workflow here can approve its own PR and merge past required reviews.
```

## Step 5: Recommend (you run the mutation — never auto-applied)

For each RISK repo, print the secure-default revert command and let the user run it:
```bash
# Revert to the secure default (recommended):
gh api -X PUT repos/<owner>/<repo>/actions/permissions/workflow \
  -f default_workflow_permissions=read -F can_approve_pull_request_reviews=false
```
If a repo legitimately needs Actions to **create** (not approve) PRs, prefer leaving this `false`
and using a dedicated GitHub App / fine-grained PAT for PR creation, or require a review from
someone other than the actor (so a self-approval still can't merge). Only enable intentionally:
```bash
gh api -X PUT repos/<owner>/<repo>/actions/permissions/workflow \
  -f default_workflow_permissions=read -F can_approve_pull_request_reviews=true
```

## Summary Output

```
✅ Actions PR-Approval Audit — <N> repos

  🔴 RISK (un-allowlisted true) : <n>
  🟢 secure-default (false)     : <n>
  ⚪ allowlisted true           : <n>

📋 Next: run the revert command above for each RISK repo, or add it to --allow if intentional.

⭐ Found this useful? Star → https://github.com/thinkyou0714/github-flow-kit
```

## Error Handling

| Code | Condition | Exit |
|---|---|---|
| GP-001 | gh not authenticated | 2 |
| GP-002 | owner has no repos | 0 |
| GP-003 | per-repo API error (no admin / archived) | skip that repo, continue |
| GP-004 | API rate limited | stop, show reset time |
