From 09c6b164ba5a1fe31b43f6fc16b0195a15759738 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Wed, 30 Sep 2026 10:46:36 +0100 Subject: [PATCH] fix(rules): escape `/` in three regex sigils so hypatia compiles again #862 put an unescaped `/` inside a character class in three `~r/.../` sigils (pin_integrity.ex @uses_regex and locked_refs/1, pr_automerge.ex @pin_re). In a `~r/` sigil that `/` terminates the sigil, so `mix compile` fails with MismatchedDelimiterError. Every estate Hypatia scan (hypatia-scan-reusable.yml resolves hypatia@main) has failed since. `\/` inside a character class matches the same byte set as `/`; this change is semantics-preserving and only restores compilation. The two modules' own tests (17) now run for the first time and fail on latent logic bugs in #862; nothing outside test/ calls either module. Those are fixed in a follow-up PR, kept separate so this outage fix stays three characters. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0136eszqrQ53Kj7aBH1D4rXK --- lib/rules/pin_integrity.ex | 4 ++-- lib/rules/pr_automerge.ex | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rules/pin_integrity.ex b/lib/rules/pin_integrity.ex index 6919d6dc..f3e4d506 100644 --- a/lib/rules/pin_integrity.ex +++ b/lib/rules/pin_integrity.ex @@ -53,7 +53,7 @@ defmodule Hypatia.Rules.PinIntegrity do or to the owner as `flag` when the repair is not a substitution. """ - @uses_regex ~r/^\s*-?\s*uses:\s*(?[A-Za-z0-9_.-]+\/[A-Za-z0-9_./-]*?)@(?[^\s#]+)\s*(?:#\s*(?.*?))?\s*$/ + @uses_regex ~r/^\s*-?\s*uses:\s*(?[A-Za-z0-9_.-]+\/[A-Za-z0-9_.\/-]*?)@(?[^\s#]+)\s*(?:#\s*(?.*?))?\s*$/ @doc """ Parse every `uses:` pin site in a workflow file. @@ -362,7 +362,7 @@ defmodule Hypatia.Rules.PinIntegrity do |> String.split("\n") |> Enum.with_index(1) |> Enum.flat_map(fn {line, number} -> - case Regex.run(~r/'(?[A-Za-z0-9_.-]+\/[A-Za-z0-9_./-]+)@(?[^\s']+)'/, line) do + case Regex.run(~r/'(?[A-Za-z0-9_.-]+\/[A-Za-z0-9_.\/-]+)@(?[^\s']+)'/, line) do nil -> [] diff --git a/lib/rules/pr_automerge.ex b/lib/rules/pr_automerge.ex index 780f12d8..273629b1 100644 --- a/lib/rules/pr_automerge.ex +++ b/lib/rules/pr_automerge.ex @@ -419,7 +419,7 @@ defmodule Hypatia.Rules.PrAutomerge do # - - uses: actions/checkout@v4.1.7 # so the marker is part of the match. (Without this, every real diff looks # like a non-pin change and every PR falls through to `flag`.) - @pin_re ~r/^[-+]?\s*-?\s*uses:\s*(?[A-Za-z0-9_.-]+\/[A-Za-z0-9_./-]*?)@(?[^\s#]+)/ + @pin_re ~r/^[-+]?\s*-?\s*uses:\s*(?[A-Za-z0-9_.-]+\/[A-Za-z0-9_.\/-]*?)@(?[^\s#]+)/ @doc "Parse a `uses:` line into `%{action, base, ref}`; `nil` when it is not one." def parse_pin(line) do