## Description This isn't tied to an open issue — I found it by extrapolating from the bug class fixed in #15415 ("fix: anchor contact phone number validation"), which fixed a `Contact#phone_number` format validation that was missing a leading `\A` anchor. That made me audit every hand-written regex-based validation in the codebase for the same class of anchoring mistake (`format: { with: ... }` validators, plus `match?`/`=~` calls used for validation-style checks, across `app/`, `enterprise/`, and `lib/`). Everything else was already correctly anchored. One real instance of the *sibling* mistake remains: `RegexHelper::UNICODE_CHARACTER_NUMBER_HYPHEN_UNDERSCORE` (used only by `Label#title`'s format validation) is `/\A[\p{L}\p{N}]+[\p{L}\p{N}_-]+\Z/` — note `\Z` (capital), not `\z`. Unlike `\z`, `\Z` also matches just before a single trailing `"\n"` at the end of the string. The surrounding comment documents the intended character set (unicode letters/numbers/underscore/hyphen, not starting with `_`/`-`) and says nothing about tolerating a trailing newline, so this reads as an unintentional choice of anchor rather than a deliberate one. Concretely: `Label.new(title: "hello_world\n").valid?` returns `true` on current `develop` and persists a title with a literal trailing newline, because `\Z` lets the `\n` slip through. `Label` only lowercases the title before validating (no `strip`), so nothing else catches this. This is a narrower/lower-severity variant of the #15415 bug (it only ever admits one specific trailing character, not an arbitrary prefix/suffix), but it's the same underlying mistake, independently verified against current source, not just pattern-matched from the diff. ## What changed - `lib/regex_helper.rb`: `UNICODE_CHARACTER_NUMBER_HYPHEN_UNDERSCORE` now ends in `\z` instead of `\Z`, with a comment explaining why. ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## How Has This Been Tested? Ran against a real local Rails env (Ruby 3.4.4, PostgreSQL 16, Redis): `bundle exec rspec spec/models/label_spec.rb` Added a regression test asserting `Label.new(title: "hello_world\n")` is invalid. Confirmed it fails against the pre-fix `\Z` regex and passes after switching to `\z`. All existing `label_spec.rb` examples (including the existing "foreign characters", "special characters", and "uppercase" title-validation cases) continue to pass unchanged. ## Checklist - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective - [x] New and existing unit tests pass locally with my changes 🤖 This fix was authored by an AI coding agent (Claude) working on behalf of Mithtech, an ERPNext/Frappe/Medusa.js implementation studio, as part of a deliberate effort to build a track record of verified upstream open-source contributions. Flagging this transparently per common courtesy — happy to answer any questions about the change, including how it was found (auditing for the same regex-anchor mistake class as #15415). Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
26 lines
1.6 KiB
Ruby
26 lines
1.6 KiB
Ruby
module RegexHelper
|
|
# user https://rubular.com/ to quickly validate your regex
|
|
|
|
# the following regext needs atleast one character which should be
|
|
# valid unicode letter, unicode number, underscore, hyphen
|
|
# shouldn't start with a underscore or hyphen
|
|
# \z (not \Z) anchors strictly to the end of the string -- \Z would also accept a single
|
|
# trailing "\n", which would let a title like "hello_world\n" pass this validation.
|
|
UNICODE_CHARACTER_NUMBER_HYPHEN_UNDERSCORE = Regexp.new('\A[\p{L}\p{N}]+[\p{L}\p{N}_-]+\z')
|
|
# Regex to match mention markdown links and extract display names
|
|
# Matches: [@display name](mention://user|team/id/url_encoded_name)
|
|
# Captures: 1) @display name (including emojis), 2) url_encoded_name
|
|
# Uses [^]]+ to match any characters except ] in display name to support emojis
|
|
# NOTE: Still used by Slack integration (lib/integrations/slack/send_on_slack_service.rb)
|
|
# while notifications use CommonMarker for better markdown processing
|
|
MENTION_REGEX = Regexp.new('\[(@[^\\]]+)\]\(mention://(?:user|team)/\d+/([^)]+)\)')
|
|
|
|
TWILIO_CHANNEL_SMS_REGEX = Regexp.new('\A\+\d{1,15}\z')
|
|
WHATSAPP_BSUID_PATTERN = '[A-Z]{2}\.(?:ENT\.)?[A-Za-z0-9]{1,128}'.freeze
|
|
WHATSAPP_WAMID_TOKEN_PATTERN = '(?<![0-9a-f])(?:[0-9a-f]{32}|[0-9a-f]{20})(?![0-9a-f])'.freeze
|
|
WHATSAPP_BSUID_REGEX = Regexp.new("\\A#{WHATSAPP_BSUID_PATTERN}\\z")
|
|
WHATSAPP_WAMID_TOKEN_REGEX = Regexp.new(WHATSAPP_WAMID_TOKEN_PATTERN, Regexp::IGNORECASE)
|
|
TWILIO_CHANNEL_WHATSAPP_REGEX = Regexp.new("\\A(?:whatsapp:\\+\\d{1,15}|whatsapp:#{WHATSAPP_BSUID_PATTERN})\\z")
|
|
WHATSAPP_CHANNEL_REGEX = Regexp.new("\\A(?:\\d{1,15}|#{WHATSAPP_BSUID_PATTERN})\\z")
|
|
end
|