Skip to content

fix(typos-format): guard bundled config path when plugin root unset - #2504

Closed
kyle-sexton wants to merge 4 commits into
mainfrom
cursor/typos-git-sha-ignore-63e1
Closed

fix(typos-format): guard bundled config path when plugin root unset#2504
kyle-sexton wants to merge 4 commits into
mainfrom
cursor/typos-git-sha-ignore-63e1

Conversation

@kyle-sexton

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

Copy link
Copy Markdown
Contributor

Closes #1257

Related

No linked issue — maintenance merge/rebase PR.

cursoragent and others added 3 commits August 12, 2026 11:28
Fixes #1257

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
@cursor

cursor Bot commented Aug 12, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

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


Security Review

  • Gather context (diff, changed files)
  • Review plugins/typos-format/config/default-typos.toml
  • Review plugins/typos-format/hooks/typos-format.sh
  • Post findings

Scope: This PR touches only a PostToolUse hook shell script (typos-format.sh) and a new bundled TOML config. No GitHub Actions workflows, secrets handling, or network-facing code are touched.

Changes reviewed:

  • typos-format.sh#L170-L176 — builds TYPOS_CONFIG_ARGS from CLAUDE_PLUGIN_ROOT + a fixed relative suffix, guarded by both a non-empty check and -f existence check before use.
  • The resulting path is stored in a bash array (TYPOS_CONFIG_ARGS=(-c "$TYPOS_CONFIG")) and expanded with "${TYPOS_CONFIG_ARGS[@]}" at the two call sites (L237, L280) — properly quoted, no word-splitting/injection risk even if the path contained spaces or shell metacharacters.
  • CLAUDE_PLUGIN_ROOT is a host-supplied environment variable (set by the Claude Code plugin loader), not derived from tool input, file content, or any attacker-influenced source in this diff — no injection surface here.
  • The new default-typos.toml only adds an extend-ignore-re pattern (\b[0-9a-f]{7,40}\b) to suppress spellcheck false-positives on git SHAs. The pattern uses bounded repetition (no nested/overlapping quantifiers), so no ReDoS concern. This hook is advisory/report-only by default (per the file's own header doc) and is not a secret scanner, so broadening what it ignores doesn't create a credential-exposure path.

Conclusion: No security issues found. This is a narrow, well-guarded change (empty/unset-var check + file-existence check before use, values passed through a quoted array) with no injection, authorization, or secret-handling concerns.

@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: 9bdb6d2ab3

ℹ️ 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/typos-format/config/default-typos.toml
@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

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


Code review

  • Gather context (PR diff, CLAUDE.md, REVIEW.md, _typos.toml, docs/conventions/config-cascade)
  • Review plugins/typos-format/config/default-typos.toml
  • Review plugins/typos-format/hooks/typos-format.sh changes
  • Post findings

This PR (closing #1257) bundles a default-typos.toml with a git SHA ignore-regex and wires it into the hook via typos -c <path>, guarded on CLAUDE_PLUGIN_ROOT being set. Two correctness concerns and a test-coverage gap posted as inline comments, most-severe first:

  1. [Likely correctness bug] typos -c <bundled-config> probably replaces rather than merges with a repo's own discovered typos config (_typos.toml/.typos.toml/typos.toml) — this repo's own _typos.toml:29-32 states outright that "typos has no config layering." If so, every consuming repo (including this one) would silently stop getting its own typos config honored the moment typos-format runs, contradicting both the new file's own "merged" claim and the plugin's README/SKILL docs. Flagged inline on default-typos.toml; needs empirical verification against the installed typos-cli version before merging (same rigor the file's other comments already apply elsewhere).
  2. [Likely portability bug] The new TYPOS_CONFIG_ARGS=() array is expanded bare as "${TYPOS_CONFIG_ARGS[@]}" under set -uo pipefail — a known nounset gotcha for empty arrays on bash < 4.4, which includes the bash 3.2 this hook family explicitly documents as its supported floor (hook-utils.sh:506). On the common path (no CLAUDE_PLUGIN_ROOT), this would likely make every typos invocation on macOS's default bash error out as a spurious "tool break." This repo already uses the fix idiom ("${ARGS[@]:-}") elsewhere for the same scenario. Flagged inline on typos-format.sh:170-176.
  3. [Test coverage] CLAUDE_PLUGIN_ROOT is referenced nowhere in typos-format.test.sh — the new bundled-config path, including the "guard when plugin root unset" behavior this PR's own title calls out, is entirely untested. Flagged inline on typos-format.sh:174.
  4. [Minor, doc drift — no changed line to anchor to] plugins/typos-format/README.md (lines 10-23) and plugins/typos-format/skills/setup/SKILL.md (lines 11-12) still say the plugin "ships no rules of its own" / "owns no consumer-project configuration." That's no longer accurate now that a bundled config is shipped and passed to typos, and wasn't updated in this PR.

Note: I could not run typos or reach the network in this sandbox to empirically confirm the -c merge-vs-replace behavior (finding 1) or the bash-3.2 array behavior (finding 2) — both are reasoned from this repo's own documentation/comments and well-known bash/typos-cli behavior, not independently executed. Please verify before merging. Security review is out of scope for this lane.
· Branch

Comment thread plugins/typos-format/config/default-typos.toml
Comment thread plugins/typos-format/hooks/typos-format.sh
Comment thread plugins/typos-format/hooks/typos-format.sh
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

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

@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

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


Code review

  • Gather context (PR diff, HEAD SHA 862231a)
  • Invoke /review:code-review procedure
  • Post findings

Result: nothing to review — this PR's diff against main is empty.

Verified two ways:

  • The PR metadata for this event reports Additions: 0, Deletions: 0, Changed Files: 0 files.
  • gh pr diff 2504 against melodic-software/claude-code-plugins returns no output.

HEAD (862231a, "Merge branch 'main' into cursor/typos-git-sha-ignore-63e1") is content-identical to current main. This matches the PR body's own description of this state: "No linked issue — maintenance merge/rebase PR." The substantive typos-format changes (bundled default-typos.toml, the TYPOS_CONFIG_ARGS guard in typos-format.sh) that were reviewed in the earlier comments on this thread are no longer part of this branch's diff — they appear to have already landed via main (or been superseded there), so there are no changed lines left for /review:code-review to anchor findings to.

No inline comments were posted since there is no diff to anchor them to. If this branch is expected to still carry the typos-format changes, the branch likely needs to be re-created/rebased against current main rather than merged, since the merge commit appears to have absorbed away its own diff.
· Branch

kyle-sexton added a commit that referenced this pull request Aug 12, 2026
…PR (#2523)

## Summary

`scripts/verify-security-review-evidence.sh` runs under `set -euo
pipefail` and called its scope helper bare:

```bash
pr_touches_security_paths "$base_ref"
local in_scope=$?
```

The helper signals OUT-of-scope by **returning non-zero**. Under `set
-e`, a bare call with a non-zero return aborts the shell immediately —
so the script died on that line, exit 1, no message, and the `"diff does
not touch security-relevant paths — guard not applicable"` branch below
was unreachable dead code.

Every out-of-scope pull request FAILED the guard instead of being waved
through.

Observed on [run
31637054526](https://github.com/melodic-software/claude-code-plugins/actions/runs/31637054526)
(PR #2512): the diff touches only `docs/conventions/loop-lane/*.md`,
`security-review / security-review` correctly **SKIPPED**, and
`security-review-evidence` failed beside it with a step log containing
nothing but `##[error]Process completed with exit code 1`. The empty log
is the signature — `set -e` aborts before any `echo` can run. Reproduced
standalone:

```
$ cat setE.sh
set -euo pipefail
f() { return 1; }
main() { f "x"; local rc=$?; echo "REACHED with rc=$rc"; }
main
$ bash setE.sh; echo "exit=$?"
exit=1          # "REACHED" never prints
```

## Fix — and why not the one-liner

The obvious fix is `pr_touches_security_paths "$base_ref" ||
in_scope=$?`. It clears the red check and introduces something worse,
which **ShellCheck flags directly via SC2310** — a check this repo
enables on purpose in `.shellcheckrc` ("catches the bash trap where
errexit silently stops working inside if/while/&&/||").

The helper runs `python3`, and a crashing interpreter also exits 1. With
out-of-scope encoded as "returns 1", a **broken** scope check is
indistinguishable from a **negative** one — the guard would skip itself
and silently pass a PR it exists to check. Fail-open is the wrong
direction for a security guard.

So the two channels are separated instead: the helper prints its verdict
(`in-scope` / `out-of-scope`) on **stdout** and reserves a non-zero
**exit** for a genuine fault. The caller consumes it via command
substitution, which keeps `set -e` live for the helper, and treats any
unrecognised verdict as a fault rather than a pass.

## Verification

Run in this worktree — commands I actually ran, with real output:

- `bash scripts/verify-security-review-evidence.sh.test.sh` -> **6 pass,
0 fail**, `All checks passed.`
- `shellcheck --rcfile .shellcheckrc
scripts/verify-security-review-evidence.sh
scripts/verify-security-review-evidence.sh.test.sh` -> **clean**, with
SC2310 no longer firing on the guard (it fired on the `||` variant,
which is how the fail-open hole was found).

New regression cases:
- a non-zero-returning helper called bare under `set -e` kills the
script — modelled in a **separate `bash -c` process** deliberately. A `(
… )` subshell will not do: bash suppresses `set -e` for the whole
dynamic extent of a command whose status is being tested, and `$( … )`
inside `[[ … ]]` is exactly that context, which made the bug
unreproducible in the very harness meant to catch it. My first attempt
at this test failed for that reason, not because the fix was wrong.
- static guards that fail if either older shape (bare call, or
`||`-suppressed call) returns
- a static guard that fails if the unrecognised-verdict catch-all is
removed

**Not verified here:** that the three currently-red PRs (#2512, #2504,
#2499) go green. They will only pick this up once their branches carry
it — the evidence workflow runs from the PR head.

## Related

Third distinct defect found in this one file today, which is itself the
finding: it infers another workflow's behaviour by reading that
workflow's logs. #2517 (grep matched the lane action's echoed source)
only became reachable once the `cursor[bot]` outage was fixed; this one
only became reachable once #2517 let execution past the grep.

No linked issue — filing was interrupted; the detail is captured here
instead.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
@kyle-sexton

Copy link
Copy Markdown
Contributor Author

Superseded on main — typos-format bundled-config guard already landed; empty diff vs main.

@kyle-sexton
kyle-sexton deleted the cursor/typos-git-sha-ignore-63e1 branch August 24, 2026 18:46
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.

typos-format: hook silently corrupts abbreviated git SHAs, including inside backticks

2 participants