Class: Blazer::Ai::SqlValidator

Inherits:
Object
  • Object
show all
Defined in:
lib/blazer/ai/sql_validator.rb

Defined Under Namespace

Classes: ValidationError

Constant Summary collapse

FORBIDDEN_KEYWORDS =

Keywords that indicate write/dangerous operations - never allow these

%w[
  INSERT UPDATE DELETE DROP TRUNCATE ALTER CREATE
  GRANT REVOKE COMMIT ROLLBACK SAVEPOINT LOCK
  EXEC EXECUTE CALL
  UNION
  COPY
  DECLARE SET
  PREPARE DEALLOCATE
  ATTACH DETACH
].freeze
DANGEROUS_PATTERNS =

Patterns that indicate potential SQL injection or dangerous operations

[
  /;\s*\w/i,                   # Multiple statements
  /--/,                        # SQL comments (potential injection)
  /\/\*/,                      # Block comments
  /#(?!\{)/,                   # MySQL comments (but not Ruby interpolation)
  /\$\$/,                      # PostgreSQL dollar quoting
  /INTO\s+OUTFILE/i,           # File operations
  /INTO\s+DUMPFILE/i,          # File operations
  /LOAD_FILE/i,                # File operations
  /LOAD\s+DATA/i,              # MySQL file loading
  /SLEEP\s*\(/i,               # Time-based attacks
  /BENCHMARK\s*\(/i,           # Time-based attacks
  /WAITFOR\s+DELAY/i,          # SQL Server time attack
  /PG_SLEEP/i,                 # PostgreSQL time attack
  /PG_READ_FILE/i,             # PostgreSQL file read
  /PG_LS_DIR/i,                # PostgreSQL directory listing
  /UTL_FILE/i,                 # Oracle file operations
  /DBMS_/i,                    # Oracle packages
  /XP_CMDSHELL/i,              # SQL Server command execution
  /SP_CONFIGURE/i,             # SQL Server configuration
  /0x[0-9A-Fa-f]{8,}/i        # Long hex strings (potential encoding attacks)
].freeze

Instance Method Summary collapse

Instance Method Details

#extract_clean_sql(content) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/blazer/ai/sql_validator.rb', line 79

def extract_clean_sql(content)
  return nil if content.blank?

  # Try to extract SQL from markdown code blocks
  if content.include?("```")
    match = content.match(/```(?:sql)?\s*\n?(.*?)\n?```/m)
    return match[1].strip if match
  end

  # Otherwise return the content stripped
  content.strip
end

#safe?(sql) ⇒ Boolean

Returns:



72
73
74
75
76
77
# File 'lib/blazer/ai/sql_validator.rb', line 72

def safe?(sql)
  validate!(sql)
  true
rescue ValidationError
  false
end

#validate!(sql) ⇒ Object

Raises:



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/blazer/ai/sql_validator.rb', line 42

def validate!(sql)
  raise ValidationError, "SQL cannot be empty" if sql.blank?

  # Normalize Unicode to prevent homoglyph attacks (e.g., Cyrillic characters)
  # and strip non-ASCII from keyword matching
  ascii_only = sql.encode("ASCII", undef: :replace, replace: "").upcase.gsub(/\s+/, " ")
  normalized = sql.upcase.gsub(/\s+/, " ")

  # Check for forbidden keywords (check both normalized and ASCII-only versions)
  FORBIDDEN_KEYWORDS.each do |keyword|
    if normalized.match?(/\b#{keyword}\b/) || ascii_only.match?(/\b#{keyword}\b/)
      raise ValidationError, "SQL contains forbidden keyword: #{keyword}"
    end
  end

  # Check for dangerous patterns
  DANGEROUS_PATTERNS.each do |pattern|
    if sql.match?(pattern)
      raise ValidationError, "SQL contains potentially dangerous pattern"
    end
  end

  # Ensure it starts with SELECT or WITH
  unless normalized.match?(/^\s*(SELECT|WITH)\b/)
    raise ValidationError, "SQL must start with SELECT or WITH"
  end

  true
end