Skip to content

fix(code-tidying): read porcelain -z so escaped paths reach the audit - #3151

Merged
kyle-sexton merged 1 commit into
mainfrom
fix/residue-porcelain-space-paths
Aug 23, 2026
Merged

fix(code-tidying): read porcelain -z so escaped paths reach the audit#3151
kyle-sexton merged 1 commit into
mainfrom
fix/residue-porcelain-space-paths

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

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:

Git's octal escapes for control and non-ASCII bytes are still not decoded by either, so such a path continues to miss.

This PR closes that gap, in both parsers that carry it. It is a follow-on to #3140, not a competing fix.

Path v1 renders as v1 slice yields
café.py ?? "caf\303\251.py" literal escape sequence — names nothing
tab<TAB>here.py ?? "tab\there.py" literal \t — names nothing

Both 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 -z form, 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's Uncommitted 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 find café.py while the preview listed nothing.

Under -z a 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\0dst, verified against git 2.55).

Verification

  • 53/53 pass, including every one of fix(code-tidying): parse porcelain by slicing so spaced paths survive discovery #3140's checks.
  • Nothing vacuous, checked by reverting each piece:
  • The parity harness was itself masking the defect and is fixed here. It extracted only the awk program and hardcoded the porcelain invocation; feeding -z to a v1 program makes the v1 program look correct, because -z output carries no quoting for it to fail at decoding. It now reads the invocation from SKILL.md too, and REPO13 gains a non-ASCII fixture.
  • mawk 1.3.4 (the runner's default awk) confirmed to support RS = "\0" before relying on it.
  • Local gates green: typos, shell-portability (scripts and 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 head 65a7b2c; head d7b2b67 adds only a main merge plus the version rebase.

Current state — read this before continuing

Head is d7b2b67, version 0.14.2. main published its own 0.14.0 (#3156) and 0.14.1 mid-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_signatures
  • require_extra_approval_for_unattributed_changes

Everything else is satisfied: all four required checks green, all review threads resolved, no merge conflicts, and required_approving_review_count is 0 — so once the signature question is settled this PR needs no human approval.

Two ways to settle it:

  1. Register the signing key on the account (Settings → SSH and GPG keys → New SSH key, type Signing Key). No push needed; the existing commits become verified, and the commit history is preserved.
  2. Rebuild the branch through the GitHub API. Commits created via the API are signed by GitHub and verify automatically — that is why every commit on main shows committer=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

@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 5m 54s —— View job


Code review

  • Gather context (PR diff, changed files)
  • Invoke /review:code-review skill and follow its instructions
  • Post findings as inline PR comments where anchorable
  • Summarize review in this comment

Scope: plugins/code-tidying/skills/audit-comment-residue/scripts/detect.sh and detect.test.sh (the only changed files). Security concerns are out of scope for this lane — claude-security-review.yml covers that separately.

What the fix does: replaces git status --porcelain | awk '{print $NF}' with a manual parse (${line:3}, take the right side of old -> new, strip surrounding quotes and unescape \"), matching the sibling audit-noise/detect.sh implementation exactly.

Independent verification I ran (not just restating the PR's own claims):

  • Confirmed empirically that git status --porcelain does quote paths containing a plain space (?? "my helper.sh"), validating the PR's core premise — I could not run the test suite itself in this sandbox (script execution required approval I don't have here), so I verified the underlying git behavior directly instead.
  • Traced the parse logic against actual porcelain output for the untracked-space and rename-with-space cases described in the PR body — both resolve correctly.
  • Diffed against plugins/docs-hygiene/skills/audit-noise/scripts/detect.sh and confirmed this is a faithful, byte-for-byte port of the parsing block (minus the .md filter, which doesn't apply here).

Finding posted inline (detect.sh:111-116): the quote-unescape only reverses \"", not git's other C-style escapes. Since core.quotePath defaults to true, a non-ASCII filename like café.sh porcelains as ?? "caf\303\251.sh" (verified by touching such a file locally), and after this block runs the target path is still the literal escaped string, so it won't match anything on disk — a residual instance of the same silent-drop failure mode this PR fixes for spaces. This is not a regression: it mirrors audit-noise/detect.sh's existing parse verbatim, so the same gap already exists there. Flagged as non-blocking — worth a follow-up across both files rather than blocking this PR, since the stated goal here was consistency with the already-shipped sibling implementation, not a from-scratch parser.

No other correctness or maintainability issues found. The rename-arrow split (${local_path##* -> }) has a theoretical mis-parse if the new filename itself contained the literal substring " -> ", but that's vanishingly unlikely and identically present in the sibling script, so I didn't flag it separately.
· branch

@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 2m 8s —— View job


Security review complete

  • Gather context (PR diff, changed files)
  • Review detect.sh parsing changes for security-relevant issues
  • Review detect.test.sh changes
  • Post final findings

No security issues found.

This PR replaces an awk '{print $NF}' parse of git status --porcelain with an explicit slice (${line:3}), rename-arrow split, and quote-strip in detect.sh. I traced how the resulting local_path values flow downstream:

  • They're appended to the TARGETS array and only ever consumed via quoted expansions — [[ -d "$target" ]], find "$target" -type f, cr_is_code_file "$target" (L124-L134), and later audit_file "$file" which does [[ -f "$file" ]] and <"$file" — no eval, no sh -c, no unquoted word-splitting/glob context anywhere in the diff. A filename containing shell metacharacters (backticks, ;, $(...), embedded quotes) cannot achieve command injection here, whether it arrives via this new parse path or the old one.
  • Paths from git status --porcelain are repo-relative and can't escape the working tree through this parsing logic; the cd "$repo_root" anchoring is unchanged from before this diff.
  • The quote-unescaping (${local_path//\\\"/\"}) only unwinds git's \" escaping of embedded quotes — it doesn't introduce new decoding of attacker-controlled escape sequences into anything executed.
  • detect.test.sh's new fixtures use mktemp -d with an EXIT trap for cleanup and unset GIT_DIR/GIT_WORK_TREE/GIT_CONFIG before git init, consistent with this repo's existing fixture-isolation convention — no shared/predictable temp paths.

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 zizmor/Actions concerns either — no workflow files are touched.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 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".

Comment thread plugins/code-tidying/skills/audit-comment-residue/scripts/detect.sh Outdated
Comment thread plugins/code-tidying/skills/audit-comment-residue/scripts/detect.sh Outdated
@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown

Last security-reviewed head: 2df47e6f25b8026c81407ac47ee1fb0506d23b0a. On the next push, the relevance gate compares only the commits since this SHA; delete this comment to force a full re-review.

@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 47s —— View job


Security review

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions
  • Post findings
  • Summarize review in this comment

Result: no security findings

Reviewed the full diff (plugins/code-tidying/skills/audit-comment-residue/scripts/detect.sh, detect.test.sh, plus the version bump and changelog entry) against the security-review criteria: injection surfaces, unsafe path/credential handling, authz gaps, and GitHub Actions trust-boundary risk.

This PR changes only the porcelain-parsing loop in detect.sh, a read-only, local repo-analysis tool. Findings from that surface:

  • Every derived path (local_path) stays inside double-quoted expansions throughout — [[ -d "$target" ]], find "$target" -type f, [[ -f "$file" ]], <"$file" — with no eval, no unquoted interpolation, and no string built for a shell/sh -c call. Bash quoting isn't defeated by adversarial filename content here, so there's no command-injection path even for maliciously named files.
  • Porcelain paths are repo-relative and consumed only after the script has already cd'd into repo_root, so a crafted filename can at most cause a wrong-but-still-in-repo file to be read — no path traversal outside the working tree, and no privilege boundary is crossed (the caller already has read access to everything in the repo).
  • No secrets, tokens, network calls, or GitHub Actions workflow files are touched by this PR; the printf calls use %s placeholders throughout, so file/excerpt content can't be interpreted as a format string.

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 \" and not \\, so a filename containing a literal backslash would still silently drop out of the target list — but that's a code-quality concern, not a security one, so it's out of scope for this lane.)

kyle-sexton pushed a commit that referenced this pull request Aug 23, 2026
…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>
Comment thread plugins/code-tidying/skills/audit-comment-residue/scripts/detect.sh
@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 3m 8s —— View job


Security review complete

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review skill and follow its instructions
  • Post findings as inline PR comments where anchorable
  • Summarize review in this comment

No security issues found.

I reviewed the cumulative diff for this PR (dff0942..b255c4c, i.e. all three commits: e2438ae, 0b3ad5a, b255c4c) against /review:security-review's criteria — logic flaws, injection surfaces, trust-boundary gaps, unsafe token/credential handling, and dangerous Actions patterns. No .github/workflows files are touched, so the Actions-specific checks don't apply here.

Skip-gate note: this PR has no security-relevant surface in the sense the lane hunts for. detect.sh is a read-only, local dev tool that audits the invoking user's own working tree — no eval, no sh -c, no unquoted expansion, no network calls, no writes, no secret handling. Every local_path/file value flows only into quoted contexts ([[ -f "$file" ]], find "$target" -type f, <"$file"), so a filename containing shell metacharacters, backticks, or embedded quotes cannot achieve command injection via this parse path.

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 awk/quote-strip approach in e2438ae. The final commit (b255c4c) supersedes that approach and resolves both:

  • It switches to git status --porcelain -z, which git documents as emitting raw bytes with no quoting or C-style escaping at all — so the non-ASCII/café.py-style decode gap Codex flagged no longer applies; there's nothing to decode.
  • It now branches on the actual XY status letters ([RC]? | ?[RC] in detect.sh#L110-L115) rather than string-matching " -> ", so an ordinary filename that happens to contain an arrow (e.g. left -> right.py) is no longer misparsed as a rename.
  • detect.test.sh gained regression coverage for exactly these cases (REPO9/REPO10: spaces, staged renames, arrow-in-filename, non-ASCII), consistent with the PR's stated 31/31 pass claim.

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.

@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown

Claude has reviewed this PR 5 times. The lane skips further automatic reviews after 5; deleting this comment resets the count.

@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 22s —— View job


Security review complete

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions
  • Post findings
  • Summarize review in this comment

Result: no security findings (skip-gate hit)

Scope checked: cumulative diff dff0942...1769ecf (all 4 commits: e2438ae, 0b3ad5a, b255c4c, 1769ecf), across plugins/code-tidying/skills/audit-comment-residue/scripts/detect.sh, detect.test.sh, plugin.json, CHANGELOG.md. No .github/workflows files are touched, so the Actions-specific criteria don't apply.

Skip gate, condition 3 (already-reviewed head still applies): the top commit, 1769ecf, changes only comment wording and a changelog sentence — rewording the café.py escape example ("caf\303\251.py" → "an é becomes \303\251") so a typo-checker stops misreading caf as a word. I diffed b255c4c...1769ecf directly to confirm: zero lines of executable logic changed in detect.sh or detect.test.sh, only three comment/doc lines.

The prior commit, b255c4c (the actual parsing logic — switch to git status --porcelain -z), already received a full cumulative security review in this thread (dff0942..b255c4c, all three logic-bearing commits) with no findings: every derived path stays inside quoted expansions ([[ -d "$target" ]], find "$target" -type f, [[ -f "$file" ]], <"$file"), no eval/sh -c, no unquoted interpolation, no network/secrets/credentials touched, and porcelain paths are repo-relative and consumed only after cd "$repo_root" — no traversal outside the working tree. That review remains fully applicable since no logic changed after it.

On the two Codex P2 findings (non-ASCII quote-escaping, arrow-in-filename mis-split): both were filed against the intermediate e2438ae/0b3ad5a parse and are resolved by the -z switch in b255c4c (no quoting/escaping performed under -z, and rename detection no longer relies on string-matching ->). Both are correctness/false-negative fixes for a local, read-only audit tool, not exploitable vulnerabilities, and are unchanged by 1769ecf.

No new security-relevant surface was introduced by the latest push. Nothing further to flag.
· branch

Copy link
Copy Markdown
Contributor Author

Heads-up: #3140 merged as 9a6c649f (0.13.3) about 15 minutes ago, closing #3126. Two lanes were working this issue concurrently — I claimed #3126 at 02:47 (assignee + lease comment 5383867114), but the tracker seam is unusable in these containers (gh 2.45 vs. the >= 2.94 the adapter requires, plus an invalid GH_TOKEN), so the lease could not do its job. This base has moved and this PR is now dirty; its 0.13.2 → 0.13.3 bump also collides, since main is already at 0.13.3.

Your -z approach is better than what merged, and I verified that rather than assuming it. Checking your two claimed gaps against the code now on main:

Case Merged 0.13.3 parse Verdict
left -> right.py (ordinary file) parses to left -> right.py, audited ✅ already handled — the merged split is gated on the R/C status letter, so it never fires on a ?? record. Your table describes audit-noise's ungated v1 split, not this one.
café.py (default core.quotePath) parses to caf\303\251.py, exists=NO, silently dropped confirmed — you're right.

Reproduced on main just now, two residue-bearing files in the tree:

?? "caf\303\251.py"
?? "left -> right.py"
  parsed=[caf\303\251.py]     exists=NO
  parsed=[left -> right.py]   exists=YES
Summary total: files=1 T1=1 T2=0 T3=0     <-- should be 2

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. --porcelain -z emits ?? café.py unquoted and sidesteps the whole unquoting problem.

Suggested path: rebase this onto 9a6c649f and reduce it to the -z conversion — the -z parse supersedes the merged string-parse entirely, so the slice/gate/unescape logic in detect.sh comes out rather than being layered on. Worth keeping from #3140 when you rebase: the SKILL.md pre-computed-context line has the same parse and needs the same treatment, and detect.test.sh section 10 extracts that awk program from SKILL.md and executes it so the two can't silently diverge. Also note the rename-record ordering difference you flagged — under -z the new path comes first with the old as a following record — which the merged tests' cases 9b/9c/9d will need updating for.

Also relevant to your closing note: I filed #3143 for audit-noise's parse before seeing this PR. It records the ungated-split defect and the missing \\ unescape; your non-ASCII finding applies there too and is worth adding.

Sorry for the duplicated effort — the root cause is the broken seam, not your lane.


Generated by Claude Code

@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 2m 16s —— View job


Code review

  • Gather context (PR diff, changed files)
  • Invoke /review:code-review skill and follow its instructions
  • Post findings as inline PR comments where anchorable
  • Summarize review in this comment

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 (1769ecf) against b255c4c — the commit already fully reviewed by both this lane and the security lane across four prior passes, with every finding (non-ASCII quote-decode, arrow-in-filename mis-split, backslash-unescape gap) confirmed resolved by the switch to --porcelain -z. 1769ecf changes zero functional code: it only reworks three comment/changelog wordings (detect.sh:103, detect.test.sh, CHANGELOG.md) to stop a spell-checker from misreading the escaped-string example "caf\303\251.py" as the word caf/calf. detect.sh#L100-L117 is byte-identical in logic to what was already reviewed.

I independently re-read the parsing block at that link to confirm nothing regressed in the rewording: the -z NUL-delimited read, the [RC]?|?[RC] rename-record consumption, and the ${record:3} path extraction are unchanged and still correct per git's documented -z behavior (no quoting/escaping) and the rename-record order kyle-sexton verified against git 2.55 in the review thread.

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.
· branch

@kyle-sexton kyle-sexton changed the title fix(code-tidying): parse porcelain without $NF so spaced paths survive fix(code-tidying): read porcelain -z so escaped paths reach the audit Aug 23, 2026
@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 2m 28s —— View job


Security review complete

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions
  • Post findings
  • Summarize review in this comment

Result: no security findings

Scope checked: this trigger fired on a new commit, 6b00623 — a merge of origin/main into this branch, reconciling this PR's -z porcelain parse with the overlapping fix that landed separately as #3140/9a6c649. The skip gate's "already reviewed" condition doesn't apply here since this exact commit hasn't been reviewed before, so I diffed it against the branch's prior tip (1769ecf, already fully reviewed) to isolate what the merge itself changed:

  • detect.shbyte-identical to 1769ecf. The merge kept this branch's --porcelain -z parse rather than main's v1-slice version, exactly as the merge commit message states. No new logic to review; the prior cumulative review (quoted expansions throughout, no eval/sh -c, repo-relative paths consumed only after cd "$repo_root") still applies unchanged.
  • plugin.json / CHANGELOG.md — version bump (0.13.30.13.4, resolving the collision with main) and prose only. No executable content.
  • SKILL.md — the Uncommitted code files: pre-computed-context line is pulled in from main's 9a6c649 (this branch hadn't touched it before). It's a local git status --porcelain | awk '...' one-liner with no external input, no eval, and no network/credential access — reads the invoking user's own working tree only, same trust boundary as the rest of this skill.
  • detect.test.sh — expanded fixture set (rename/space/non-ASCII combinations, plus a new section 10 that extracts and executes the SKILL.md awk program against fixtures to keep the two parsers from silently diverging). All fixtures use mktemp -d + EXIT trap and unset GIT_DIR GIT_WORK_TREE GIT_CONFIG before git init, matching this repo's existing isolation convention — no shared/predictable temp paths, no unsanitized input reaching eval or a shell interpolation context. The extracted awk program comes from this repo's own tracked SKILL.md, not from any external or attacker-controlled source, so it isn't an injection surface (editing it already requires repo write access).
  • No .github/workflows files are touched by this commit — confirmed via git diff 1769ecf 6b00623 --stat -- .github/ (empty).

I could not execute detect.test.sh in this sandbox (no shell-execution approval available), so I verified the diff by reading rather than running — consistent with what prior reviews in this thread noted about their own sandbox limits. This lane covers security only; correctness/test-pass status is the code-review lane's concern and was already addressed by kyle-sexton's own local verification in the PR body.

No new security-relevant surface was introduced by this merge commit.
· branch

@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 4m 38s —— View job


Code review

  • Gather context (PR diff, changed files)
  • Invoke /review:code-review skill and follow its instructions
  • Post findings as inline PR comments where anchorable
  • Summarize review in this comment

Scope note on the diff: origin/main has advanced past this branch's rebase point (unrelated PR #3156 bumped code-tidying to 0.14.0 after this branch merged in 9a6c649/0.13.3). Diffing straight against current origin/main tip would conflate that unrelated churn with this PR's own changes, so I diffed HEAD (6b00623) against b6e0c57 — the actual main commit this branch merged in — which reproduces the PR's reported stats exactly (52 insertions / 29 deletions / 4 files). That's the diff I reviewed.

Core logic (detect.sh, detect.test.sh): unchanged from b255c4c/1769ecf, both already reviewed exhaustively across five prior passes in this thread (code-review + security-review), including independent verification of the -z NUL-delimited read, the [RC]?|?[RC] rename-record gating, and the reversed rename-record order under -z. Nothing new to add there — re-litigating settled findings would be noise, not signal.

What's new in this head: the merge (6b00623) plus the version/changelog reconciliation (0.13.30.13.4, avoiding the collision with main's already-shipped 0.13.3). That reconciliation is correct on its own.

Finding

SKILL.md's pre-computed-context line was left on the v1 parse this PR retires in detect.sh, so the same silent-drop defect this PR fixes still reaches the model's context preview.

SKILL.md:16 still runs the v1 awk program (quote-strip + \"/\\ unescape only) that #3140 added to keep parity with detect.sh at the time. This PR moves detect.sh to git status --porcelain -z (no quoting/escaping at all), but never touches SKILL.md's line — confirmed by diffing dff0942..b6e0c57 (where #3140 added the v1 program to SKILL.md to match detect.sh's then-current v1 parse) against this PR's own diff (which never lists SKILL.md as a changed file, across all 5 commits).

Net effect: for a café.py-style non-ASCII path, detect.sh now correctly audits it, but the skill's own "Uncommitted code files" preview line still renders the raw C-style-escaped garbage (caf\303\251.py) and matches nothing — the exact "confident nothing-here" false negative this PR's own description calls out as the reason the bug was worth fixing rather than tidying, just moved to a different surface.

This isn't hypothetical: detect.test.sh's section 10 (SKILL.md pre-computed-context parser stays at parity with detect.sh, added by #3140) exists specifically to catch this class of divergence, but its REPO13 fixtures (quote".py, back\-slash.py, plain space.py, a worktree rename) are all ASCII — none exercise the non-ASCII case section 11's new REPO14 fixtures added for detect.sh (café.py). So the parity test still passes green while the two parsers have in fact diverged on exactly the case this PR was written to close.

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 SKILL.md's awk-based preview at the same -z read detect.sh now uses (or simplify it to shell out to detect.sh's own target-discovery logic), and extend detect.test.sh section 10's REPO13 fixtures with a non-ASCII name so this parity gap can't silently reopen. Fix this → (non-blocking — the audit script itself, the actual finding source, is fixed; this is the preview-context surface only)

Also worth a heads-up (not a code defect, just timing): origin/main has moved again since this branch's b6e0c57 merge point — code-tidying is now at 0.14.0 on main (via #3156), one minor ahead of this PR's 0.13.4. The changelog-parity gate will likely need another rebase pass before merge.

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.
· branch

@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 44s —— View job


Security review complete

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions
  • Post findings
  • Summarize review in this comment

Result: no security findings (skip-gate hit)

Scope checked: current head c6f56f1, a merge of origin/main that lands the unrelated #3156 (dissolve-comments feature) and rebases this PR's version to 0.14.1.

I diffed 6b00623..c6f56f1 (the branch tip before this merge, which already received a full cumulative security review earlier in this thread with no findings) restricted to this PR's actual changed-file set:

git diff 6b00623..HEAD -- plugins/code-tidying/skills/audit-comment-residue/

Empty diffdetect.sh and detect.test.sh are byte-identical to the already-reviewed 6b00623 state. The wider 6b00623..HEAD diff (docs/CATALOG.md, dissolve-comments/*, source-control/*, worktree/*) is entirely origin/main content pulled in by the merge and unrelated to this PR's scope — those files belong to #3156 and other already-merged work, not this branch's changes.

I also confirmed via git diff origin/main...HEAD --stat that this PR's total change set is still exactly the 4 files listed in the PR (plugin.json, CHANGELOG.md, detect.sh, detect.test.sh), and git diff origin/main...HEAD -- .github/workflows/ is empty — no workflow files touched.

Per the skip gate: this head has no new security-relevant surface beyond what's already been reviewed (dff0942..b255c4c for the parsing logic itself, 1769ecf for comment rewording, 6b00623 for the main-merge reconciliation). The -z porcelain parse in detect.sh remains: quoted-only path usage ([[ -d "$target" ]], find "$target" -type f, <"$file"), no eval/sh -c, no network/secrets, and repo-relative paths consumed only after cd "$repo_root".

Nothing further to flag.
· branch

kyle-sexton pushed a commit that referenced this pull request Aug 23, 2026
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

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 34s —— View job


Security review complete

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions
  • Post findings
  • Summarize review in this comment

Result: no security findings

Scope checked: current head 71cbf40, which adds one new commit on top of c6f56f1 (already reviewed in full in this thread with no findings). I isolated what changed since that last-reviewed head:

git diff c6f56f1..71cbf40 --stat
 plugins/code-tidying/CHANGELOG.md                                       | 10 ++++++++++
 plugins/code-tidying/skills/audit-comment-residue/SKILL.md              |  2 +-
 plugins/code-tidying/skills/audit-comment-residue/scripts/detect.test.sh | 19 ++++++++++++++++++-

detect.sh — the actual audit logic, and the surface every prior pass in this thread scrutinized — is byte-identical to c6f56f1. No .github/ files are touched (confirmed via git diff c6f56f1..71cbf40 --stat -- .github/, empty).

What this commit does: it's the fix for the parity gap I flagged in my own prior code-review pass on this thread — SKILL.md's Uncommitted code files: pre-computed-context line was still on the v1 quote-strip parse while detect.sh had moved to --porcelain -z, so a non-ASCII file could be audited but not previewed. This commit moves that line to the same -z/NUL-delimited read:

SKILL.md:16git status --porcelain -z 2>/dev/null | awk 'BEGIN { RS = "\0" } skip { skip = 0; next } { if (substr($0, 1, 2) ~ /[RC]/) skip = 1; print substr($0, 4) }' | grep -Ei '\.(cs|ts|tsx|...)$' | head -10. This is the same local, read-only, no-network, no-secret pattern already reviewed for detect.sh's -z parse — it reads the invoking user's own working tree via a command embedded in a tracked, repo-authored SKILL.md file (the same trust boundary Claude Code's own pre-computed-context mechanism already assumes for every skill in this repo).

One thing I specifically traced for a new attack surface: detect.test.sh:286 now does eval "$skill_porcelain", where skill_porcelain is extracted via sed from SKILL.md (line 254 resolves SKILL_MD="$SCRIPT_DIR/../SKILL.md" — the repo's own tracked file, not user input or anything fetched at runtime). This is new use of eval in the test harness, but it doesn't cross a trust boundary: whoever can edit SKILL.md already has repo write access, and the same content is already executed as a shell command by Claude Code's own ! backtick mechanism when the skill loads. The CHANGELOG entry itself explains why this indirection exists — hardcoding the porcelain invocation in the test would let a future v1-parse regression pass silently, since -z output has no quoting for a v1 program to fail at decoding. That's a test-robustness rationale, not a security-relevant one.

CHANGELOG.md is prose only.

No security-relevant surface was introduced by this commit. Nothing further to flag — same conclusion as every prior pass in this thread.
· branch

@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 3m 49s —— View job


Code review

  • Gather context (PR diff, changed files)
  • Invoke /review:code-review skill and follow its instructions
  • Post findings as inline PR comments where anchorable
  • Summarize review in this comment

Scope: this trigger fired on the new commit 71cbf40 — "move the SKILL.md preview to -z alongside detect.sh." I diffed it against 6b00623 (the branch tip already reviewed exhaustively earlier in this thread) to isolate what's new:

git diff 6b00623..71cbf40 --stat -- plugins/code-tidying/
 plugin.json          |  4 +-
 CHANGELOG.md         | 46 +++++++++++++++++++++-
 SKILL.md             |  2 +-
 detect.test.sh       | 19 ++++++++-

detect.sh is untouched — the byte-for-byte-reviewed -z parsing logic (dff0942..b255c4c) carries over unchanged.

What this commit does: it closes the exact gap I flagged in my last pass on this PR — SKILL.md's Uncommitted code files: preview line was still on the v1 quote-strip parse while detect.sh had moved to -z, so a café.py-style path would be audited by detect.sh but silently missing from the model's own preview.

I traced the new awk program line by line against detect.sh's already-reviewed bash loop (detect.sh:106-117) to confirm they're equivalent:

BEGIN { RS = "\0" }
skip { skip = 0; next }
{ if (substr($0, 1, 2) ~ /[RC]/) skip = 1; print substr($0, 4) }
  • Rule 2 fires on every non-skipped record; if the status field contains R/C it sets skip=1 and still prints this record (the new path) — matches detect.sh printing the new path before gating the next read.
  • Rule 1 then consumes the following record (the bare original path a rename emits second under -z) via next, without inspecting its content as a status code — matches detect.sh's read -r -d '' _ discard.
  • substr($0,1,2) ~ /[RC]/ is an unanchored 2-char substring test, equivalent to detect.sh's [RC]? | ?[RC] case pattern (either status column being R/C).

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 detect.sh implementation.

Test changes (detect.test.sh): the REPO13 parity block now extracts both the awk program and the porcelain invocation from SKILL.md (previously only the awk program was extracted, with the -z flag hardcoded in the harness). That's the right fix, not just extra coverage — hardcoding -z in the test would have let a SKILL.md still on plain --porcelain pass anyway, since -z-shaped input happens to make the v1 awk program "work" (no quoting to trip over). Reading the actual invocation off SKILL.md closes that masking risk. The new café.py fixture plus assert_contains .. 'café.py' / assert_not_contains .. '\303' exercise exactly the case this commit fixes.

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.
· branch

@kyle-sexton

Copy link
Copy Markdown
Contributor Author

No description provided.

@kyle-sexton

Copy link
Copy Markdown
Contributor Author

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:

  1. Unresolved thread from claude (non-blocking per its own text, proposes a follow-up covering the same octal-escape gap in audit-noise/detect.sh too) — no code fix has landed for it yet. Deferring this thread needs a filed tracker item before it can be dispositioned deferred via the independent-resolver path; none exists yet.
  2. Unsigned-identity blocker: base branch requires signed commits, and 7 commits on this branch (e2438ae, 0b3ad5a, b255c4c, 1769ecf, 6b00623, c6f56f1, 71cbf40) carry valid signatures but an author/committer email not linked to any GitHub account. Fix requires either linking that email under GitHub account settings, or rewriting the commits with --reset-author — the latter needs a force-push, which this lane never performs autonomously.

Not merging. Leaving for human resolution of blocker 2, and optionally filing a follow-up issue to close blocker 1.

kyle-sexton added a commit that referenced this pull request Aug 23, 2026
…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>
@kyle-sexton
kyle-sexton force-pushed the fix/residue-porcelain-space-paths branch from 71cbf40 to 65a7b2c Compare August 23, 2026 14:59
kyle-sexton added a commit that referenced this pull request Aug 23, 2026
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

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 2m 6s —— View job


Code review

  • Gather context (PR diff, changed files)
  • Invoke /review:code-review skill and follow its instructions
  • Post findings as inline PR comments where anchorable
  • Summarize review in this comment

Skip gate: no new review needed. Condition 4 applies — this head already has a successful review from this lane that still applies.

Current head 65a7b2c carries the same content this lane already reviewed exhaustively as 71cbf40 earlier in this thread — the only difference is the commits were rewritten (new hashes, same messages/content) somewhere along the way, plus two origin/main merges that pulled in unrelated, already-merged work (#3140, #3156) and a version bump to 0.14.1 to avoid the resulting collision.

I verified this by reading the current state directly rather than trusting the rewrite:

  • detect.sh — byte-identical logic to what was already traced line-by-line in this thread: --porcelain -z read, [RC]?|?[RC] rename-record gating and discard, ${record:3} slice. No quoting/escaping left to decode.
  • SKILL.md:16 — the preview line's awk program still matches detect.sh's parse (confirmed the one finding I raised in an earlier pass on this PR — the preview lagging on the v1 parse — is the fix that's already landed here, not still open).
  • detect.test.sh — REPO13 now carries the café.py fixture and extracts the porcelain invocation from SKILL.md (not just the awk program), closing the masking risk where -z-shaped input would make a stale v1 parser look correct.
  • plugin.json/CHANGELOG.md — version now 0.14.1, changelog entry sits correctly above the already-published 0.13.3/0.14.0 entries with no collision.

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.
· branch

@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 32s —— View job


Security review complete

  • Gather context (PR diff, changed files, HEAD SHA)
  • Invoke /review:security-review and follow its instructions
  • Post findings
  • Summarize review in this comment

Result: no security findings (skip-gate hit)

Scope checked: current head 65a7b2c.

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 71cbf40, reviewed with no findings.

I verified this rather than trusting the marker blindly:

git diff 71cbf40f951e5b35f41970d8b67449272956e1d7 65a7b2ca45adb0881059acd1461883e0df1786ea --stat

Empty — across the entire repository, not just this PR's files. The commits in between (c5b2ff2, fb28ebc, e7c8c9b, a7b6348, 301e3cc, 16c7541) are rebase/merge artifacts from reconciling origin/main's advance to 0.14.1 — same tree content under different commit hashes/parents, not new changes. I also confirmed .github/workflows/ shows no diff between the two heads, so the Actions-specific criteria don't newly apply either.

That means the current head is byte-identical, in every file, to the commit already scrutinized across multiple passes in this thread (dff0942..b255c4c for the core -z porcelain parse in detect.sh, 1769ecf for comment rewording, 6b00623/c6f56f1 for the main-merge reconciliations, and 71cbf40 for the SKILL.md preview parity fix). Every derived path in that logic stays inside quoted expansions ([[ -d "$target" ]], find "$target" -type f, <"$file"), with no eval/sh -c in detect.sh, no network/credential access, and paths consumed only after cd "$repo_root" — conclusions that still hold since nothing changed.

Nothing further to flag.
· branch

@kyle-sexton

Copy link
Copy Markdown
Contributor Author

🔒 Lane claim + escalation (melo-lap-001-merge-20260823T045045Z, autopilot, PR-queue coordinator).

Fresh merge-gate check: mergeStateStatus=BLOCKED. Two independent blockers:

  1. Unsigned/unregistered-key commits — 7 commits fail signature verification with reason=unknown_key (signed with a key not registered on the committer's GitHub account). Requires uploading the public key to the account or re-signing with a registered key — a human/machine-config action outside this lane's authority.
  2. One unresolved review thread from claude (not outdated) plus ci-status not yet satisfied as of this check (other required checks were still pending). This PR is self-authored (kyle-sexton), so autonomous/independent-resolver thread resolution refuses by design (self-login guard) even once addressed.

Leaving for human on the signing blocker; the thread can be revisited once the signing issue is resolved and CI settles.

@kyle-sexton

Copy link
Copy Markdown
Contributor Author

🔧 Lane claim — melo-lap-001-merge-20260823T045045Z (conflict-batch coordinator)

Claiming this PR to diagnose and attempt conflict resolution (/source-control:resolve-conflicts) against current main. Will push if resolution succeeds, or report the specific blocker if not. No merge will be performed by this pass.

@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 51s —— View job


Security review complete

  • Gather context (PR diff, changed files, HEAD SHA)
  • Invoke /review:security-review and follow its instructions
  • Post findings
  • Summarize review in this comment

Result: no security findings (skip-gate hit)

Scope checked: current head d7b2b67 — a merge of origin/main that rebases this PR's version onto 0.14.2. I confirmed this PR's actual scope against origin/main (tip 49c3d37) rather than trusting the branch history at face value, since the repo checkout here is shallow and a merge-base diff (origin/main...HEAD) isn't resolvable:

git diff origin/main HEAD --stat -- plugins/code-tidying/skills/audit-comment-residue/ \
  plugins/code-tidying/.claude-plugin/plugin.json plugins/code-tidying/CHANGELOG.md

That reproduces exactly the PR's reported stats (81 insertions / 31 deletions / 5 files), confirming the PR's true scope is limited to detect.sh, detect.test.sh, SKILL.md, plugin.json, and CHANGELOG.md in plugins/code-tidying/. No .github/workflows files are touched (git diff origin/main HEAD --stat -- .github/ is empty).

Skip gate, condition 3 applies to the core logic: diffing the last fully-reviewed head, 65a7b2c (reviewed with no findings earlier in this thread), against current HEAD, restricted to the skill directory:

git diff 65a7b2c d7b2b67 --stat -- plugins/code-tidying/skills/audit-comment-residue/

Emptydetect.sh, detect.test.sh, and SKILL.md are byte-identical to the state already reviewed multiple times in this thread with no findings: the --porcelain -z NUL-delimited parse (no quoting/escaping to decode), [RC]?|?[RC] rename-record gating and discard, all derived paths consumed only inside quoted expansions ([[ -f "$file" ]], find "$target" -type f, <"$file"), no eval/sh -c in detect.sh, and repo-relative paths used only after cd "$repo_root".

What's new since the last review: plugin.json (version 0.14.10.14.2) and CHANGELOG.md (prose entry only, reflowed above the already-published 0.14.1/0.14.0/0.13.x entries) — both metadata/prose, no executable content, no security surface.

detect.test.sh's use of eval "$skill_porcelain" (added earlier in this thread to extract the porcelain invocation from SKILL.md for parity testing) was already reviewed and found not to cross a trust boundary — it evaluates this repo's own tracked SKILL.md content, not external or attacker-controlled input; unchanged here.

Nothing further to flag — same conclusion as every prior pass in this thread.
· branch

@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 46s —— View job


Security review complete

  • Gather context (PR diff, changed files, HEAD SHA)
  • Invoke /review:security-review and follow its instructions
  • Post findings
  • Summarize review in this comment

Result: no security findings (skip-gate hit)

Scope checked: current head c9c1415 — a merge of origin/main (which pulled in #3188, an unrelated docs-hygiene/d1-measurement spec batch, plus work-items changes).

I confirmed the PR's actual scope before reviewing, rather than trusting the branch history at face value:

git diff origin/main HEAD --stat -- plugins/code-tidying/skills/audit-comment-residue/ \
  plugins/code-tidying/.claude-plugin/plugin.json plugins/code-tidying/CHANGELOG.md

reproduces exactly the PR's reported stats (81 insertions / 31 deletions / 5 files), confirming this PR's true scope remains limited to detect.sh, detect.test.sh, SKILL.md, plugin.json, and CHANGELOG.md under plugins/code-tidying/.

Skip gate, condition 3 applies: diffing the last fully-reviewed head, d7b2b67 (reviewed with no findings earlier in this thread), against current HEAD:

git diff d7b2b67 c9c1415 --stat -- plugins/code-tidying/
git diff d7b2b67 c9c1415 --stat -- .github/

Both are empty. Everything under plugins/code-tidying/skills/audit-comment-residue/detect.sh, detect.test.sh, SKILL.md — is byte-identical to the state already reviewed multiple times in this thread with no findings, and no .github/workflows files are touched by this merge.

Re-read the core logic directly to reconfirm nothing regressed in the merge (detect.sh#L106-L117): the --porcelain -z NUL-delimited read (no quoting/escaping to decode), [RC]?|?[RC] rename-record gating with the trailing record consumed and discarded, and ${record:3} slicing. Every derived path is used only inside quoted expansions downstream ([[ -d "$target" ]], find "$target" -type f, <"$file") — no eval/sh -c in detect.sh, no network or credential access, and paths are consumed only after cd "$repo_root" (no traversal outside the working tree).

The rest of the merge's content (docs/specs/d1-model-already-knows-measurement/*, plugins/docs-hygiene/*, plugins/work-items/*) is unrelated, already-merged origin/main work outside this PR's scope and outside this lane's remit for this review.

Nothing further to flag — same conclusion as every prior pass in this thread.
· branch

Close the residual octal-escape / arrow-bearing-name gap in both porcelain
parsers by switching to git status --porcelain -z.

Refs #3140
@kyle-sexton
kyle-sexton force-pushed the fix/residue-porcelain-space-paths branch from c9c1415 to 6746622 Compare August 23, 2026 19:12
@kyle-sexton kyle-sexton reopened this Aug 23, 2026
@claude

claude Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 16s —— View job


Security review complete

  • Gather context (PR diff, changed files, HEAD SHA)
  • Invoke /review:security-review and follow its instructions
  • Post findings
  • Summarize review in this comment

Result: no security findings

Scope checked: current head 2df47e6 — one commit past the last-reviewed head (c9c1415). Confirmed the PR's actual scope by diffing origin/main against HEAD:

plugins/code-tidying/.claude-plugin/plugin.json    |  2 +-
plugins/code-tidying/CHANGELOG.md                  | 25 ++
plugins/code-tidying/skills/audit-comment-residue/SKILL.md          |  2 +-
plugins/code-tidying/skills/audit-comment-residue/scripts/detect.sh | 46 +++---
plugins/code-tidying/skills/audit-comment-residue/scripts/detect.test.sh | 37 ++
5 files changed, 81 insertions(+), 31 deletions(-)

— matching the PR's reported stats exactly, and no .github/ files touched.

What changed since the last-reviewed head: the version/changelog rebase from 0.14.10.14.2 (plugin.json, CHANGELOG.md — prose and a version string only). I read detect.sh, SKILL.md, and detect.test.sh in full to confirm they are unchanged in substance from the state already reviewed multiple times in this thread:

  • detect.sh's target-discovery loop reads git status --porcelain -z (NUL-delimited, no quoting/escaping per git's own documentation), gates rename-record consumption on [RC]?|?[RC] in the status byte pair, and slices ${record:3} for the path — no eval, no sh -c, no unquoted expansion. Every derived path is used only inside quoted contexts downstream ([[ -d "$target" ]], find "$target" -type f, [[ -f "$file" ]], <"$file"), and paths are consumed only after cd "$repo_root" — no traversal outside the working tree, no privilege boundary crossed (the caller already has read access to everything in its own repo).
  • SKILL.md's Uncommitted code files: preview line mirrors the same -z/awk-equivalent parse, closing the divergence between what the model previews and what detect.sh actually audits.
  • detect.test.sh's eval "$skill_porcelain" (line ~292) evaluates a command extracted from this repo's own tracked SKILL.md, not external or attacker-controlled input — already reviewed in this thread as not crossing a trust boundary, since editing SKILL.md already requires repo write access.

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.
· branch

@kyle-sexton
kyle-sexton merged commit db7d8ea into main Aug 23, 2026
50 checks passed
@kyle-sexton
kyle-sexton deleted the fix/residue-porcelain-space-paths branch August 23, 2026 20:07
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.

1 participant