Skip to content

Read a Push Option Attached to -o as Its Value in the Write Guard #3720

Closed

Description

@ptr727

Found by the local strict review of the fix for #3716, on code that change did not touch.

_push_targets in host-setup/agent-safety/claude/gh-write-guard.py reads an all-letter short-option word as a cluster of flags, force, delete = force or "f" in a, delete or "d" in a, then i += a.endswith("o"). A push option attached to -o is not a cluster, since git reads every character after -o as the option's value. Two misreads follow, both constructed:

  • git push -ofoo origin develop reads f as --force. Because the word ends in o, the reading also consumes origin as the option's value, so develop is read as the remote and the push as a bare push of the current branch.
  • With live rules where develop requires a pull request and the current branch feature/x has no rule, that shape is judged as a force push of feature/x and allowed, while git pushes develop.

The fix is to stop the cluster walk at the first value-taking letter (o), the way _skips_hooks does, so the rest of the word is the value and the next word is consumed only when nothing follows -o. Self-test cases for -ofoo and -o foo would pin it.

Activity

  1. added
    pre-existingReview finding classed pre-existing per local-strict-review Disposing of Findings
    on Oct 31, 2026
  2. ptr727 commented on Nov 1, 2026

    @ptr727
    OwnerAuthor

    Decision needed (decision triage, 2026-11-01)

    Question: Is the fix approved that makes _push_targets in host-setup/agent-safety/claude/gh-write-guard.py stop reading a short-option cluster at o, so the rest of a word like -ofoo is read as the push option's value rather than as flags?

    Options, recommended first:

    1. Approve as proposed, with self-test rows (recommended): A real fail-open: git push -ofoo origin develop reads f as force and consumes origin as the option's value, then judges a bare push of the current feature branch and allows it while git pushes develop. The fix copies the walk _skips_hooks already uses (lines 983-997), and -o <option> is git push's only value-taking short option. Add rows for -ofoo, -o foo, -fofoo. No work in flight.
    2. Approve, fold into the combined guard PR: Same fix carried with Drop the Unused leading_cd and moved Parameters From the Write Guard's Bare-Push Reader #3723/Read a Bare Push's Branch After an Earlier Branch Switch in the Same Command in the Write Guard #3729/Decide Whether Every Bare Push With an Undetermined Repository Fails Closed in the Write Guard #3730 so one PR edits gh-write-guard.py instead of four. Avoids rebase conflicts, but this security fix waits for the larger change. No work in flight.
    3. Decline: Leaves a known bypass of requirement 4. Not defensible. No work in flight.

    Evidence: gh-write-guard.py:861-863 force, delete = force or "f" in a, delete or "d" in a then i += a.endswith("o"). git help push lists -o <option>, --push-option=<option>. Unchanged since #3722 (8d71126).

    Blocks: none

  3. added
    decisionA question waiting on the maintainer, alone or beside whatever else the issue carries
    on Nov 1, 2026
  4. ptr727 commented on Nov 1, 2026

    @ptr727
    OwnerAuthor

    Maintainer answer (decision triage, 2026-11-01): Option 1: approved. Fix _push_targets in gh-write-guard.py to stop reading a short-option cluster at 'o' and take the rest of the word as its value, with self-test rows for -ofoo, -o foo, and -fofoo. Ship it as its own fix. This agent-safety edit is approved for implementation.

  5. removed
    decisionA question waiting on the maintainer, alone or beside whatever else the issue carries
    on Nov 1, 2026
  6. ptr727 commented on Nov 1, 2026

    @ptr727
    OwnerAuthor

    Released (2026-11-01): worktree and branch removed, so this claim holds no files. Its fix merged to develop in PR #3784.

    Backlog burndown claim (round 2, group R2G1). Branch: feature/burn-3720. Issues: #3720.

    Predicted file set:

    • host-setup/agent-safety/claude/gh-write-guard.py, host-setup/agent-safety/claude/test_install.py, host-setup/agent-safety/README.md, tests/test_guard_size.py

    This group edits the agent-safety tree. The worker drives the pull request to the Merge Gate and does not merge it. The merge waits on the maintainer's go-ahead after reading the diff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    pre-existingReview finding classed pre-existing per local-strict-review Disposing of Findings

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions