feat: add compliance-remediate.sh — close the audit -> auto-fix -> PR loop#220
feat: add compliance-remediate.sh — close the audit -> auto-fix -> PR loop#220don-petry wants to merge 44 commits into
Conversation
|
Warning Review limit reached
More reviews will be available in 55 minutes and 9 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughA new Bash automation script reads compliance findings from JSON and performs repository auto-remediation via GitHub CLI. It supports direct API updates and PR-based fixes, maintains per-run reports, tracks counters, and supports DRY_RUN mode. Handlers cover repository settings, check-suite preferences, labels, CODEOWNERS generation, and GitHub Actions workflow SHA pinning. ChangesCompliance Remediation Script
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Adds an org-level remediation script that consumes findings.json from scripts/compliance-audit.sh and attempts to automatically resolve common compliance findings via direct GitHub API changes and PR-based fixes.
Changes:
- Introduces
scripts/compliance-remediate.shto apply direct remediations (repo settings, labels, check-suite preferences) from audit findings. - Adds PR-based remediation flows for CODEOWNERS standardization and GitHub Actions SHA pinning.
- Generates markdown reports summarizing remediations performed and findings skipped/failed.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # --------------------------------------------------------------------------- | ||
| # Logging helpers |
| if [ "$DRY_RUN" = "true" ]; then | ||
| skip "[DRY] Would disable check-suite auto-trigger for app $app_id on $ORG/$repo" | ||
| report_direct "$repo" "$check" "DRY: would set \`auto_trigger=false\` for app_id=$app_id" | ||
| return 0 | ||
| fi | ||
|
|
||
| local payload | ||
| payload=$(jq -n --argjson id "$app_id" '{"auto_trigger_checks":[{"app_id":$id,"setting":false}]}') | ||
|
|
||
| if echo "$payload" | gh api -X PATCH "repos/$ORG/$repo/check-suites/preferences" \ | ||
| --input - > /dev/null 2>&1; then | ||
| ok "Disabled check-suite auto-trigger for app $app_id on $ORG/$repo" | ||
| report_direct "$repo" "$check" "Set \`auto_trigger=false\` for app_id=$app_id" | ||
| else | ||
| err "Failed to disable check-suite auto-trigger for app $app_id on $ORG/$repo" | ||
| report_fail "$repo" "$check" "PATCH check-suites/preferences failed for app_id=$app_id" | ||
| fi | ||
| } | ||
|
|
||
| # --------------------------------------------------------------------------- |
| return 0 | ||
| fi | ||
|
|
||
| # Get default branch and its HEAD SHA |
| tag_part="${ref##*@}" | ||
|
|
||
| # Skip if already a full SHA (shouldn't occur given grep above) | ||
| if echo "$tag_part" | grep -qE '^[0-9a-f]{40}$'; then | ||
| continue | ||
| fi | ||
|
|
||
| # Resolve the tag to a commit SHA. | ||
| # Lightweight tags point directly to a commit (.object.type == "commit"). | ||
| # Annotated tags point to a tag object (.object.type == "tag") which | ||
| # must be dereferenced to get the commit SHA. | ||
| local commit_sha="" | ||
| local ref_json | ||
| ref_json=$(gh api "repos/$action_part/git/refs/tags/$tag_part" 2>/dev/null || echo "") | ||
|
|
||
| if [ -n "$ref_json" ]; then | ||
| local obj_type obj_sha | ||
| obj_type=$(echo "$ref_json" | jq -r '.object.type // empty') | ||
| obj_sha=$(echo "$ref_json" | jq -r '.object.sha // empty') | ||
|
|
||
| if [ "$obj_type" = "tag" ]; then | ||
| # Annotated tag — dereference the tag object | ||
| commit_sha=$(gh api "repos/$action_part/git/tags/$obj_sha" \ | ||
| --jq '.object.sha' 2>/dev/null || echo "") | ||
| else | ||
| commit_sha="$obj_sha" | ||
| fi | ||
| fi | ||
|
|
||
| # Fallback: commits API | ||
| if [ -z "$commit_sha" ]; then | ||
| commit_sha=$(gh api "repos/$action_part/commits?sha=$tag_part&per_page=1" \ | ||
| --jq '.[0].sha' 2>/dev/null || echo "") | ||
| fi | ||
|
|
||
| if [ -z "$commit_sha" ]; then |
| local escaped_ref | ||
| escaped_ref=$(printf '%s' "$ref" | sed 's/[[\.*^$()+?{|]/\\&/g') | ||
| patched_content=$(echo "$patched_content" \ | ||
| | sed "s|uses: ${escaped_ref}|uses: ${action_part}@${commit_sha} # ${tag_part}|g") |
| encoded_content=$(printf '%s' "$codeowners_content" | base64 -w 0) | ||
|
|
||
| local api_args=(-X PUT "repos/$ORG/$repo/contents/$existing_path" | ||
| -f message="fix: update CODEOWNERS to use @petry-projects/org-leads team (compliance remediation)" |
| fi | ||
|
|
||
| local new_encoded | ||
| new_encoded=$(printf '%s' "$patched_content" | base64 -w 0) |
| report_direct "$repo" "unpinned-actions-$workflow_file" \ | ||
| "DRY: would pin $pins_applied action(s)" | ||
| return 0 | ||
| fi | ||
|
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/compliance-remediate.sh`:
- Around line 706-713: The current repos assignment silences jq parse/errors via
"|| echo ''" causing malformed FINDINGS_FILE to be treated as no findings;
remove the fallback and instead run jq to populate the repos variable and
immediately check its exit status (i.e., run repos=$(jq -r '[.[].repo] |
unique[]' "$FINDINGS_FILE" 2>/dev/null) and if jq fails — detect non-zero exit
code or empty output due to parse errors — call the script's error/fatal logging
function (e.g., error or fatal) with the jq error context and exit with a
non-zero status; ensure you reference FINDINGS_FILE and the repos variable and
do not swallow jq failures.
- Line 264: The script uses GNU-only base64 flags (e.g., base64 -w 0 and base64
-d) which break on macOS; add portable helper functions b64_encode() and
b64_decode() near the other helpers that detect GNU vs BSD base64 and call the
appropriate options, then replace all raw base64 invocations (e.g., the
encoded_content assignment and the other two occurrences where base64 is used)
to pipe through b64_encode or b64_decode as appropriate so encoding/decoding
works on both Linux and macOS.
- Around line 379-414: The gh API calls use action_part (which may include a
workflow path) instead of the repository slug; extract the repo slug as the
first two path components (e.g.,
repo_slug="${action_part%%/*}/${action_part#*/}" truncated to two components)
before the tag-resolution block and replace action_part with repo_slug in the
three gh api calls that assign ref_json and commit_sha (the calls using
"repos/$action_part/git/refs/tags/$tag_part",
"repos/$action_part/git/tags/$obj_sha", and
"repos/$action_part/commits?sha=$tag_part&per_page=1") so API paths become
"repos/$repo_slug/…". Ensure the new repo_slug variable is used consistently and
falls back to action_part if it cannot be parsed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: c46eb8fd-914c-4734-a2d8-a47f99280156
📒 Files selected for processing (1)
scripts/compliance-remediate.sh
|
Auto-rebase failed — merge conflict — this branch has conflicts with Please resolve the conflicts and push: |
Adds `scripts/compliance-remediate.sh` to auto-remediate recurring compliance-audit findings from `findings.json`. Direct API remediations (applied immediately, no PR): - `has_wiki=true` → PATCH has_wiki=false - `allow_auto_merge=false` → PATCH allow_auto_merge=true - `delete_branch_on_merge=false` → PATCH delete_branch_on_merge=true - `has_discussions=false` → PATCH has_discussions=true - `check-suite-auto-trigger-*` → disable for Claude/CodeRabbit app IDs - `missing-label-*` → gh label create with colors/descriptions from standard PR-based remediations (creates branch + PR in target repo): - `missing-codeowners`, `codeowners-empty`, `codeowners-org-leads-not-first`, `codeowners-individual-users`, `codeowners-no-catchall` → generates `.github/CODEOWNERS` with `* @petry-projects/org-leads` per current standard - `unpinned-actions-<file.yml>` → resolves tag → commit SHA (handles annotated vs. lightweight tags), pins all unpinned refs, opens PR Skipped with explanation (for human/agent pickup): - Workflow files, rulesets, dependabot.yml, CLAUDE.md/AGENTS.md, CodeQL default setup, push-protection settings Improvements over prior attempts (claude/issue-35-20260406-0341): - CODEOWNERS generation uses `@petry-projects/org-leads` team (not individual users — forbidden per codeowners-standard.md updated 2026-05-04) - Handles all five CODEOWNERS finding variants, not just `missing-codeowners` - Adds `in-progress` label to the label map (was missing) - Adds check-suite auto-trigger remediation (new audit finding) - Bash 4+ version guard (consistent with apply-repo-settings.sh) Closes #35 Co-authored-by: Don Petry <don-petry@users.noreply.github.com>
- SC2034: Remove unused CHECK_SUITE_APP_IDS array (app_id extracted from finding check name at runtime, no static list needed) - SC2155: Split local declarations from command-substitution assignments (local branch_name; branch_name="...$(date ...)") - SC2221/SC2222: Move ci-workflows/missing-permissions-* before the more general ci-workflows/missing-* to prevent pattern override Co-authored-by: Don Petry <don-petry@users.noreply.github.com>
8a49089 to
ae0f4c8
Compare
Superseded by automated re-review at
|
Superseded by automated re-review at
|
|
@coderabbitai resolve |
Dev-Lead — review-changes (applied)Changes committed and pushed. |
✅ Actions performedComments resolved and changes approved. |
Dev-Lead — fix-reviews (applied)Changes committed and pushed. |
|



Summary
Adds
scripts/compliance-remediate.shto close the audit → report → auto-fix → PR loop from #35. The script readsfindings.jsonfromcompliance-audit.shand applies automatic remediations.Closes #35
Direct API remediations (applied immediately, no PR)
has_wiki=truehas_wiki=falseallow_auto_merge=falseallow_auto_merge=truedelete_branch_on_merge=falsedelete_branch_on_merge=truehas_discussions=falsehas_discussions=truecheck-suite-auto-trigger-<app_id>missing-label-<name>gh label createwith correct colors/descriptions per standardPR-based remediations (creates branch + PR in target repo)
missing-codeowners,codeowners-empty,codeowners-org-leads-not-first,codeowners-individual-users,codeowners-no-catchall.github/CODEOWNERSwith* @petry-projects/org-leadsper current standardunpinned-actions-<file.yml>Skipped with explanation (for human/agent pickup)
Missing workflow files, rulesets,
dependabot.yml,CLAUDE.md/AGENTS.md, CodeQL default setup, push-protection settingsUsage
Workflow integration snippet
Add a
remediatejob tocompliance-audit-and-improvement.ymlafter theauditjob:Improvements over prior attempts (
claude/issue-35-20260406-0341)* @petry-projects/org-leads(not individual users — forbidden per codeowners-standard.md updated 2026-05-04)missing-codeownersin-progresslabel: Added to label map (was missing in prior versions)check-suite-auto-trigger-*findings that block auto-mergeapply-repo-settings.shGenerated with Claude Code
Summary by CodeRabbit