Skip to content

fix(code_safety): js_exec_sync reads spawn-family arguments, not a regex span - #1087

Merged
hyperpolymath merged 7 commits into
mainfrom
claude/js-exec-follow-up
Nov 14, 2026
Merged

hyperpolymath merged 7 commits into
mainfrom
claude/js-exec-follow-up

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Summary

This follows up #1083, which auto-merged before the owner's "Fix everything first" items were done (ruling in the Mathesis thread, 2026-11-14). It addresses the four remaining review threads on #1083:

Item Thread Before After
(A) 4572752253 spawn(c, a, {env: {shell: '/bin/bash'}}) was reported (false positive) Only the call's own top-level shell key counts
(1) 4572814517 A hypatia:ignore on the import line blanked the binding, so later cp.exec(...) calls went unreported Bindings are read from the unsuppressed file; matches still run against the suppressed one
(2) 4572814520 Compiled TypeScript (0, child_process_1.exec)(cmd) was missed (0, ns.exec)(, (0, ns.execSync)( and (0, ns.spawn)(...) are followed
(3) 4572814514 A ; or bracket inside a string or template argument ended the regex span Arguments are read by a scanner that skips strings, templates and comments

Design. A new module, Hypatia.Rules.JsCallScan, replaces the spawn-family regex. For each spawn, spawnSync, execFile or execFileSync call (or a renamed local, or the compiled form), it:

  • walks the argument list, skipping quoted strings, template literals (including ${...} nesting), and // and /* */ comments;
  • tracks ()[]{} depth and splits the top-level arguments;
  • reports only an object-literal argument whose own shell key (bare or quoted) is true or a string.

This also removes the old two-level nesting limit. A call written inside a string or a comment is no longer counted. scan_content/2 and scan_web_security/1 share one rule_matches/3, so lines and occurrence counts agree.

Remaining limits, named in the module doc and the rule comment:

  • a regex literal containing a quote or bracket can desynchronise the walk;
  • an options object passed in a variable is not followed;
  • a call written inside a template's ${...} is not looked for.

Evidence

  • 6 new tests in test/code_safety_test.exs: one each for (A), (1), (2) and (3); calls inside strings or comments; and arguments nested three or more levels deep. All 6 fail on main (6693f9a) and pass on this branch. All 99 existing tests are kept: 105 code_safety tests pass.
  • 996 tests pass across code_safety, scanner_suppression, soundness, ci_changed and test/rules.
  • Every JS/TS file in hyperpolymath/mathesis at PR 90's head (bdcc599) still scans clean.
  • hypatia_rules_praxis.deed is unchanged (--check passes), the format check passes, and there are no compile warnings in the changed files.

The owner approved this PR in my session on 2026-11-14.


Generated by Claude Code

…gex span

Follow-up to #1083 (owner: fix everything first).

- A shell key nested inside another option ({env: {shell: ...}}) is no
  longer the call's option (thread 4572752253).
- An inline hypatia:ignore on the child_process import line no longer
  hides the calls below it: bindings are read from the unsuppressed file
  (4572814517).
- The compiled TypeScript form (0, ns.exec)(cmd), .execSync and
  (0, ns.spawn)(...) are followed (4572814520).
- A ; or bracket inside a string, template or comment argument no longer
  ends the call (4572814514), and the two-level nesting limit is gone.

Hypatia.Rules.JsCallScan walks each spawn/spawnSync/execFile/execFileSync
call's arguments, skipping strings, templates (with ${...}) and comments,
and reports only an object-literal argument whose own shell key is true
or a string. Calls written inside strings or comments are not calls.
Limits are named in the module doc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136P7ZkGCWGEyedTtdEHAPT
@coderabbitai

coderabbitai Bot commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 16 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: f6162e1c-69f5-4b8f-b788-00c68c8524ec
Commits

Reviewing files that changed from the base of the PR and between e1d3b28 and 014e69e.

Files selected for processing: 5

  • .claude/CLAUDE.md
  • README.adoc
  • lib/rules/code_safety.ex
  • lib/rules/js_call_scan.ex
  • test/code_safety_test.exs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

The readme-claims gate re-measures the tree: the new module makes
lib/rules 44 source files and lib/ 158. README.adoc and the
.claude/CLAUDE.md architecture count now match
(scripts/check-readme-claims.sh passes).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136P7ZkGCWGEyedTtdEHAPT
@hyperpolymath
hyperpolymath marked this pull request as ready for review November 14, 2026 10:19
@chatgpt-codex-connector

Copy link
Copy Markdown

This security review couldn’t start because the paying account has exhausted its Codex allowance and has insufficient available credits. The payer can check their balance and add credits in the Codex usage dashboard, then try again. If you do not manage the paying account, contact this repository's admins.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 14, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-14T10:52:53.719533Z 014e69e New commits
🔒 Security Review ❌ Failed 2026-11-14T10:49:19.544800Z
We couldn’t complete this review. Comment @codex security review to try again.
014e69e New commits
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: 360682fd80

ℹ️ 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 lib/rules/js_call_scan.ex Resolved
Comment thread lib/rules/js_call_scan.ex Resolved
Comment thread lib/rules/code_safety.ex Resolved
Codex review of #1087:
- A comment before the shell key ({ /* x */ shell: true }, or a //
  line) hid it; each property now starts at its first code byte.
- The exec forms ((0, cp.exec)(cmd), cp.exec( ...) matched inside a
  string, template or comment; regex hits are now kept only at code
  offsets (JsCallScan.code_offsets/2, one walk shared with the spawn
  scan).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136P7ZkGCWGEyedTtdEHAPT
@chatgpt-codex-connector

Copy link
Copy Markdown

This security review couldn’t start because the paying account has exhausted its Codex allowance and has insufficient available credits. The payer can check their balance and add credits in the Codex usage dashboard, then try again. If you do not manage the paying account, contact this repository's admins.

@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: 224a1ba766

ℹ️ 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 lib/rules/js_call_scan.ex Resolved
Comment thread lib/rules/js_call_scan.ex Resolved
Comment thread lib/rules/js_call_scan.ex Resolved
… lookup

Codex review of #1087:
- A parenthesised options object (spawn(c, a, ({shell: true}))) is read:
  object_start/3 steps over wrapping parentheses and the whitespace and
  comments around them.
- A computed string key (['shell'], ["shell"], [`shell`]) names the
  option too. Not a regression; the old regex missed it as well.
- code_offsets/2 walks the sorted offsets against the sorted, disjoint
  non-code spans in one pass, and shell_option_calls/2 uses it, so there
  is one lookup and it is linear.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136P7ZkGCWGEyedTtdEHAPT
@chatgpt-codex-connector

Copy link
Copy Markdown

This security review couldn’t start because the paying account has exhausted its Codex allowance and has insufficient available credits. The payer can check their balance and add credits in the Codex usage dashboard, then try again. If you do not manage the paying account, contact this repository's admins.

@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: b7b654d292

ℹ️ 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 lib/rules/js_call_scan.ex Resolved
Comment thread lib/rules/js_call_scan.ex Resolved
Comment thread lib/rules/js_call_scan.ex Resolved
… not the object

Codex review of #1087:
- {...{shell: true}} (and a parenthesised spread) contributes its own
  top-level keys; a shell key nested deeper in the spread does not.
- object_start/3 accepts an object (or a parenthesised one) only when it
  is the whole argument, so ({shell: true}, {shell: false}) and
  {shell: true} && opts are not read as that object.
- The module doc names the remaining cost limit: nested spawn-family
  calls re-read their own argument lists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136P7ZkGCWGEyedTtdEHAPT
@chatgpt-codex-connector

Copy link
Copy Markdown

This security review couldn’t start because the paying account has exhausted its Codex allowance and has insufficient available credits. The payer can check their balance and add credits in the Codex usage dashboard, then try again. If you do not manage the paying account, contact this repository's admins.

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

ℹ️ 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 lib/rules/js_call_scan.ex Resolved
Comment thread lib/rules/js_call_scan.ex Resolved
Comment thread lib/rules/js_call_scan.ex Resolved
Codex review of #1087: a ternary branch (cond ? {shell: true} : {...})
and a TypeScript assertion ({shell: true} as / satisfies SpawnOptions)
were missed, because an object counted only when it was the whole
argument. One rule now: an object literal counts when it is a top-level
operand of the argument expression, reached only through wrapping
parentheses; in a parenthesised comma expression only the last element
counts; an object inside a call, array or other object never counts.

This reports {shell: true} && opts again, as an accepted over-report;
the module doc says so, and also names the JSX-text apostrophe limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136P7ZkGCWGEyedTtdEHAPT
@chatgpt-codex-connector

Copy link
Copy Markdown

This security review couldn’t start because the paying account has exhausted its Codex allowance and has insufficient available credits. The payer can check their balance and add credits in the Codex usage dashboard, then try again. If you do not manage the paying account, contact this repository's admins.

@sonarqubecloud

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath merged commit b7944d3 into main Nov 14, 2026
105 checks passed
@hyperpolymath
hyperpolymath deleted the claude/js-exec-follow-up branch November 14, 2026 11:13
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.

3 participants