Repository navigation
Delete a Merged Feature Branch Through a pr_review.py cleanup Subcommand - #2970
Conversation
Add `cleanup <number> --repo OWNER/NAME`, which reads the head branch from the merged pull request, refuses unless it merged into develop from a head in that repository, is not a permanent branch, and is covered by no ruleset or branch protection, then deletes the ref only where its tip is the pull request's headRefOid and confirms the delete by reading the ref back. The owner and repository are bound to the registry through handoff.py's own write-scope check. Point drive-pr and merge-and-release at it, keeping the hand form and the paste-ready report as the fallback for a host without the managed allow rule. Closes #2967 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
State the tip check as verify-then-delete rather than a compare-and-swap, name the registry's fork admission and which exit a registry refusal takes, read the rule and protection endpoints through reread_json so a transient failure is retried, cover the fork path and both new transports in the tests, and restore the subcommand list's column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Split reread_json so cleanup can print the last read's stderr where nothing parsed, state that 64 also covers an origin that cannot be read, and rewrap the lines the previous commit left long. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
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 |
|
A recorded local strict-review pass covers head |
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved cleanup safety issues remain in scripts/pr_review.py, including path encoding, pagination handling, and nested response validation.
2 open findings
What changed in this PR
Adds a verified cleanup subcommand for deleting merged feature branches, with documentation, workflow, and test updates.
Changes:
- Adds verification, protection checks, deletion, and read-back confirmation.
- Updates cleanup instructions and generated skill copies.
- Expands tests and mutation-safety coverage.
| File | Summary |
|---|---|
tests/test_pr_review.py |
Adds cleanup behavior and safety tests. |
scripts/README.md |
Documents the cleanup command. |
scripts/pr_review.py |
Implements branch verification and deletion. |
.github/skills/merge-and-release/SKILL.md |
Updates release cleanup instructions. |
.github/skills/drive-pr/SKILL.md |
Updates PR workflow cleanup instructions. |
.claude-plugin/fleet-skills/skills/merge-and-release/SKILL.md |
Updates generated release skill. |
.claude-plugin/fleet-skills/skills/drive-pr/SKILL.md |
Updates generated drive skill. |
.claude-plugin/fleet-skills/.source-digests/merge-and-release |
Updates source digest. |
.claude-plugin/fleet-skills/.source-digests/drive-pr |
Updates source digest. |
.agents/skills/merge-and-release/SKILL.md |
Updates canonical release skill. |
.agents/skills/drive-pr/SKILL.md |
Updates canonical drive skill. |
🧠 Review effort: Lite
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #2970 +/- ##
===========================================
+ Coverage 60.02% 60.53% +0.50%
===========================================
Files 17 17
Lines 8784 8904 +120
===========================================
+ Hits 5273 5390 +117
- Misses 3511 3514 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Local review finding left open in the description (no test asserts that a failed |
|
Copilot's headline also names "nested response validation" beside its two counted findings, with no finding or thread of its own. Read against the head: |
…de-Override and Shell-Rewrite Denies to Main (#2980) - #2970 adds a `cleanup` subcommand to `scripts/pr_review.py` that runs the merged-feature-branch verify-then-delete in code. It reads the head branch from the merged pull request, refuses a base other than `develop`, a head from another repository, a protected or default branch, and a repository outside the registry, reads the ref by its qualified name, deletes only when its tip matches `headRefOid`, and confirms the delete by reading the ref back. `drive-pr` step 4 and `merge-and-release` step 8 now call it, with the hand form kept as the fallback - #2974 makes `gh-write-guard` deny an `include.path`/`includeIf` override on a commit or push, on a command that runs other git commands (`rebase`, `submodule`, `bisect`, `filter-branch`, `difftool`, `mergetool`), and on any command git does not build in. It reads an `eval` argument holding an include key as the command it runs, and keeps a local branch name such as `release/1.0` whole when checking it against the rule set. A differential against the previous guard found zero allow flips, and the known new over-denials are listed in that pull request - #2979 makes `gh-write-guard` read quote-split words and an uppercase `GIT` through the existing push and include checks, and fail closed on a run-time word (an expansion, a substitution, a backtick, a brace expansion) where the subcommand goes, among a push's or a commit's global options or arguments, on a redirection before the subcommand, and on an unquoted comment among a push's words. The managed permission rule's description now names `pr_review.py cleanup`. A differential against the previous guard found zero allow flips, and the known new over-denials and the gaps left open (#2976, #2977, #2978) are listed in that pull request After this merges, the host-safety installer payload changes, so the maintainer runs the installer after promotion. Closes #2967 Closes #2958 Closes #2960 Closes #2962 Closes #2959 Closes #2961 Closes #2968 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a guarded cleanup option for merged pull request branches. It verifies that the branch is eligible and unchanged before deletion, then confirms the result. * **Security** * Strengthened protections against potentially unsafe Git commit and push commands, including attempts to bypass configured safeguards. * **Documentation** * Updated guidance for branch cleanup, safety checks, and the outcomes reported when cleanup cannot proceed. <!-- end of auto-generated comment: release notes by coderabbit.ai -->


Summary
Adds a
cleanupsubcommand toscripts/pr_review.pythat runs the merged-feature-branch verify-then-delete in code, so the delete runs under the host-safety installer's existingBash(python3 scripts/pr_review.py:*)allow rule instead of as a hand-typed delete the write guard or the auto-mode classifier refuses.drive-prstep 4 andmerge-and-releasestep 8 now call it, and the hand form stays as the fallback for a host without that rule, with its commands reported paste-ready where the seat cannot run them.python3 scripts/pr_review.py cleanup <number> --repo OWNER/NAME:develop, itsheadRepository.nameWithOwnerequals--repo, and the head branch is notdevelop,main, or the default branch read live.commentandreplycheck (exit 64). Then it binds the owner toregistry/repos.jsonand admits only a registered repository or a fork, usinghandoff.py'srequire_write_scope, which it imports rather than copies.rules/branches/{branch}) or classic protection (branches/{branch},.protected) covers. A read that fails or comes back in the wrong shape exits 2, and it never counts as "no rules".headRefOidexits 1 and names both commits. Otherwise it sendsdeleteRefwith the node id that same read returned.--dry-run, because no other subcommand of this script has one.deleteRefis the script's fifth mutation document, and the whole-source write test now pins five.The delete carries no expected tip, so this is verify-then-delete, the same gate the hand form uses, rather than a compare-and-swap.
Tests
tests/test_pr_review.pyhas newCleanupCasecases. They mock GraphQL and REST and use constructed names only. They cover:cleanupis also added to the cross-owner write table, which now also asserts that neither of the new transports is reached. The new subcommand was not run against any live branch.Local Review
A strict local pass ran for three rounds, and the receipt was recorded at this head.
Filed rather than fixed:
Declined with evidence:
rules/branchesendpoint returned a JSON list.Left open after the edit budget was spent, class
introduced:cleanup_rest). Only the diagnostic text is uncovered. The exit 2 itself is covered.Closes #2967
🤖 Generated with Claude Code