yegor256/judges

`Judges::Judges#fits?` doesn't escape regex metacharacters, so `--boost`/`--demote` patterns over-match

Aperta

#476 aperta il 12 lug 2026

 (2 commenti) (0 reazioni) (0 assegnatari)Ruby (15 fork)github user discovery
bughelp wanted

Metriche repository

Star
 (7 stelle)
Metriche merge PR
 (Merge medio 5g) (13 PR mergiate in 30 g)

Descrizione

Judges::Judges#fits? (lib/judges/judges.rb:137-142), used to match judge names against --boost/--demote patterns, only translates * to .* before building the match regex:

def fits?(name, patterns)
  return false if patterns.nil? || patterns.empty?
  Array(patterns).any? do |pattern|
    name.match?("\\A#{pattern.gsub('*', '.*')}\\z")
  end
end

Every other regex metacharacter in the user-supplied pattern (., +, ?, (, ), [, ], etc.) is passed straight into the regex unescaped. Per the feature's own originating issue (#344, closed), the intended semantics are: "* means .* (regexp) and that's it" — i.e. everything besides * should match literally.

What happens: a pattern containing a literal dot, e.g. --demote=my.judge, is meant to match only the exact judge name my.judge. Because the dot is interpreted as a regex "any character," it also matches unrelated judge names that merely happen to have some other character in that position:

fits?("myXjudge", ["my.judge"]) # => true  (WRONG — should be false)
fits?("my.judge", ["my.judge"]) # => true  (correct)

Judge names containing dots are common (many real judges are named like some.judge or reference dotted paths), so this isn't a corner case — any such pattern silently over-matches.

Impact: --boost/--demote can silently reorder judges that were never intended to match the given pattern, whenever the pattern contains any regex metacharacter other than *.

What should happen: all characters in the pattern except * should be treated literally, e.g. Regexp.escape(pattern).gsub('\*', '.*') instead of the current bare pattern.gsub('*', '.*').

Guida contributor