Skip to content

Read Completed, Pruned, and Slash-Remote Push Targets in the Write Guard - #3023

Merged
ptr727 merged 5 commits into
developfrom
feature/3005-3007-2973-guard-push-targets
Oct 14, 2026
Merged

ptr727 merged 5 commits into
developfrom
feature/3005-3007-2973-guard-push-targets

Conversation

@ptr727

@ptr727 ptr727 commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

Summary

Three push-target readings in the write guard, each of which let a push that writes a protected branch through.

  • Read a Push Destination Git Completes Under refs/ in the Write Guard #3005, destination completion. Git matches a destination outside refs/ with its refs/%s rule, so HEAD:heads/develop updates develop and :heads/develop deletes it. New _dst_branches reads a heads/ destination as the branch after heads/ as well as by its literal name. No other matching rule writes a branch: refs/tags/%s, refs/remotes/%s, and refs/remotes/%s/HEAD are not branches, and refs/heads/%s and the unmatched fallback write the literal name, which was already read. A colon-less heads/develop refspec goes through the same reading.
  • Read --prune Beside a Branch Pattern as a Delete in the Write Guard #3007, --prune and --mirror. --prune, whole or cut short, adds a delete to every branch a pattern refspec, a : refspec, --all/--branches, or a bare push may match. A bare push is included since a configured push refspec or push.default=matching may be a pattern. --prune beside an explicit refspec adds nothing, which is what git does. --mirror is read as a force and a delete.
  • Strip Only the Remote From a Remote-Tracking Push Target in the Write Guard #2973, the @{push} read. It now reads --symbolic-full-name @{push} rather than --abbrev-ref. Each remote name git remote lists that prefixes the text after refs/remotes/ is stripped, so a remote named like up/stream loses both segments. The text is also read whole and with its first segment dropped, so every name the old --abbrev-ref read gave is kept. A local branch named like origin/develop no longer turns the read into origin/develop.

