Class: QueryGuard::Migrations::MigrationAnalyzer

Inherits:
Analyzers::Base show all
Defined in:
lib/query_guard/migrations/migration_analyzer.rb

Overview

Migration risk analyzer - scans Rails migration files for risky patterns. Searches for dangerous operations like:

  • Index additions without algorithm: :concurrently
  • Column removals/type changes
  • Non-NULL additions without defaults
  • Full-table updates
  • Unsafe raw SQL

Optionally integrates with database metadata for table-size-aware risk estimation.

Example:

analyzer = MigrationAnalyzer.new
findings = analyzer.analyze_migration(migration_file_path)

With table size awareness:

connection = ActiveRecord::Base.connection
adapter = PostgreSQLAdapter.new(connection)
analyzer = MigrationAnalyzer.new(database_adapter: adapter)
findings = analyzer.analyze_migration(migration_file_path)

Instance Attribute Summary

Attributes inherited from Analyzers::Base

#name

Instance Method Summary collapse

Methods inherited from Analyzers::Base

#enabled?

Constructor Details

#initialize(database_adapter: nil) ⇒ MigrationAnalyzer

Initialize analyzer

Parameters:

  • database_adapter (DatabaseAdapter) (defaults to: nil) —

    Optional adapter for table metadata



28
29
30
31
32
# File 'lib/query_guard/migrations/migration_analyzer.rb', line 28

def initialize(database_adapter: nil)
  super(:migration_risk)
  @database_adapter = database_adapter
  @table_risk_analyzer = TableRiskAnalyzer.new(database_adapter)
end

Instance Method Details

#analyze(context, config) ⇒ Array<Core::Finding>

Analyze method for integration with QueryGuard context This is called by registry when running full analysis

Parameters:

  • context (Core::Context) —

    Not used for migrations, but required by Base

  • config (Config) —

    Configuration object

Returns:



73
74
75
76
# File 'lib/query_guard/migrations/migration_analyzer.rb', line 73

def analyze(context, config)
  migrations_dir = config&.migrations_directory || "db/migrate"
  analyze_migrations_directory(migrations_dir)
end

#analyze_migration(file_path) ⇒ Array<Core::Finding>

Analyze a single migration file

Parameters:

  • file_path (String) —

    Path to migration file

Returns:



38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/query_guard/migrations/migration_analyzer.rb', line 38

def analyze_migration(file_path)
  return [] unless File.exist?(file_path)

  content = File.read(file_path)
  migration_name = File.basename(file_path, ".rb")

  risks = MigrationRiskDetectors.detect_risks(content, migration_name)
  
  # Enhance risks with table metadata if adapter available
  risks = @table_risk_analyzer.enhance_risks(content, risks)

  risks_to_findings(risks, file_path)
end

#analyze_migrations_directory(migrations_dir = "db/migrate") ⇒ Array<Core::Finding>

Analyze all migrations in a directory

Parameters:

  • migrations_dir (String) (defaults to: "db/migrate") —

    Path to db/migrate directory

Returns:

  • (Array<Core::Finding>) —

    List of findings from all migrations



56
57
58
59
60
61
62
63
64
65
# File 'lib/query_guard/migrations/migration_analyzer.rb', line 56

def analyze_migrations_directory(migrations_dir = "db/migrate")
  findings = []
  return findings unless Dir.exist?(migrations_dir)

  Dir.glob(File.join(migrations_dir, "*.rb")).each do |file_path|
    findings.concat(analyze_migration(file_path))
  end

  findings
end