fix(code-tidying): read porcelain -z so escaped paths reach the audit - #3151
Conversation
|
Claude finished @kyle-sexton's task in 5m 54s —— View job Code review
Scope: What the fix does: replaces Independent verification I ran (not just restating the PR's own claims):
Finding posted inline (detect.sh:111-116): the quote-unescape only reverses No other correctness or maintainability issues found. The rename-arrow split ( |
|
Claude finished @kyle-sexton's task in 2m 8s —— View job Security review complete
No security issues found. This PR replaces an
This is a local, read-only audit script operating on the invoking user's own working tree, so the trust boundary is unchanged by this fix — it only corrects which paths land in the target list, not how they're subsequently handled. Nothing in scope for |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e2438aed0d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Last security-reviewed head: |
|
Claude finished @kyle-sexton's task in 1m 47s —— View job Security review
Result: no security findingsReviewed the full diff ( This PR changes only the porcelain-parsing loop in
Per the lane's skip gate, this change has no security-relevant surface — saying so plainly rather than manufacturing a finding. (Note: there is a minor correctness edge case — the quote-unescaping at L115 only unescapes |
…s survive Review on #3151 surfaced two cases the v1 parse still dropped, both confirmed against git 2.55: * A file literally named `left -> right.py` renders as `?? "left -> right.py"`, indistinguishable from a rename, so the arrow split reduced it to `right.py"` and the file vanished from the target list. * With the default core.quotePath, non-ASCII paths are C-style escaped (`café.py` arrives as `"caf\303\251.py"`). Stripping the quotes left a literal backslash sequence naming no file. Both reproduce the original silent false negative this fix set out to remove, so parse the NUL-delimited -z form instead, which git documents as performing no quoting or backslash-escaping. Under -z a rename emits the NEW path first and the original as a following record (the reverse of v1's display order); that second record is consumed and dropped so a vanished path is never audited. Adds four checks covering an arrow-bearing name, a non-ASCII name, and the rename's discarded original. Three fail against the previous implementation; the fourth guards against a partial-decode regression. Refs #3126 Co-Authored-By: Claude <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 3m 8s —— View job Security review complete
No security issues found. I reviewed the cumulative diff for this PR ( Skip-gate note: this PR has no security-relevant surface in the sense the lane hunts for. On the two Codex P2 findings (quote-decode for non-ASCII paths, and arrow-in-filename mis-splitting a rename): both were filed against the intermediate
Both findings are correctness/false-negative fixes for a local audit tool rather than exploitable vulnerabilities, but it's worth noting they're already closed out by the current HEAD — no further action needed on them from a security standpoint. I did not find anything new to flag beyond what's already been addressed in this PR's history. |
|
Claude has reviewed this PR 5 times. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
|
Claude finished @kyle-sexton's task in 1m 22s —— View job Security review complete
Result: no security findings (skip-gate hit)Scope checked: cumulative diff Skip gate, condition 3 (already-reviewed head still applies): the top commit, The prior commit, On the two Codex P2 findings (non-ASCII quote-escaping, arrow-in-filename mis-split): both were filed against the intermediate No new security-relevant surface was introduced by the latest push. Nothing further to flag. |
|
Heads-up: #3140 merged as Your
Reproduced on main just now, two residue-bearing files in the tree: So the merged fix still carries the exact false negative it set out to remove, for any non-ASCII filename. I documented that as a known residual limitation at the parse site and in the CHANGELOG; you actually solved it. Suggested path: rebase this onto Also relevant to your closing note: I filed #3143 for Sorry for the duplicated effort — the root cause is the broken seam, not your lane. Generated by Claude Code |
|
Claude finished @kyle-sexton's task in 2m 16s —— View job Code review
Skip gate: no new review needed. The code-review lane's skip gate stops early when "this head already has a successful review from this lane that still applies." That's the case here. I diffed the current head ( I independently re-read the parsing block at that link to confirm nothing regressed in the rewording: the No inline findings posted — none survive against unchanged code, and re-litigating already-resolved findings from earlier commits in this PR would be noise, not signal. |
|
Claude finished @kyle-sexton's task in 2m 28s —— View job Security review complete
Result: no security findingsScope checked: this trigger fired on a new commit,
I could not execute No new security-relevant surface was introduced by this merge commit. |
|
Claude finished @kyle-sexton's task in 4m 38s —— View job Code review
Scope note on the diff: Core logic ( What's new in this head: the merge ( Finding
Net effect: for a This isn't hypothetical: Also worth noting: this was flagged in-thread by the PR author themselves as something to carry over — "the SKILL.md pre-computed-context line has the same parse and needs the same treatment" — but the current head doesn't yet include that change. Suggested fix: point Also worth a heads-up (not a code defect, just timing): I was not able to execute the shell scripts in this sandbox (script execution requires approval not granted to this lane), consistent with earlier passes in this thread — the above is based on static reading of the diff and the referenced files, not a test run. |
|
Claude finished @kyle-sexton's task in 44s —— View job Security review complete
Result: no security findings (skip-gate hit)Scope checked: current head I diffed Empty diff — I also confirmed via Per the skip gate: this head has no new security-relevant surface beyond what's already been reviewed ( Nothing further to flag. |
Review on #3151 flagged the divergence this branch had left open: detect.sh reads -z and audits an escaped path, while the `Uncommitted code files` pre-computed context still ran the v1 slice and listed nothing for it. #3140 brought that line to parity deliberately and added a test that extracts and runs it, so leaving it behind reopened the gap that test exists to close, on the surface the model actually reads. The preview now runs the same NUL-delimited read. The parity test was also masking the mismatch. It extracted only the awk program and hardcoded `git status --porcelain` as the input, so a first attempt that hardcoded `-z` instead made the v1 program look correct: -z output carries no quoting for a quote-stripping parse to fail at, and every existing fixture is ASCII. The reader now extracts the porcelain invocation from SKILL.md too, and a non-ASCII fixture joins REPO13 — the only case the two parses do not already agree on. Verified by swapping main's SKILL.md back in: three assertions fail, including #3140's own `SKILL.md preview covers every file detect.sh audits`, which the hardcoded harness had been passing through the divergence. Refs #3126, #3140 Co-Authored-By: Claude <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 1m 34s —— View job Security review complete
Result: no security findingsScope checked: current head
What this commit does: it's the fix for the parity gap I flagged in my own prior code-review pass on this thread —
One thing I specifically traced for a new attack surface:
No security-relevant surface was introduced by this commit. Nothing further to flag — same conclusion as every prior pass in this thread. |
|
Claude finished @kyle-sexton's task in 3m 49s —— View job Code review
Scope: this trigger fired on the new commit
What this commit does: it closes the exact gap I flagged in my last pass on this PR — I traced the new awk program line by line against BEGIN { RS = "\0" }
skip { skip = 0; next }
{ if (substr($0, 1, 2) ~ /[RC]/) skip = 1; print substr($0, 4) }
I could not execute the shell/awk directly in this sandbox (script execution isn't approved for this lane, consistent with every earlier pass in this thread), so this is a static trace rather than a run — but the logic maps 1:1 to the already-verified Test changes ( No new findings — nothing in this delta regressed the already-reviewed parsing logic, and the one open item from my prior pass on this PR is resolved here. |
|
No description provided. |
|
Autopilot pass (lane=babysit-loop): resolved the 2 pre-push-outdated bot threads from chatgpt-codex-connector (both confirmed fixed in b255c4c, verified against current head). Remaining blockers require human action and are escalated rather than auto-resolved:
Not merging. Leaving for human resolution of blocker 2, and optionally filing a follow-up issue to close blocker 1. |
…s survive Review on #3151 surfaced two cases the v1 parse still dropped, both confirmed against git 2.55: * A file literally named `left -> right.py` renders as `?? "left -> right.py"`, indistinguishable from a rename, so the arrow split reduced it to `right.py"` and the file vanished from the target list. * With the default core.quotePath, non-ASCII paths are C-style escaped (`café.py` arrives as `"caf\303\251.py"`). Stripping the quotes left a literal backslash sequence naming no file. Both reproduce the original silent false negative this fix set out to remove, so parse the NUL-delimited -z form instead, which git documents as performing no quoting or backslash-escaping. Under -z a rename emits the NEW path first and the original as a following record (the reverse of v1's display order); that second record is consumed and dropped so a vanished path is never audited. Adds four checks covering an arrow-bearing name, a non-ASCII name, and the rename's discarded original. Three fail against the previous implementation; the fourth guards against a partial-decode regression. Refs #3126 Co-Authored-By: Claude <noreply@anthropic.com>
71cbf40 to
65a7b2c
Compare
Review on #3151 flagged the divergence this branch had left open: detect.sh reads -z and audits an escaped path, while the `Uncommitted code files` pre-computed context still ran the v1 slice and listed nothing for it. #3140 brought that line to parity deliberately and added a test that extracts and runs it, so leaving it behind reopened the gap that test exists to close, on the surface the model actually reads. The preview now runs the same NUL-delimited read. The parity test was also masking the mismatch. It extracted only the awk program and hardcoded `git status --porcelain` as the input, so a first attempt that hardcoded `-z` instead made the v1 program look correct: -z output carries no quoting for a quote-stripping parse to fail at, and every existing fixture is ASCII. The reader now extracts the porcelain invocation from SKILL.md too, and a non-ASCII fixture joins REPO13 — the only case the two parses do not already agree on. Verified by swapping main's SKILL.md back in: three assertions fail, including #3140's own `SKILL.md preview covers every file detect.sh audits`, which the hardcoded harness had been passing through the divergence. Refs #3126, #3140 Co-Authored-By: Claude <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 2m 6s —— View job Code review
Skip gate: no new review needed. Condition 4 applies — this head already has a successful review from this lane that still applies. Current head I verified this by reading the current state directly rather than trusting the rewrite:
I could not run the shell/awk directly in this sandbox (no script-execution approval on this lane, consistent with every earlier pass in this thread), so this is a static read confirming the rewritten head matches what was already dynamically-reasoned-about and reviewed, not a fresh test run. No new findings — nothing to post inline. Re-litigating already-resolved findings from earlier commits in this PR would be noise, not signal. |
|
Claude finished @kyle-sexton's task in 1m 32s —— View job Security review complete
Result: no security findings (skip-gate hit)Scope checked: current head Per this lane's skip gate, condition 3 applies: this head already has a successful security review that still applies. The last fully-reviewed head recorded in this thread's bot marker comment is I verified this rather than trusting the marker blindly: Empty — across the entire repository, not just this PR's files. The commits in between ( That means the current head is byte-identical, in every file, to the commit already scrutinized across multiple passes in this thread ( Nothing further to flag. |
|
🔒 Lane claim + escalation (melo-lap-001-merge-20260823T045045Z, autopilot, PR-queue coordinator). Fresh merge-gate check:
Leaving for human on the signing blocker; the thread can be revisited once the signing issue is resolved and CI settles. |
|
🔧 Lane claim — melo-lap-001-merge-20260823T045045Z (conflict-batch coordinator) Claiming this PR to diagnose and attempt conflict resolution ( |
|
Claude finished @kyle-sexton's task in 1m 51s —— View job Security review complete
Result: no security findings (skip-gate hit)Scope checked: current head That reproduces exactly the PR's reported stats (81 insertions / 31 deletions / 5 files), confirming the PR's true scope is limited to Skip gate, condition 3 applies to the core logic: diffing the last fully-reviewed head, Empty — What's new since the last review:
Nothing further to flag — same conclusion as every prior pass in this thread. |
|
Claude finished @kyle-sexton's task in 46s —— View job Security review complete
Result: no security findings (skip-gate hit)Scope checked: current head I confirmed the PR's actual scope before reviewing, rather than trusting the branch history at face value: reproduces exactly the PR's reported stats (81 insertions / 31 deletions / 5 files), confirming this PR's true scope remains limited to Skip gate, condition 3 applies: diffing the last fully-reviewed head, Both are empty. Everything under Re-read the core logic directly to reconfirm nothing regressed in the merge ( The rest of the merge's content ( Nothing further to flag — same conclusion as every prior pass in this thread. |
Close the residual octal-escape / arrow-bearing-name gap in both porcelain parsers by switching to git status --porcelain -z. Refs #3140
c9c1415 to
6746622
Compare
|
Claude finished @kyle-sexton's task in 1m 16s —— View job Security review complete
Result: no security findingsScope checked: current head — matching the PR's reported stats exactly, and no What changed since the last-reviewed head: the version/changelog rebase from
This is a local, read-only audit tool operating on the invoking user's own working tree; the trust boundary and conclusions are unchanged from every prior pass in this thread. No new security-relevant surface was introduced. |
No related issue: follow-on to the limitation #3140 recorded at its own parse site. #3126 is already closed by that PR, and no issue tracks the residual escape-decode gap.
Summary
#3140 fixed the #3126 false negative by slicing the v1 porcelain record, and recorded the remaining limitation at the parse site:
This PR closes that gap, in both parsers that carry it. It is a follow-on to #3140, not a competing fix.
café.py?? "caf\303\251.py"tab<TAB>here.py?? "tab\there.py"\t— names nothingBoth confirmed against git 2.55. The file is silently dropped, so the run reports a clean tree — the same false-negative class #3126 described.
Fix
Both porcelain parsers in this skill move to the NUL-delimited
--porcelain -zform, which git documents as performing no quoting or backslash-escaping, so there is nothing left to decode.detect.sh— the audit's target router.SKILL.md'sUncommitted code files:preview — the pre-computed context the model reads. fix(code-tidying): parse porcelain by slicing so spaced paths survive discovery #3140 deliberately brought this to parity and added a test that extracts and runs it, so leaving it behind would have reopened the divergence that test exists to prevent: the audit would findcafé.pywhile the preview listed nothing.Under
-za rename emits the new path first and the original as a following record — the reverse of v1's display order — and that second record is consumed and dropped. Rename handling is therefore structural, with no arrow matching, which also resolves the intent-to-add rename #3140 gated on the worktree status letter (R dst\0src\0→dst, verified against git 2.55).Verification
main'sdetect.sh→ fails 2 of case 11's 5 assertions (non-ASCII,tab-bearing). The arrow assertion passes onmain— fix(code-tidying): parse porcelain by slicing so spaced paths survive discovery #3140's[RC]gating already handles it, not claimed here.main'sSKILL.md→ fails 3 assertions, including fix(code-tidying): parse porcelain by slicing so spaced paths survive discovery #3140's ownSKILL.md preview covers every file detect.sh audits.-zto a v1 program makes the v1 program look correct, because-zoutput carries no quoting for it to fail at decoding. It now reads the invocation fromSKILL.mdtoo, andREPO13gains a non-ASCII fixture.mawk 1.3.4(the runner's defaultawk) confirmed to supportRS = "\0"before relying on it.SKILL.md), skill-portability, skill-precompute-compose, changed-skills, leaf-names, count-claims, fixture-git-isolation, orphaned-fixtures, manifest-duplicate-keys,bash -n, changelog-parity in all three modes.ci-status(the required aggregate check) reported success on head65a7b2c; headd7b2b67adds only amainmerge plus the version rebase.Current state — read this before continuing
Head is
d7b2b67, version0.14.2.mainpublished its own0.14.0(#3156) and0.14.1mid-review, so the version was rebased twice; the changelog keeps each published entry intact with this PR's entry above them.One blocker remains, and it is not about the code. The branch's commits are signed with a key that is not registered on the committing GitHub account, so they report
verified=false, reason=unknown_key. That trips two ruleset rules:required_signaturesrequire_extra_approval_for_unattributed_changesEverything else is satisfied: all four required checks green, all review threads resolved, no merge conflicts, and
required_approving_review_countis 0 — so once the signature question is settled this PR needs no human approval.Two ways to settle it:
mainshowscommitter=noreply@github.com, verified=true. Since the repo is squash-merge only, collapsing this branch's commits loses nothing that would survive the merge anyway.Related
0.13.3entry and full test suite are preserved here.code-tidyingto0.14.0mid-review.audit-noisecarries the same defect class. fix(docs-hygiene): gate the porcelain rename split and unescape \\ (0.19.1) #3171 fixed its rename-split half; the octal-escape half is still open and tracked there. Not fixed here — separate plugin, separate version bump.