Skip to content

Describe a Timed-Out push.default Read as a Deny in the Agent-Safety READMEs - #3062

Merged
ptr727 merged 2 commits into
developfrom
feature/promo-3051-fix-2
Oct 15, 2026
Merged

ptr727 merged 2 commits into
developfrom
feature/promo-3051-fix-2

Conversation

@ptr727

@ptr727 ptr727 commented Oct 15, 2026

Copy link
Copy Markdown
Owner

A promotion fix for #3051. Since #3054, the write guard answers unresolved, and so denies, when its push.default read times out or cannot run. Both agent-safety READMEs still said such a read is read as both destinations. They now say:

  • an unset push.default is read as simple
  • both destinations are read where push.default holds a value git does not define, or where its read exits with any other error
  • a bare push is denied where any read of its branch, its push target, or push.default times out or cannot run

This answers the two README threads on #3051 and fixes #3052, the issue filed for that drift.

The sentence-length hits that prose_lint.py --diff reports on host-setup/agent-safety/claude/README.md:15 are sentences that were already there. That bullet is one physical line, so any change to it brings every sentence in it into scope. Neither new sentence exceeds the limit.

Two local strict review passes ran at Opus. Pass 1 raised three findings. Two, a timed-out read still covered by the "read as both" sentence and the unset case left unstated, are fixed. The third, the guard folding the value's case, is pre-existing and filed as #3061. Pass 2 raised nothing.

Closes on promotion: #3052

🤖 Generated with Claude Code

ptr727 and others added 2 commits October 15, 2026 06:58
…READMEs

The guard now answers unresolved when its push.default read times out or
cannot run, so both READMEs no longer say such a read is read as both.
Both readings stay for a value git does not define and for a failed read
other than an unset key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ty READMEs

An unset push.default reads as simple, and only a read exiting with
another error reads both destinations, so a timed-out read is no longer
covered by the sentence describing the both reading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings October 15, 2026 14:02
@coderabbitai

coderabbitai Bot commented Oct 15, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Repository: ptr727/ProjectTemplate/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1552eec1-88ef-4ca2-a92b-103d0940c317
  • 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.

@ptr727

ptr727 commented Oct 15, 2026

Copy link
Copy Markdown
Owner Author

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

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.

🟢 Approval recommended

Documentation is aligned with the write guard behavior, with no unresolved review issues.

0 open findings

What changed in this PR

Updates both agent-safety READMEs to document push.default handling and fail-closed behavior for timed-out or failed reads.

Changes:

  • Documents unset push.default as simple.
  • Clarifies fallback behavior for invalid values and errors.
  • Documents denial when relevant reads time out or cannot run.
File Description
host-setup/​agent-safety/​README.md Updates push destination and timeout documentation.
host-setup/​agent-safety/​claude/​README.md Mirrors the corrected guard behavior.

🧠 Review effort: Lite


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@codecov

codecov Bot commented Oct 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.21%. Comparing base (b633996) to head (710f828).

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #3062   +/-   ##
========================================
  Coverage    61.21%   61.21%           
========================================
  Files           17       17           
  Lines         9062     9062           
========================================
  Hits          5547     5547           
  Misses        3515     3515           
Flag Coverage Δ
python-3.13 61.21% <ø> (ø)

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.

