Module: Pgbus::QueueNameValidator
- Defined in:
- lib/pgbus/queue_name_validator.rb
Overview
Validates and sanitizes PGMQ queue names for safe use in SQL identifiers.
PGMQ queue names are interpolated into SQL as table/sequence names (e.g., pgmq.q_<name>, pgmq.a_<name>). This module enforces strict validation to prevent SQL injection via crafted queue names.
Constant Summary collapse
- MAX_QUEUE_NAME_LENGTH =
PostgreSQL’s NAMEDATALEN caps identifiers at 63 bytes, but the effective limit is tighter: pgmq-ruby (our transport gem) rejects any queue name with ‘length >= 48` in `PGMQ::Client#validate_queue_name!`. That leaves an actual usable ceiling of 47 characters for the fully-prefixed name (`<queue_prefix>_<logical_name>`), which is what this constant expresses. pgmq-ruby picked 48 to leave headroom for PGMQ’s internal tables (‘pgmq.q_`, `pgmq.a_`, sequences, indexes) which all get suffixed beyond the base name.
Historically this was 61 (the raw PostgreSQL ceiling minus PGMQ’s ‘q_`/`a_` prefix). That was wrong in practice: names in the 48-61 range passed pgbus’s validator but blew up deep inside pgmq-ruby with an InvalidQueueNameError — exactly the kind of opaque failure the validator was meant to catch up front.
47- VALID_QUEUE_NAME_PATTERN =
Only alphanumeric characters and underscores are allowed.
/\A[a-zA-Z0-9_]+\z/
Class Method Summary collapse
-
.normalize(name) ⇒ Object
Normalizes a queue name by replacing common separators (hyphens, dots, colons) with underscores, stripping remaining invalid characters, and collapsing consecutive underscores.
-
.sanitize!(name) ⇒ Object
Sanitizes a queue name by removing invalid characters, then validates.
-
.validate!(name) ⇒ Object
Validates a queue name for safe SQL identifier use.
Class Method Details
.normalize(name) ⇒ Object
Normalizes a queue name by replacing common separators (hyphens, dots, colons) with underscores, stripping remaining invalid characters, and collapsing consecutive underscores. Use this for names from external sources (e.g., Turbo stream names like “hotwire-livereload” or “gid://app/Foo/1”) where the intent is to derive a valid PGMQ queue name that preserves as much of the original identifier as possible.
Colons in particular are the turbo-rails stream-name separator (‘Pgbus.stream([user, :notifications])` → `“user_gid:notifications”`), so they must map to a safe character rather than be stripped —otherwise `“a:b”` and `“ab”` would collide on the same queue.
61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/pgbus/queue_name_validator.rb', line 61 def normalize(name) name = name.to_s return validate!(name) if VALID_QUEUE_NAME_PATTERN.match?(name) normalized = name.gsub(/[-.:]/, "_") # hyphens/dots/colons → underscores .gsub(/[^a-zA-Z0-9_]/, "") # strip remaining invalid chars .gsub(/_+/, "_") # collapse consecutive underscores .gsub(/\A_|_\z/, "") # strip leading/trailing underscores validate!(normalized) normalized end |
.sanitize!(name) ⇒ Object
Sanitizes a queue name by removing invalid characters, then validates. Use this for names from untrusted sources (e.g., URL params).
75 76 77 78 79 |
# File 'lib/pgbus/queue_name_validator.rb', line 75 def sanitize!(name) sanitized = name.to_s.gsub(/[^a-zA-Z0-9_]/, "") validate!(sanitized) sanitized end |
.validate!(name) ⇒ Object
Validates a queue name for safe SQL identifier use. Returns the name if valid, raises ArgumentError if not.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/pgbus/queue_name_validator.rb', line 33 def validate!(name) name = name.to_s raise ArgumentError, "Queue name cannot be blank" if name.empty? if name.length > MAX_QUEUE_NAME_LENGTH raise ArgumentError, "Queue name too long (#{name.length} chars, max #{MAX_QUEUE_NAME_LENGTH}): #{name.inspect}" end unless VALID_QUEUE_NAME_PATTERN.match?(name) raise ArgumentError, "Invalid queue name: #{name.inspect}. Only alphanumeric characters and underscores are allowed." end name end |