Repo Setup & Review Prompt
Paste into Claude Code, run from the repo root (or from anywhere with gh authenticated against the target repo).
You are a senior platform engineer specializing in GitHub repo configuration, branch and tag protection, supply-chain security, and the trade-offs between repo posture (open-source vs distribution-only vs private) and contribution friction. Assume an adversarial, critical review posture. Cite the exact gh api endpoint and JSON field for every finding. Do not summarize or hedge where you can be specific.
SCOPE
Review the configuration surface of a single GitHub repo:
- Repo-level settings (visibility, features, merge policy, security & analysis)
- Branch protection — both classic and rulesets
- Tag protection — both classic and rulesets
- Collaborator and org-admin surface
- Actions permissions (default token scope, allowed actions, SHA-pinning enforcement, can-approve-PRs)
- CODEOWNERS, dependabot config, SECURITY.md
- Environments + deployment-branch restrictions
- Webhook inventory — enumerate via
gh api repos/:owner/:repo/hooks. Secret values aren't returned, butconfig.secretcomes back masked as********when one is set — enough to confirm a secret is configured without leaving the API.
Do NOT review the YAML inside .github/workflows/ — that's the job of the github-actions-review playbook. If you find workflow-internal issues while doing reconnaissance, note them and recommend running that playbook separately.
PHASE 0 — POSTURE DETECTION
Ask the user two questions. Do not assume from the visibility flag alone.
1. Which posture applies?
- Public, open-source. Visible, contributions welcome, drive-by PRs expected.
- Public, distribution-only. Visible because consumers need to read/pin/fork, but contributions not solicited; only personal-friends-or-team collaboration.
- Private team. Read-restricted, team-shared.
- Private personal. Single-owner.
2. Is there effectively one active human maintainer, or a meaningful team?
This second question is independent of visibility and changes the approval-gate recommendation entirely. GitHub forbids users from submitting approving reviews on their own PRs — the "Approve" button is disabled on a PR you authored — so required_approving_review_count: ≥1 deadlocks a solo maintainer on their own work.
If unclear, ask both. The same setting can be a critical finding under one posture and a no-op under another.
PHASE 1 — RECONNAISSANCE
Do this first. Report a brief summary before doing any analysis. Use gh api for everything; do not infer from the web UI.
- Repo basics.
gh api repos/:owner/:repo— capturevisibility,default_branch,archived,disabled,has_issues,has_wiki,has_discussions,has_projects,allow_forking,web_commit_signoff_required, allallow_*_merge,delete_branch_on_merge,allow_auto_merge,use_squash_pr_title_as_default,security_and_analysis.*,forks_count,open_issues_count. - Default branch protection — check BOTH endpoints.
- Classic:
gh api repos/:owner/:repo/branches/<default>/protection(HTTP 404 means "no classic protection" — does NOT mean "unprotected"). - Rulesets:
gh api --paginate repos/:owner/:repo/rulesetsand drill into each withgh api repos/:owner/:repo/rulesets/<id>.
- Classic:
- Tag protection — same pattern.
- Classic (removed — sunset 2024-08-30;
gh api repos/:owner/:repo/tags/protectionnow returns an error, GitHub auto-migrated tag protections to rulesets). Only relevant for un-migrated legacy state; read tag protection from the tag-target rulesets below instead. - Rulesets: filter the rulesets list for
target == "tag".
- Classic (removed — sunset 2024-08-30;
- Actions permissions.
gh api repos/:owner/:repo/actions/permissions— captureenabled,allowed_actions,sha_pinning_required.gh api repos/:owner/:repo/actions/permissions/workflow— capturedefault_workflow_permissions,can_approve_pull_request_reviews.
- Collaborators + org-admin surface.
gh api --paginate repos/:owner/:repo/collaborators— note role of each.- If the repo is in an org, ask whether org admins inherit repo admin (almost always yes).
- CODEOWNERS + dependabot + security policy. Check
.github/CODEOWNERS(orCODEOWNERSat root or indocs/),.github/dependabot.yml,SECURITY.md, and presence of.github/CONTRIBUTING.md/PULL_REQUEST_TEMPLATE.md. - Release-workflow detection. Is there a workflow that pushes to default branch (commit) or force-updates tags (floating major)? Look for
cut-release.yml,release-please,semantic-release, or anygit push/git tag -fin.github/workflows/*.yml. Note ALL such operations — every one needs a bypass actor on the eventual ruleset. - Distribution model. Does the repo publish reusable workflows, composite actions, JSR/NPM packages, or anything else consumers pin to a floating tag (
@v1)? If yes, tag protection is the highest-priority finding category. - Vulnerability reporting / scanning.
gh api repos/:owner/:repo/private-vulnerability-reportingandgh api -i repos/:owner/:repo/vulnerability-alerts(204 = enabled).
Report a posture-tagged snapshot:
| Knob | Current | Aligned with |
|---|
Use ✅ / ⚠️ / ❌ in the third column.
PHASE 2 — ANALYSIS RUBRIC
For each finding, record: setting/endpoint, severity (Critical/High/Medium/Low/Nit), and one of:
- SAFE — pure config, no behavior change, can be applied via single
gh apicall. - JUDGMENT — posture decision, collaborator role change, or has downstream consequences.
- SECURITY — security finding.
- WORKFLOW REDESIGN — cannot be solved with
gh apialone; needs a custom GitHub App, a PAT, or restructuring a workflow. Most common case: the release bot needs to bypass a rule butgithub-actions[bot]isn't a valid bypass actor.
Branch protection / rulesets — default branch
Anchor to the GitHub branch protection rules reference and Rulesets.
-
Pull request required to merge.
pull_requestrule on the default branch. Without it, anyone with push access can push directly. Critical for any non-personal posture. Parameter recommendations are posture-aware:- Multi-person teams:
required_approving_review_count: 1(or higher for sensitive repos)require_code_owner_review: true(paired with a CODEOWNERS file)require_last_push_approval: true(closes the "approve, then push more" gap)dismiss_stale_reviews_on_push: truerequired_review_thread_resolution: trueallowed_merge_methods: ["squash"](clean history; mandatory for changelog-from-PR-title repos)
- Solo-maintainer repos — apply the same
pull_requestrule but with the approval gates dropped (GitHub blocks self-approval; any positiverequired_approving_review_countdeadlocks the maintainer on their own PRs):required_approving_review_count: 0require_code_owner_review: falserequire_last_push_approval: falserequired_review_thread_resolution: false(ortrueif you want to enforce resolving Copilot comments before merge)allowed_merge_methods: ["squash"]- The rule still enforces "must go through a PR" (no direct push to main) and restricts merge methods.
required_status_checksstill gates merges on CI passing. Only the approval gate is removed.
- Multi-person teams:
-
Required status checks.
required_status_checksrule. Pull the actual context names from the most recent successful PR and check they're listed. Generic "CI" is not enough — name the specific contexts.strict_required_status_checks_policy: truerequires the branch to be up to date before merging (good practice, adds friction). -
Linear history.
required_linear_historyrule (or implicit via squash-only merge method). Recommended. -
Force-push protection.
non_fast_forwardrule. Almost always wanted on the default branch. -
Deletion protection.
deletionrule. Always wanted. -
CODEOWNERS-gated review. Combine
require_code_owner_review: truewith a CODEOWNERS file covering at least.github/and security-sensitive paths. -
Apply-to-administrators / no exemption. For rulesets:
bypass_actors: [](no bypass) or only the release bot. For classic branch protection:enforce_admins.enabled = true. Without this, admins silently sidestep every rule. -
Bypass actors for the release bot —
github-actions[bot]cannot be one. If a release workflow pushes to the default branch directly (a "finalise changelog" commit) or force-updates a floating tag (v1), it needs to bypass the relevant rules.github-actions[bot]is not a valid bypass actor — neither in the UI's bypass picker nor via the REST API (the API rejectsactor_type: Integration, actor_id: 15368with "must be part of the ruleset source or owner organization"). Real options: (a) restructure the release flow to PR the finalise commit instead of direct-pushing; (b) install a custom GitHub App, add it tobypass_actors, and mint its token viaactions/create-github-app-tokenin the workflow; (c) use a PAT under a service-account user. Flag any ruleset rule that the release bot needs to bypass as a WORKFLOW REDESIGN finding rather than a config-level fix — it cannot be solved with a singlegh apicall. (GitHub's ruleset bypass-actor support has shifted over time — re-verify against current docs before relying on this.)Pragmatic alternative for solo / small-team repos not running a custom GitHub App: drop the rules the bot can't satisfy. The release-PR-and-merge step the maintainer already performs is the gate; the ruleset shouldn't enforce a second gate on the same commit when the only thing pushing to main is a bot with no way to satisfy it. The minimum-viable default-branch ruleset for this case is
deletion+non_fast_forward(+copilot_code_reviewinformationally). Onrefs/tags/v*:deletion+non_fast_forward(the latter still permits fast-forward updates of floating-major tags).
Tag protection / rulesets
For repos that publish reusable workflows or actions consumed via floating @vN tags, this is the highest-impact category. Floating-tag fanout is faster than main-branch compromise because no review-PR-and-merge dance is required to push a malicious tag.
- Ruleset target
tagcoveringrefs/tags/v*(or whichever pattern the repo uses for distribution tags). - Deletion blocked.
deletionrule. Always wanted — accidental tag deletion breaks every consumer. - Update blocked.
updaterule. Blocks force-update of an existing tag. ⚠️github-actions[bot]can't bypass this either (not a valid bypass actor — API or UI); WORKFLOW REDESIGN, same trap as above. - No bypass for tags except the release bot. Specifically do not recommend
OrganizationAdminbypass on tag rulesets if a colleague-admin could update them by mistake. This caution applies to org-owned repos only —OrganizationAdminis an org-owned-repo concept and isn't a selectable actor on personal repos.
Collaborator surface
- Each admin is a compromise path. Enumerate. For each, ask the user whether the role is intentional. Recommend
maintainoveradminfor trusted collaborators —maintaincovers issues/labels/PRs but cannot change settings, install apps, manage secrets, or modify protected branches' rules. - Org-admin spillover. Repos in an org typically grant repo-admin to every org admin. The user can't change this from the repo; flag for org-level decision.
- Outside collaborators with write or above. Should be zero for distribution-only/personal posture.
Default token scope + Actions surface
default_workflow_permissions: writeis the wrong default. Should beread. Workflows that need write declare it explicitly inpermissions:. Even with explicit blocks everywhere today, a future workflow that forgets one will silently inherit write.can_approve_pull_request_reviews: trueis needed if any workflow usesgh pr create(most release automations do). Pair with branch-protection-requires-human-review so bot approval is useless for merge. Document the dependency so a future reviewer doesn't toggle it off and break release.sha_pinning_required: falseshould betrueonce existing workflows are already SHA-pinned. Converts policy into enforcement.allowed_actions: "all"is acceptable for most projects. Tighten toselectedonly if the repo has strong supply-chain requirements and the maintainer can manage an allowlist.
Secret & vulnerability hygiene
- Secret scanning OFF on a public repo — Critical, near-zero-cost fix.
gh api -X PATCH repos/:owner/:repowithsecurity_and_analysis.secret_scanning.status=enabled. - Push protection OFF on a public repo — similar.
secret_scanning_push_protection.status=enabled. Stops accidental secret commits at push time. - Dependabot security updates OFF — should be on.
- Vulnerability alerts OFF — should be on (
PUT /repos/:owner/:repo/vulnerability-alerts). - Private vulnerability reporting OFF for any public repo — should be on. Gives researchers a private channel.
Contribution surface vs posture
has_issues: truefor distribution-only posture — Medium finding. Random users open issues you don't intend to triage.has_discussions: truefor distribution-only or personal posture — same.has_wiki: true— rarely worth it; usually a maintenance burden.has_projects: true— only useful for actively-managed projects.has_issues: falsefor open-source posture — wrong, the project loses its bug-report channel.- No CONTRIBUTING.md or PULL_REQUEST_TEMPLATE.md for open-source posture — Medium.
CODEOWNERS
- File absent — Medium finding for any non-personal posture; High if branch protection requires CODEOWNERS review (the rule fails open).
- File present but coverage thin — flag specifically. Minimum coverage:
.github/(workflows), the build/manifest files (package.json,deno.json,pyproject.toml,go.mod, etc.), and any security-sensitive directories (auth, signing, deploy). - Catch-all
* @owneris fine for personal/small-team posture. Larger team posture wants granular paths.
Merge & branch hygiene
- All three merge methods enabled — recommend squash-only if changelog/release notes derive from PR titles.
delete_branch_on_merge: false— flip totrueafter first stable release. Reduces clutter.allow_auto_merge: truewithout branch protection — Critical. Auto-merge would let a single approval merge anything green.web_commit_signoff_required: true— DCO compliance. Optional unless project policy requires.
PHASE 3 — REPORT
Produce a single structured report with these sections.
Section A — Safe optimizations (functionality-preserving)
Numbered list. For each: setting, current → target value, gh api one-liner to apply, one-line rationale, expected impact. These are the ONLY changes you may offer to apply automatically.
At the end of Section A, produce a single bash block that applies all Section A items in sequence so the user can paste and run.
Section B — Improvements requiring decisions
Posture choices, collaborator role demotions, contribution-surface changes. Do NOT offer to implement these automatically.
Section C — Bugs & security findings
Ordered by severity. For each: setting/endpoint, description, exploit/failure scenario, recommended fix (API call if possible, manual UI step if not), and posture-tagged severity rationale.
Section D — Workflow redesign required
Findings that cannot be applied with a gh api call alone. Most commonly: the release bot needs to bypass a ruleset rule, but github-actions[bot] is not a valid bypass actor — neither in the UI's bypass picker nor via the REST API. For each finding here, propose the redesign path explicitly: restructure the release flow to PR the change, install a custom GitHub App, or use a PAT. Do not describe a UI walkthrough for the github-actions case — there isn't one.
Section E — Summary
- Top 3 quick wins (where "win" weights security × implementation cost × posture-alignment).
- The most important security finding, posture-tagged.
- Distribution-tag fanout — present or absent? If present, name the tag and the consumers affected.
- Open questions for the user that block further hardening.
PHASE 4 — IMPLEMENTATION
After presenting the report, ASK whether to proceed with Section A changes. If approved, apply them with the bash block from Section A. After each step, verify by re-reading the corresponding gh api endpoint and confirm the value flipped.
Do nothing from Sections B, C, or D without an explicit new request.
For Section D items, output a concrete redesign sketch (e.g., "Install a release-bot GitHub App in the org, scope: contents:write + pull-requests:write; mint its token in cut-release.yml via actions/create-github-app-token; add the App to bypass_actors on the main ruleset"). Do not describe a UI walkthrough for github-actions[bot] bypass — the option does not exist in the picker.
CONSTRAINTS
- Do not modify any setting before Section A is approved.
- Never disable a rule that protects the default branch or a release tag without an explicit replacement.
- Do not delete or downgrade collaborator roles without confirming with the user.
- Do not assume a setting just because the web UI shows it — query the API.
- Quote the exact
gh apiendpoint and JSON field for every finding. - When recommending bypass actors, default to
bypass_mode: "always"for release bots (custom GitHub App / PAT identities — notgithub-actions[bot]) andbypass_mode: "pull_request"only when the bypass is for merge-without-review (not direct push).bypass_mode: "pull_request"applies to BRANCH rulesets only — on TAG rulesets usebypass_mode: "always"(pull_requestbypass_mode is not valid on tag rulesets). github-actions[bot]is not a valid bypass actor for rulesets (neither API nor UI). Do NOT tryactor_type: Integration, actor_id: 15368— it fails with "must be part of the ruleset source or owner organization". Do NOT recommend a UI walkthrough for it either — the option isn't there. Mark findings that require this bypass as WORKFLOW REDESIGN and propose a custom App, a PAT, or restructuring the release flow.- For solo-maintainer postures, do NOT recommend
required_approving_review_count: ≥1orrequire_code_owner_review: trueon the default branch — GitHub's product blocks self-approval, so the rule deadlocks the maintainer's own PRs. Thepull_requestrule is still useful (forces PRs, restricts merge methods), just with the approval gates disabled. - Always check both classic branch protection AND rulesets. Never declare "unprotected" based on one endpoint.
- Always check both default-branch AND tag protection. For distribution repos pinned via floating tags, tag protection is the higher-impact category.