path-matching #1

Merged
dkam merged 7 commits from path-matching into main 2025-11-15 01:55:46 +00:00
3 changed files with 103 additions and 0 deletions
Showing only changes of commit d9701e4af6 - Show all commits

View File

@@ -0,0 +1,33 @@
<%# Compact rule display for showing rules on network range pages %>
<div class="flex items-center justify-between text-sm py-1.5 hover:bg-gray-50 px-2 -mx-2 rounded">
<div class="flex items-center space-x-2 min-w-0 flex-1">
<%= link_to rule, class: "flex items-center space-x-2 min-w-0 hover:text-blue-600" do %>
<%# Action badge %>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium <%= rule.waf_action == 'deny' ? 'bg-red-100 text-red-800' : rule.waf_action == 'allow' ? 'bg-green-100 text-green-800' : 'bg-blue-100 text-blue-800' %>">
<%= rule.waf_action.upcase %>
</span>
<%# Network CIDR %>
<span class="font-mono text-gray-900 truncate"><%= rule.network_range.cidr %></span>
<%# Priority %>
<span class="text-xs text-gray-500">P:<%= rule.priority %></span>
<% end %>
</div>
<div class="flex items-center space-x-2 flex-shrink-0">
<%# Disabled badge %>
<% unless rule.enabled? %>
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-gray-200 text-gray-600" title="<%= rule.metadata_hash['disabled_reason'] %>">
Disabled
</span>
<% end %>
<%# Policy badge if policy-generated %>
<% if rule.waf_policy.present? %>
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-purple-100 text-purple-800" title="<%= rule.waf_policy.name %>">
Policy
</span>
<% end %>
</div>
</div>

View File

@@ -0,0 +1,12 @@
class RemoveLegacyColumnsFromRules < ActiveRecord::Migration[8.1]
def change
# Remove indexes first
remove_index :rules, name: "index_rules_on_action" if index_exists?(:rules, name: "index_rules_on_action")
remove_index :rules, name: "index_rules_on_rule_type" if index_exists?(:rules, name: "index_rules_on_rule_type")
remove_index :rules, name: "idx_rules_type_enabled" if index_exists?(:rules, name: "idx_rules_type_enabled")
# Remove the legacy columns
remove_column :rules, :action, :string
remove_column :rules, :rule_type, :string
end
end

View File

@@ -0,0 +1,58 @@
# frozen_string_literal: true
class AddTimeAwareUniqueIndexesToRules < ActiveRecord::Migration[8.1]
def up
# First, clean up existing duplicate records to allow unique constraints
cleanup_duplicate_rules
# Add time-aware unique indexes for policy-generated rules
# This prevents exact duplicate time windows while allowing temporal flexibility
# For temporary rules (with expiration dates)
add_index :rules,
[:network_range_id, :waf_action, :waf_policy_id, :expires_at],
name: 'index_rules_on_network_policy_expires_unique',
unique: true,
where: "source = 'policy' AND expires_at IS NOT NULL"
# For permanent rules (no expiration date)
add_index :rules,
[:network_range_id, :waf_action, :waf_policy_id],
name: 'index_rules_on_network_policy_unique',
unique: true,
where: "source = 'policy' AND expires_at IS NULL"
# Additional indexes for performance
add_index :rules, [:source, :expires_at], name: 'index_rules_on_source_expires'
add_index :rules, [:waf_policy_id, :expires_at], name: 'index_rules_on_policy_expires'
end
def down
remove_index :rules, name: 'index_rules_on_network_policy_expires_unique'
remove_index :rules, name: 'index_rules_on_network_policy_unique'
remove_index :rules, name: 'index_rules_on_source_expires'
remove_index :rules, name: 'index_rules_on_policy_expires'
end
private
def cleanup_duplicate_rules
# Clean up duplicates for policy rules with the same expiration time
duplicate_sql = <<~SQL
WITH ranked_rules AS (
SELECT id,
ROW_NUMBER() OVER (
PARTITION BY network_range_id, waf_action, waf_policy_id, expires_at
ORDER BY created_at DESC
) as rn
FROM rules
WHERE source = 'policy'
)
DELETE FROM rules
WHERE id IN (SELECT id FROM ranked_rules WHERE rn > 1)
SQL
execute duplicate_sql
Rails.logger.info "Cleaned up duplicate policy rules with same expiration times"
end
end