yegor256/judges

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

Aberta

#476 aberto em 12 de jul. de 2026

 (2 comentários) (0 reação) (0 responsável)Ruby (15 forks)github user discovery
bughelp wanted

Métricas do repositório

Stars
 (7 estrelas)
Métricas de merge de PR
 (Métricas PR pendentes)

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

Guia do colaborador