Skip to content

Identity hook: the three readings SonarCloud flagged are string readings in one pass - #249

Merged
don-petry merged 3 commits into
mainfrom
hooks/identity-regexes-bounded
Oct 21, 2026
Merged

don-petry merged 3 commits into
mainfrom
hooks/identity-regexes-bounded

Conversation

@don-petry

@don-petry don-petry commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Why

"Identity hook: three super-linear regexes bounded, so a long command cannot stall the guard (SonarCloud S8786)" (issue 239). SonarCloud flagged three regexes in tools/hooks/identity.py as super-linear: the one that reads the identity git var gives, the one that takes a credential out of a URL before a sentence shows it, and the one that tells a URL or an scp-like remote from a remote's name. The hook is a mistake guard (decisions 0040, 0041) that reads every command a session is about to run; a reading that backtracks on a long or repetitive word stalls the session for a harmless command.

What changed

  • Three string readings in one pass, _ident, _without_credential and _urlish, replace the regexes, with the same answers at every edge the regexes had: an empty name, a < the email holds, a ://@ with nothing before the @, an @ or a : after the first /. Git strips < and > from a name and an email, so the last < and the last > bound the email as the greedy regex did.
  • Measured: a remote of 200,000 characters with an @ in every other one took the old pattern 41 seconds, and 10 seconds at 100,000; an identity of 40,000 < took 19 seconds. Each reading is now a pass. The wall-clock test holds the three readings under a second at those sizes, and the whole hook under five seconds on a 20,000-character remote. Past that, the hook's cost on a long command is Python's shlex and the hook's several passes over the command, within the hook's own 10-second budget and its command_unreadable refusal; that cost is older than this issue and is not changed here.
  • A Boundary row on decision 0040; six mutants, one per reading and one more each for the email's bound, the nested scheme and the digit class, each killed by the edge test and, where it reaches, by the identity and credential tests.

Regression corpus

hook_regressions.py (the reviewers' attack inputs and the ordinary corpus) and the 10,722-command fresh corpus, main b324f93 against this head, at the first head and again after the fix round: 40 attack inputs, 0 regressions; 8,842 corpus commands, 0 newly refused; and of the 10,722 fresh commands, 0 newly refused and 0 newly passed, with no exception on either side. The readings give the regexes' answers on every command the corpora hold.

Measured

make verify passed on a git archive export of the head, run alone. The six mutants were killed by hand on scratch copies with their named tests (the filtered run cannot select tools/hooks/identity.py alone: it holds more than 40 mutants).

Who read it

Muse Wonder Full read the first head, 1247383, as the Maintainer's ruling of 2026-10-20 has it for a hook pull request, and found three things, each in the one fix round the helper rule allows: a blocker, real, where a :// nested in a run that no @ ended was skipped, so https://a://user:secret@host kept its credential that the old regex took out (the search goes on from just after each :// now, with the case in the credential test); the rpartition mutant unkilled for want of a name holding < (the same survivor CI's shard 7 showed; the edge is in); and isdigit wider than the regex's \d, taking a superscript (isdecimal now, and one line only). Muse did not read the fix round. The Claude review and the security pass found no defect: the readings take no new input and give no new output, and a credential is still taken out of every sentence.

Closes #239.

🤖 Generated with Claude Code

…ngs in one pass (#239)

The identity git var gives, a credential in a URL and an scp-like remote were read by regexes that
backtrack super-linearly (python:S8786): a remote of 200,000 characters with an @ in every other one
took the old pattern 41 seconds, and an identity of 40,000 " <" nineteen. Each is read by string
methods now, in one pass, with the same answers at every edge the regexes had, held by a test of
those edges and a wall-clock test. The hook's remaining cost on a long command is Python's shlex and
its passes over the command, within its own budget. A Boundary row on decision 0040; four mutants.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@don-petry
don-petry requested a review from a team as a code owner October 21, 2026 01:33
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

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

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-21T01:33:27.801677Z
We couldn’t complete this review. Comment @codex review to try again.
1247383 PR opened
ℹ️ 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

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

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 12 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
  • Configuration used: Repository: combsmith/software-factory/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 0236f69b-302b-42fa-8067-8620d363ffc7
📥 Commits

Reviewing files that changed from the base of the PR and between b324f93 and 726fcc4.

📒 Files selected for processing: 4
  • docs/decisions/0040-the-identity-hook-reads-where-the-shell-may-stand-and-a-program-it-does-not-read-may-write.md
  • tests/test_hooks.py
  • tools/hooks/identity.py
  • tools/mutants.py
  • 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

Comment @coderabbitai help to get the list of available commands.

don-petry and others added 2 commits October 20, 2026 20:51
… shard let it survive

The edge test had no name holding " <", so a reading that takes the first " <" for the email's
start gave the same answers; a name with one, and an email with a bare <, are edges now, read as
the greedy regex read them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…x's digit, after Muse's read

After a run that no @ ended, the search went on from the run's end, so a :// nested in it, as in
https://a://user:secret@host, kept its credential where the old regex took it out; the search goes
on from just after the :// now. The identity's digits are decimal digits, as \d had them, not a
superscript, and an identity holds one line. Two mutants, six in all.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@don-petry
don-petry added this pull request to the merge queue Oct 21, 2026
Merged via the queue into main with commit b376ccf Oct 21, 2026
19 checks passed
@don-petry
don-petry deleted the hooks/identity-regexes-bounded branch October 21, 2026 02:41
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.

Identity hook: three super-linear regexes bounded, so a long command cannot stall the guard (SonarCloud S8786)

1 participant