Verification

  • Git behavior, against throwaway local repositories (git 2.47.3). HEAD:heads/develop updated develop, and :heads/develop deleted it. An unmatched heads/heads/develop created the branch heads/heads/develop. --prune beside refs/heads/*:refs/heads/*, beside :, beside --all, cut short as --prun, and on a bare push with a configured pattern each deleted a remote branch with no local counterpart. --prune develop deleted nothing, and --pr is refused as ambiguous. --abbrev-ref @{push} printed remotes/origin/develop once a local branch origin/develop existed, and up/stream/develop for a remote named up/stream.
  • Develop-versus-branch differential. Each guard's classify was run over every _GIT_CASES row, about 8,700 generated push shapes, the new real-repository @{push} cases, and _PUSH_DIR_CASES. Every changed verdict is allow -> deny, in heads/, --prune, --mirror, and @{push} shapes only. Nothing develop denied is allowed.
  • Revert proof. With develop's _push_targets and _current_push_branch swapped back in, each new deny case in the selftest fails.
  • gh-write-guard.py --selftest, test_install.py, the root tests/ suite, ruff format and check, mypy, prose_lint.py, and the eol gates pass locally.

Local Review

A frontier local-strict-review pass ran over each pushed head. Its findings outside these three issues are filed rather than chased here:

From Copilot's first round, a later --no-prune now cancels an earlier --prune. The same class for the other negatable push options is #3025, and running the real-repository selftests on Windows is #3024.

The comments label is on this pull request because the shared _git_stdout helper moves two existing comment lines.

Closes on promotion: #3005, #3007, #2973

🤖 Generated with Claude Code

ptr727 and others added 3 commits October 14, 2026 15:47
A destination outside refs/ that starts with heads/ is now read as the
branch after it as well as by its literal name, since git completes it
under refs/ and writes that branch. --prune, whole or cut short, adds a
delete to every branch a pattern, a matching refspec, --all, or a bare
push may match, and --mirror is read as a force and a delete. A bare
push's @{push} target is read by its full name, with the remote stripped
by matching the configured remote names, so a local branch named like a
remote-tracking ref and a remote whose name holds a slash both resolve to
the branch the push writes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The full @{push} name is now also read whole and with its first segment
dropped, so no name the --abbrev-ref read gave is lost where a fetch
refspec writes under another remote's name. The git stdout read and the
temporary-repository build each move into one helper both callers use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The comment that moved into _git_stdout still described one caller's
outcome, which two of its callers no longer have. It now says what the
lenient decode protects for any caller.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings October 14, 2026 23:12
@ptr727 ptr727 added the comments Permits the comment lines the pull request adds or edits, which the prose gate otherwise refuses label Oct 14, 2026
@ptr727

ptr727 commented Oct 14, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 0ec27dcd9df6cd774e08c99c804ffd6a1605c086, the content this pull request carries at that commit against develop, and it recorded 0 findings.

@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 23 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: ptr727/ProjectTemplate/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 28ccf952-98f3-490f-9578-7d9ac1c517db
📥 Commits

Reviewing files that changed from the base of the PR and between 4049058 and f3068cc.

📒 Files selected for processing: 1
  • host-setup/agent-safety/claude/gh-write-guard.py
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (develop@4049058). Learn more about missing BASE report.

Additional details and impacted files
@@            Coverage Diff             @@
##             develop    #3023   +/-   ##
==========================================
  Coverage           ?   60.98%           
==========================================
  Files              ?       17           
  Lines              ?     9010           
  Branches           ?        0           
==========================================
  Hits               ?     5495           
  Misses             ?     3515           
  Partials           ?        0           
Flag Coverage Δ
python-3.13 60.98% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Protected-branch enforcement needs human validation, especially with unresolved option-order behavior and missing Windows test coverage.

2 open findings
What changed in this PR

This PR tightens the agent-safety write guard so it recognizes more pushes that can change protected branches.

Changes:

  • Recognizes heads/ destinations and treats --prune and --mirror as potential deletions.
  • Reads full @{push} references to handle remote names containing slashes.
  • Adds push-classification and temporary-repository test cases.
File Description
host-setup/​agent-safety/​claude/​gh-write-guard.py Updates push-target parsing and adds regression cases.

🧠 Review effort: Lite


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread host-setup/agent-safety/claude/gh-write-guard.py
Comment thread host-setup/agent-safety/claude/gh-write-guard.py
ptr727 and others added 2 commits October 14, 2026 16:25
Git applies --prune and --no-prune in order, so the later one wins, and
a push carrying --prune then --no-prune deletes nothing. The guard now
reads the two the same way, whole or cut short.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Git reads every word after -- or --end-of-options as a refspec, so a
--no-prune there cancels nothing and the push still prunes. The guard
read it as the option, which let such a push through.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Oct 14, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head f3068ccc3017c4a843ce3654f6686623dce8d5fe, the content this pull request carries at that commit against develop, and it recorded 0 findings.

@ptr727

ptr727 commented Oct 14, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ptr727
ptr727 merged commit fd49353 into develop Oct 14, 2026
13 checks passed
@ptr727
ptr727 deleted the feature/3005-3007-2973-guard-push-targets branch October 14, 2026 23:48
ptr727 added a commit that referenced this pull request Oct 15, 2026
…ng, and backlog-burndown Re-Dispatch Rules to Main (#3030)

- #2997 adds an updater that keeps the coding-agent tools already
installed on a host current, without installing a tool the maintainer
has not chosen
- #3017 brings the agent-safety READMEs up to the write guard's #3011
readings: `--admin` read inside a quoted `eval` argument, clustered and
cut-short push options, `--branches` as `--all`, `refs/` pattern
destinations, and a double-quoted list expansion as a directory or
commit value failing closed
- #3022 pairs a Copilot overview-table or `Review findings:` entry with
a review thread by the file it names, replacing word overlap, compares
the headline count against everything the round and the pull request
account for, and makes `pr_review.py cleanup` read every page of the
head pull requests, counting only this repository's own
- #3018 has `backlog-burndown` name a new branch when an issue is
dispatched again, name the open pull request a pushed branch still heads
when cleanup reports it, and splits the long cleanup sentence
- #3028 keeps an abandoned group's issue out of the `backlog-burndown`
ranking while that group is stopped for the maintainer, and records the
release on the claim comment
- #3023 makes `gh-write-guard` read a `heads/` push destination as the
branch git completes it to, read `--prune` beside a pattern, `:`,
`--all`, or bare push as a delete of each branch matched, read
`--mirror` as a force and a delete, and read the `@{push}` target
against the configured remote names. A differential against the previous
guard found no deny-to-allow flip
- #3032 subtracts every thread id an open entry links, back-references
included, from the earlier threads `pr_review.py`'s headline shortfall
counts, so a back-referenced thread is no longer counted twice
- #3035 covers the bootstrap upgrade handoff on Linux and Windows, the
root and elevated skips included, and has `bootstrap.ps1` say when the
agent tools report fails
- #3037 makes `gh-write-guard` fail closed when a push target resolves
but the remote names cannot be read

After this merges, the host-safety installer payload changes, so the
maintainer runs the installer after promotion.

Fixes #3009
Fixes #2985
Fixes #3003
Fixes #2993
Fixes #3016
Fixes #3005
Fixes #3007
Fixes #2973

🤖 Generated with [Claude Code](https://claude.com/claude-code)
ptr727 added a commit that referenced this pull request Oct 15, 2026
… Narrative Findings, and Bootstrap Handoff Tests to Main (#3051)

- #3042 brings the agent-safety READMEs up to the write guard's #3023
and #3037 readings: `--prune` beside a pattern, `:`, `--all`, or a bare
push, a `--mirror` push with no refspec, a `heads/` destination outside
`refs/`, the full `@{push}` read, and a bare push denied when `git
remote` cannot list the remotes
- #3041 has `backlog-burndown` keep an abandoned group's claim comment
until cleanup decides its release, say stopped on each path that sends a
group to the maintainer, and name a branch no pull request has used when
a claim comment first names it
- #3044 tests `bootstrap.sh`'s `--report` handoff to the agent tools
step, tests the `--agents` handoff on Linux and through
`Invoke-AgentsInstall` under `pwsh`, and moves the unprivileged-root
probe into `tests/host_capability.py`
- #3045 makes `pr_review.py` read an `Open findings remain:` list in a
Copilot review and count each entry no thread of the round accounts for,
pairing by severity tier and file, so the count can only rise
- #3049 makes `gh-write-guard` read a bare push's destination from
`push.default` and `branch.<name>.merge`, read a persisted
`remote.<name>.mirror`, deny when the `@{push}` read times out or cannot
run, give a dash-named word after `--` or `--end-of-options` a reading
as a remote or refspec, and judge a push moved into another checkout
against that checkout's origin as well. A differential against the
previous guard found no deny-to-allow flip. It addresses one item of
#2943, which stays open
- #3054 makes `gh-write-guard` answer unresolved, and so deny, when its
`push.default` read times out or cannot run, a promotion fix for this
pull request's first review
- #3062 brings both agent-safety READMEs up to #3054: an unset
`push.default` is read as `simple`, both destinations are read for a
value git does not define or a read exiting with any other error, and a
read that times out or cannot run is denied
- #3059 bumps `actions/create-github-app-token` from 3.2.0 to 3.3.0

After this merges, the host-safety installer payload changes, so the
maintainer runs the installer after promotion.

Fixes #3021
Fixes #3026
Fixes #3027
Fixes #3039
Fixes #3033
Fixes #3038
Fixes #3034
Fixes #3031
Fixes #3019
Fixes #3020
Fixes #3029
Fixes #3036
Fixes #3052

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comments Permits the comment lines the pull request adds or edits, which the prose gate otherwise refuses

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants