diff --git a/skills/github-project/SKILL.md b/skills/github-project/SKILL.md index f74d759..fdde425 100644 --- a/skills/github-project/SKILL.md +++ b/skills/github-project/SKILL.md @@ -13,6 +13,7 @@ GitHub repository setup, configuration, troubleshooting, and best practices for - PR won't merge or shows BLOCKED status - Auto-merge not working for Dependabot/Renovate PRs +- Solo maintainer needs auto-approve for their own PRs - Branch protection or ruleset configuration needed - GitHub Actions workflow problems or CI failures - Setting up CODEOWNERS, issue templates, or PR templates @@ -32,6 +33,10 @@ gh api graphql -f query='query($owner:String!,$repo:String!,$pr:Int!){ }' -f owner=OWNER -f repo=REPO -F pr=NUMBER --jq '.data.repository.pullRequest' ``` +### Solo Maintainer: PRs Stuck on REVIEW_REQUIRED + +Solo maintainer projects MUST have auto-approve. Use `assets/pr-quality.yml.template` and keep `required_approving_review_count >= 1`. See `references/auto-merge-guide.md` for full setup. + ### Auto-merge Not Working ```bash @@ -59,7 +64,7 @@ gh run rerun RUN_ID --repo OWNER/REPO | Repository file layout and conventions | `references/repository-structure.md` | | Branch migration (master to main) | `references/branch-migration.md` | | Dependabot/Renovate configuration | `references/dependency-management.md` | -| Auto-merge troubleshooting | `references/auto-merge-guide.md` | +| Auto-approve + auto-merge (solo maintainer, bots) | `references/auto-merge-guide.md` | | Merge strategy for signed commits | `references/merge-strategy.md` | | Sub-issues and issue hierarchy | `references/sub-issues.md` | | Release labeling automation | `references/release-labeling.md` | @@ -87,6 +92,7 @@ scripts/verify-github-project.sh /path/to/repository | `assets/PULL_REQUEST_TEMPLATE.md.template` | `.github/PULL_REQUEST_TEMPLATE.md` | | `assets/dependabot.yml.template` | `.github/dependabot.yml` | | `assets/renovate.json.template` | `renovate.json` | +| `assets/pr-quality.yml.template` | `.github/workflows/pr-quality.yml` | | `assets/auto-merge.yml.template` | `.github/workflows/auto-merge.yml` | | `assets/auto-merge-direct.yml.template` | `.github/workflows/auto-merge.yml` | | `assets/auto-merge-queue.yml.template` | `.github/workflows/auto-merge.yml` | diff --git a/skills/github-project/assets/pr-quality.yml.template b/skills/github-project/assets/pr-quality.yml.template new file mode 100644 index 0000000..2db50b1 --- /dev/null +++ b/skills/github-project/assets/pr-quality.yml.template @@ -0,0 +1,47 @@ +# .github/workflows/pr-quality.yml +# Solo-maintainer auto-approve: approves PRs from repo collaborators +# so that required_approving_review_count >= 1 is satisfied without +# manual review for trusted authors. +# +# SECURITY: This workflow uses pull_request_target which runs with base branch +# permissions. NEVER add an actions/checkout step here -- that would allow code +# from the PR to execute with write access to the repository. +# +# Bootstrap: The PR that introduces this workflow must be approved manually +# (the workflow isn't on the base branch yet). All subsequent PRs auto-approve. + +name: PR Quality Gates + +on: + pull_request_target: + types: [opened, synchronize, reopened] + +jobs: + auto-approve: + name: Auto-approve (collaborators) + runs-on: ubuntu-latest + permissions: + pull-requests: write + + steps: + - name: Harden Runner + uses: step-security/harden-runner@v2 + with: + egress-policy: audit + + - name: Check author permission + id: check-permission + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_AUTHOR: ${{ github.event.pull_request.user.login }} + REPO: ${{ github.repository }} + run: | + PERMISSION=$(gh api "repos/$REPO/collaborators/$PR_AUTHOR/permission" --jq '.permission' 2>/dev/null || echo "none") + echo "permission=$PERMISSION" >> "$GITHUB_OUTPUT" + + - name: Auto-approve PR + if: steps.check-permission.outputs.permission == 'admin' || steps.check-permission.outputs.permission == 'write' + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh pr review --approve "$PR_URL" diff --git a/skills/github-project/references/auto-merge-guide.md b/skills/github-project/references/auto-merge-guide.md index 10a06ae..931edfd 100644 --- a/skills/github-project/references/auto-merge-guide.md +++ b/skills/github-project/references/auto-merge-guide.md @@ -1,6 +1,37 @@ -# Auto-merge Troubleshooting Guide +# Auto-merge & Auto-approve Guide -Quick reference for diagnosing and fixing auto-merge issues with Dependabot and Renovate. +Auto-merge for dependency bots and auto-approve for solo maintainers. + +## Solo Maintainer: Auto-approve via `pr-quality.yml` + +Solo maintainer projects should keep `required_approving_review_count >= 1` (required for OpenSSF Scorecard and good practice) and use a `pr-quality.yml` workflow that auto-approves PRs from repo collaborators. + +**How it works:** The workflow checks the PR author's repository permission. If they have `write` or `admin` access, it approves the PR automatically via `github-actions[bot]`, satisfying the review requirement without manual intervention. + +**Use the template:** `assets/pr-quality.yml.template` → `.github/workflows/pr-quality.yml` + +**Branch protection settings:** + +```bash +gh api repos/OWNER/REPO/branches/main/protection/required_pull_request_reviews -X PATCH \ + --input - << 'EOF' +{ + "required_approving_review_count": 1, + "dismiss_stale_reviews_on_push": true, + "require_code_owner_reviews": false +} +EOF +``` + +**Who gets auto-approved:** + +| PR author | Approved by | Auto-merged by | +|-----------|-------------|----------------| +| Repo collaborator (write/admin) | `pr-quality.yml` | Manual merge or auto-merge rule | +| Dependabot / Renovate / release-please | `auto-merge-deps.yml` | `auto-merge-deps.yml` (via `--auto`) | +| External contributor | Manual review required | Manual merge | + +> **Bootstrap note:** When first adding `pr-quality.yml`, the PR that introduces it must be approved manually (the workflow isn't on the base branch yet). All subsequent PRs auto-approve. ## Troubleshooting Quick Reference diff --git a/skills/github-project/references/security-config.md b/skills/github-project/references/security-config.md index 1a0a790..24dbbfa 100644 --- a/skills/github-project/references/security-config.md +++ b/skills/github-project/references/security-config.md @@ -1,10 +1,10 @@ # Security Configuration Reference -OpenSSF Scorecard optimization, CodeQL setup, merge strategy for signed commits, and solo maintainer auto-approve. +Repository security best practices: permissions, branch protection, CodeQL, signed commits, and PR merge requirements. -## OpenSSF Scorecard: Token-Permissions +## Least-Privilege Workflow Permissions -The Scorecard Token-Permissions check flags any `write` permission declared at **workflow-level**. All `write` permissions MUST be at **job-level** only. +All `write` permissions MUST be at **job-level** only. Workflow-level should be `read` or empty. ### Pattern: Workflow-level read, job-level write @@ -24,10 +24,10 @@ jobs: contents: read # job-level: explicit read steps: ... -# WRONG -- write at workflow level (Scorecard flags this) +# WRONG -- write at workflow level permissions: contents: read - pull-requests: write # This fails Token-Permissions check! + pull-requests: write # Too broad -- move to job level! ``` ### Common Workflows That Need Fixing @@ -38,30 +38,20 @@ permissions: | `release-labeler.yml` | `issues: write, pull-requests: write` at top | Move to label-release job | | `create-release.yml` | `contents: write` at top | Move to create-release job | +> **Scorecard note:** The OpenSSF Scorecard Token-Permissions check flags workflow-level `write` permissions. + ### SLSA Generator Pinning Exception The `slsa-framework/slsa-github-generator` reusable workflow **cannot be SHA-pinned**. It requires `@vX.Y.Z` tag references because the slsa-verifier needs the tag to verify builder identity. This is tracked as [slsa-verifier#12](https://github.com/slsa-framework/slsa-verifier/issues/12). Accept this as an unavoidable Pinned-Dependencies gap. -## Branch-Protection for Scorecard (Solo Maintainer) +## Branch Protection: Required Reviews -The Scorecard Branch-Protection check requires `required_approving_review_count >= 1`. For solo maintainer projects, combine with auto-approve: +All projects MUST have `required_approving_review_count >= 1`. -```bash -# Set required_approving_review_count to 1 (auto-approve provides it) -gh api repos/OWNER/REPO/rulesets/RULESET_ID -X PUT --input - <<'EOF' -{ - "rules": [{ - "type": "pull_request", - "parameters": { - "required_approving_review_count": 1, - "dismiss_stale_reviews_on_push": true - } - }] -} -EOF -``` +- **Solo maintainer projects:** Use `pr-quality.yml` auto-approve workflow. See `references/auto-merge-guide.md` → "Solo Maintainer" for full setup. +- **Team projects:** Reviews come from team members. -This works because `pr-quality.yml` auto-approve provides the required approval via `github-actions[bot]`. +> **Scorecard note:** The OpenSSF Scorecard Branch-Protection check requires `required_approving_review_count >= 1`. Setting it to 0 lowers your score. ## Merge Strategy & Signed Commits @@ -218,3 +208,15 @@ gh api repos/OWNER/REPO/check-runs/CHECK_RUN_ID/annotations \ | 3 | All requested reviewers responded | `gh pr view NUMBER --json reviewRequests` must be empty | | 4 | All review threads resolved | GraphQL reviewThreads query | | 5 | Branch rebased on target | `gh pr view NUMBER --json mergeStateStatus` is `CLEAN` | + +## OpenSSF Scorecard Quick Reference + +If your Scorecard score is low, check these common issues: + +| Scorecard Check | Requirement | Reference | +|----------------|-------------|-----------| +| Token-Permissions | No workflow-level `write` permissions | See "Least-Privilege Workflow Permissions" above | +| Branch-Protection | `required_approving_review_count >= 1` | See "Branch Protection: Required Reviews" above | +| Pinned-Dependencies | All actions pinned to full SHA | Pin with `uses: action@SHA # vX.Y.Z` comment | +| Code-Review | PRs reviewed before merge | Auto-approve + `required_approving_review_count >= 1` satisfies this | +| SAST | Static analysis enabled | CodeQL workflow (see above) |