yegor256/judges

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

Open

#476 opened on Jul 12, 2026

 (2 comments) (0 reactions) (0 assignees)Ruby (15 forks)github user discovery
bughelp wanted

Repository metrics

Stars
 (7 stars)
PR merge metrics
 (PR metrics pending)

Description

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('*', '.*').

Contributor guide