class AlignWafActionEnums < ActiveRecord::Migration[8.1] def up # Current enum mapping (BEFORE): # allow: 0, deny: 1, rate_limit: 2, redirect: 3, log: 4, challenge: 5 # # Target enum mapping (AFTER): # deny: 0, allow: 1, redirect: 2, challenge: 3, log: 4 # # Strategy: Use temporary values to avoid conflicts during swap say "Aligning WAF action enums to canonical order (deny:0, allow:1, redirect:2, challenge:3, log:4)" # === Rules Table === say_with_time "Updating rules table..." do # Temporarily disable triggers to avoid FK constraint issues during enum swap execute "SET session_replication_role = replica;" # Step 1: Move existing values to temporary range (100+) execute <<-SQL UPDATE rules SET waf_action = CASE WHEN waf_action = 0 THEN 100 -- allow -> temp(100) WHEN waf_action = 1 THEN 101 -- deny -> temp(101) WHEN waf_action = 2 THEN 102 -- rate_limit -> temp(102) WHEN waf_action = 3 THEN 103 -- redirect -> temp(103) WHEN waf_action = 4 THEN 104 -- log -> temp(104) WHEN waf_action = 5 THEN 105 -- challenge -> temp(105) ELSE waf_action END SQL # Step 2: Move from temporary to final positions execute <<-SQL UPDATE rules SET waf_action = CASE WHEN waf_action = 101 THEN 0 -- deny -> 0 WHEN waf_action = 100 THEN 1 -- allow -> 1 WHEN waf_action = 103 THEN 2 -- redirect -> 2 WHEN waf_action = 105 THEN 3 -- challenge -> 3 WHEN waf_action = 104 THEN 4 -- log -> 4 WHEN waf_action = 102 THEN 0 -- rate_limit -> deny (rate_limit is a rule_type, not action) ELSE waf_action END SQL # Re-enable triggers execute "SET session_replication_role = DEFAULT;" # Return count without triggering model validations connection.execute("SELECT COUNT(*) FROM rules").first["count"] end # === Events Table === say_with_time "Updating events table..." do # Step 1: Move existing values to temporary range (100+) execute <<-SQL UPDATE events SET waf_action = CASE WHEN waf_action = 0 THEN 100 -- allow -> temp(100) WHEN waf_action = 1 THEN 101 -- deny -> temp(101) WHEN waf_action = 2 THEN 102 -- redirect -> temp(102) WHEN waf_action = 3 THEN 103 -- challenge -> temp(103) ELSE waf_action END SQL # Step 2: Move from temporary to final positions execute <<-SQL UPDATE events SET waf_action = CASE WHEN waf_action = 101 THEN 0 -- deny -> 0 WHEN waf_action = 100 THEN 1 -- allow -> 1 WHEN waf_action = 102 THEN 2 -- redirect -> 2 WHEN waf_action = 103 THEN 3 -- challenge -> 3 ELSE waf_action END SQL # Return count without triggering model validations connection.execute("SELECT COUNT(*) FROM events").first["count"] end say "Enum alignment complete!", true end def down # Reverse the migration - swap back to old order say "Reverting WAF action enums to original order" # === Rules Table === say_with_time "Reverting rules table..." do execute <<-SQL UPDATE rules SET waf_action = CASE WHEN waf_action = 0 THEN 100 -- deny -> temp(100) WHEN waf_action = 1 THEN 101 -- allow -> temp(101) WHEN waf_action = 2 THEN 102 -- redirect -> temp(102) WHEN waf_action = 3 THEN 103 -- challenge -> temp(103) WHEN waf_action = 4 THEN 104 -- log -> temp(104) ELSE waf_action END SQL execute <<-SQL UPDATE rules SET waf_action = CASE WHEN waf_action = 101 THEN 0 -- allow -> 0 WHEN waf_action = 100 THEN 1 -- deny -> 1 WHEN waf_action = 104 THEN 4 -- log -> 4 WHEN waf_action = 103 THEN 3 -- redirect -> 3 WHEN waf_action = 102 THEN 2 -- rate_limit -> 2 (restore even though deprecated) WHEN waf_action = 105 THEN 5 -- challenge -> 5 ELSE waf_action END SQL # Return count without triggering model validations connection.execute("SELECT COUNT(*) FROM rules").first["count"] end # === Events Table === say_with_time "Reverting events table..." do execute <<-SQL UPDATE events SET waf_action = CASE WHEN waf_action = 0 THEN 100 -- deny -> temp(100) WHEN waf_action = 1 THEN 101 -- allow -> temp(101) WHEN waf_action = 2 THEN 102 -- redirect -> temp(102) WHEN waf_action = 3 THEN 103 -- challenge -> temp(103) ELSE waf_action END SQL execute <<-SQL UPDATE events SET waf_action = CASE WHEN waf_action = 101 THEN 0 -- allow -> 0 WHEN waf_action = 100 THEN 1 -- deny -> 1 WHEN waf_action = 102 THEN 2 -- redirect -> 2 WHEN waf_action = 103 THEN 3 -- challenge -> 3 ELSE waf_action END SQL # Return count without triggering model validations connection.execute("SELECT COUNT(*) FROM events").first["count"] end say "Revert complete!", true end end