@ptr727
ptr727 merged commit 2b0975a into develop Oct 15, 2026
14 checks passed
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)
@ptr727
ptr727 deleted the feature/promo-3051-fix-2 branch October 15, 2026 14:33
ptr727 added a commit that referenced this pull request Oct 15, 2026
…s in the Write Guard (#3058)

## Summary

Closes the write guard's hidden-command allow gaps. Every changed
verdict goes from allow to deny.

- **#3010, past the wrapper cap.** `_check_bypass_flags` denies a body
nested past `_WRAPPER_NESTING_LIMIT` that names a git commit or push.
Its flags cannot be read, so a `--no-verify`, a `commit -n`, or a
hooks-path override there no longer passes. The same commit two levels
deep is still read and judged.
- **#2989 and #2999, substitutions the guard skipped.**
`_substitution_bodies` reads a `$(...)` or backtick substitution inside
a double-quoted `${...}` (`_expansion_substitutions`). It reads one
inside a heredoc body whose delimiter is unquoted
(`_unquoted_heredoc_bodies`), at top level and inside a substitution's
body. A body under a quoted delimiter, such as `<<'EOF'`, stays data.
- **#2972, config keys that run a command.** A `-c` value for a key git
runs as a command, such as `core.pager`, `core.fsmonitor`,
`core.sshCommand`, or a `diff.<driver>.textconv`, is read as the command
it runs. A value naming its program by a path or an expansion is denied,
since the guard does not read that program. So is a `--config-env` value
for such a key. An `include.path`/`includeIf` override is now denied on
any git command, the direction the issue named as the simpler one.
- **#2943, partly: other shells, stdin, editor and config environment,
and aliases.**
- A command string run by `pwsh`, `powershell`, `fish`, `script`, `cmd`,
`ash`, `csh`, `tcsh`, or `rbash` is read as a wrapper body, only where
that shell is its command's command (see `_command_prefix`). That covers
`-Command`, `--command=`, `cmd /c` and `cmd //c`, and a Windows
PowerShell positional command.
- A push in interpreter code that can start a process, such as `python3
-c "...os.system(...)"` or `node -e`, is denied. Code that only mentions
a push, such as a `perl -pi -e` substitution, is allowed.
- A push in text piped to a shell that reads its script from that pipe
is denied.
- `GIT_EDITOR`, `GIT_SEQUENCE_EDITOR`, `GIT_PAGER`, `GIT_SSH_COMMAND`,
and the other variables git runs as a command are read as commands, with
the same path rule. They count where they reach a git command, through
`export` or in that command's own prefix. `_command_prefix` reads a
prefix forward, past a redirection and a precommand such as `timeout` or
`sudo` with its options and their values.
- Config set through `GIT_CONFIG_COUNT` and its key and value variables
counts as a `-c` override. A `GIT_CONFIG_GLOBAL` or `GIT_CONFIG_SYSTEM`
file other than `/dev/null` is read as an include.
- A `--config-env` alias for the subcommand it runs is denied. So is a
push run by an alias set in the environment, by an inline alias chaining
into the persisted config, or by a persisted alias (`_hidden_command`).
A persisted alias is read only for a word shaped as an alias name that
git does not run ahead of one.

The selftest pins persisted aliases to an empty table, as it already
pins git's command list, so no row reads the host's own aliases. The
READMEs describe each new reading.

## Verification

- **Gaps confirmed at develop's tip.** A `classify` probe on constructed
commands, against a throwaway repository under `mktemp -d`, showed
develop allowing every shape the issues name, each listed in the new
selftest rows.
- **Develop-versus-branch differential**, against develop at `2b0975ae`
(after #3054, #3059, and #3062, whose guard is unchanged from #3054).
Both guards' `classify` ran over the same inputs: every develop
`_GIT_CASES` row with every new hidden-command row (387), the 7 alias
rows, 113,784 generated push shapes over eight constructed repositories
and three rule maps, the 140 `_PUSH_DIR_CASES`, and 1,944 runs of 81
extra common and edge shapes over the same repositories and maps,
116,262 inputs in all. **0 deny -> allow, 114 allow -> deny.** Every
flip is a new selftest row, one of the two `include` rows this PR
relabels from allow to deny for #2972, or one of two extra shapes:
`powershell -Command` pushing to `develop` and a push piped to `bash`.
The generated push shapes kept every develop verdict.
- **Revert proof.** With develop's `_skip_quote_body`,
`_substitution_bodies`, `_embedded_wrapper_commands`,
`_check_bypass_flags`, and `_unreadable_push` swapped into the branch
module and `_hidden_command` disabled, 64 of the 66 new deny rows fail
and all 29 controls pass. The other two are regression rows develop
already denies, kept to guard the flip a review found.
- `gh-write-guard.py --selftest` passes, and passes too with an empty
`PATH`. `test_install.py` passes (161 tests), and so does the root
`tests/` suite (2,838 tests). Ruff format and check, mypy,
`prose_lint.py`, the eol and eol-coverage gates, `spec/validate.py`, and
markdownlint and editorconfig-checker in Docker pass.

## Local Review

Three frontier `local-strict-review` passes ran before the push. Fixed
from them:

- A deny-to-allow flip. A word naming `cmd`, `script`, or `fish` made
the wrapper scan skip the arguments after it, so a later `sh -c` body
went unread. A foreign shell is now read only where it opens a command,
and the scan continues past it.
- Over-denials: a shell name used as a piped command's argument, a
`NAME=value` word in a commit message or heredoc data, and interpreter
code that only mentions a push.
- An inline alias chaining to a persisted push alias, `fish --command=`,
a PowerShell positional command, `|&`, a precommand between the
assignments and git, `cmd //c`, the `py` launcher, an empty
`GIT_CONFIG_GLOBAL`, and a control row whose label its command did not
test.
- The selftest read the host's real git aliases.

Declined, with evidence:

- An alias defined earlier in the same command, `git config alias.pp
push && git pp origin develop`, is the #3046 class.
- A timed-out persisted alias read reads as no alias, which is #3047.
- The pipeline walk in `_heredoc_openers_in` treats `|&` as ending a
pipeline. Teaching `_ends_pipeline` otherwise changes the heredoc and
wait rules, and no verdict differs.
- `_PINNED_ALIASES` follows the existing `_GIT_COMMAND_NAMES` pin. A
seam would touch about nineteen selftest loops.
- The overflow push check in `_unreadable_push` stays beside the new
one, since it also covers include keys and `eval` overflow.

The third pass's three `introduced` findings came after the opening
push's two-round edit budget. They and both Copilot threads were fixed
in the review loop's next push, under three more frontier passes:

- An assignment is read only in the prefix of the git command it
reaches, so `echo GIT_CONFIG_GLOBAL=/example/x -n git` is allowed.
Config set on an earlier `git status` no longer counts on a later push.
- A precommand option's separate value, short or long, is passed, as in
`timeout -s KILL 60`, `sudo --user root`, or `xargs --delimiter ,`. A
leading redirection is passed too.
- A foreign shell behind an option-taking launcher, such as `sudo -u
root pwsh -Command`, is read, and a shell name a `grep` behind `timeout`
searches for is not.

That push's last pass found `--eof` among the xargs options taking a
separate value, though GNU xargs takes its value attached. The push
after it drops `--eof`, and then `--max-lines` for the same reason, and
adds sudo's `-a` and `-c`. Its last pass, the eighth, found nothing new
and no deny-to-allow flip over 8,000 fuzzed commands. No `introduced`
finding is open.

Filed rather than widened here:

- #3055: a hooks-path override on a git command other than commit or
push.
- #3056: a PowerShell `-EncodedCommand` body.
- #3057: a `HOME` or `XDG_CONFIG_HOME` override on a git command.

Partially addressed: #2943, its items on non-POSIX shells, stdin
scripts, editor and config environment, and aliases. Its other items
stay open, and so does #2943.

Closes on promotion: #3010, #2972, #2999, #2989

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants