mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
feat(waf): complete composable rule orchestration
Add the React Flow rule editor, ordered graph APIs and runtime DAG execution.\n\nPublish rules only on OpenResty reload and reconcile checksum-driven IP group snapshots in bounded shared memory.
This commit is contained in:
@@ -14,26 +14,14 @@ import (
|
||||
|
||||
// OpenFlareWAFRuleGroup stores a WAF rule group.
|
||||
type OpenFlareWAFRuleGroup struct {
|
||||
ID uint `json:"id" gorm:"primaryKey;autoIncrement"`
|
||||
Name string `json:"name" gorm:"size:255;not null"`
|
||||
Enabled bool `json:"enabled" gorm:"not null;default:true"`
|
||||
IsGlobal bool `json:"is_global" gorm:"not null;default:false;index"`
|
||||
BlockStatusCode int `json:"block_status_code" gorm:"not null;default:418"`
|
||||
BlockResponseBody string `json:"block_response_body" gorm:"type:text;not null;default:''"`
|
||||
IPWhitelist string `json:"ip_whitelist" gorm:"type:text;not null;default:'[]'"`
|
||||
IPBlacklist string `json:"ip_blacklist" gorm:"type:text;not null;default:'[]'"`
|
||||
IPWhitelistGroups string `json:"ip_whitelist_group_ids" gorm:"column:ip_whitelist_groups;type:text;not null;default:'[]'"`
|
||||
IPBlacklistGroups string `json:"ip_blacklist_group_ids" gorm:"column:ip_blacklist_groups;type:text;not null;default:'[]'"`
|
||||
CountryWhitelist string `json:"country_whitelist" gorm:"type:text;not null;default:'[]'"`
|
||||
CountryBlacklist string `json:"country_blacklist" gorm:"type:text;not null;default:'[]'"`
|
||||
RegionWhitelist string `json:"region_whitelist" gorm:"type:text;not null;default:'[]'"`
|
||||
RegionBlacklist string `json:"region_blacklist" gorm:"type:text;not null;default:'[]'"`
|
||||
PoWEnabled bool `json:"pow_enabled" gorm:"column:pow_enabled;not null;default:false"`
|
||||
PoWConfig string `json:"pow_config" gorm:"column:pow_config;type:text;not null;default:'{}'"`
|
||||
Graph string `json:"graph" gorm:"type:text;not null;default:''"`
|
||||
Revision uint64 `json:"revision" gorm:"not null;default:1"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
|
||||
ID uint `json:"id" gorm:"primaryKey;autoIncrement"`
|
||||
Name string `json:"name" gorm:"size:255;not null"`
|
||||
Enabled bool `json:"enabled" gorm:"not null;default:true"`
|
||||
IsGlobal bool `json:"is_global" gorm:"not null;default:false;index"`
|
||||
Graph string `json:"graph" gorm:"type:text;not null;default:''"`
|
||||
Revision uint64 `json:"revision" gorm:"not null;default:1"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
|
||||
}
|
||||
|
||||
// TableName returns the GORM table name.
|
||||
@@ -147,21 +135,9 @@ func UpdateOpenFlareWAFRuleGroup(ctx context.Context, group *OpenFlareWAFRuleGro
|
||||
return err
|
||||
}
|
||||
return conn.Model(&OpenFlareWAFRuleGroup{}).Where("id = ?", group.ID).Updates(map[string]any{
|
||||
"name": group.Name,
|
||||
colEnabled: group.Enabled,
|
||||
"is_global": group.IsGlobal,
|
||||
"block_status_code": group.BlockStatusCode,
|
||||
"block_response_body": group.BlockResponseBody,
|
||||
"ip_whitelist": group.IPWhitelist,
|
||||
"ip_blacklist": group.IPBlacklist,
|
||||
"ip_whitelist_groups": group.IPWhitelistGroups,
|
||||
"ip_blacklist_groups": group.IPBlacklistGroups,
|
||||
"country_whitelist": group.CountryWhitelist,
|
||||
"country_blacklist": group.CountryBlacklist,
|
||||
"region_whitelist": group.RegionWhitelist,
|
||||
"region_blacklist": group.RegionBlacklist,
|
||||
"pow_enabled": group.PoWEnabled,
|
||||
"pow_config": group.PoWConfig,
|
||||
"name": group.Name,
|
||||
colEnabled: group.Enabled,
|
||||
"is_global": group.IsGlobal,
|
||||
}).Error
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ func wafMigrationFS(t *testing.T) fs.FS {
|
||||
for _, name := range []string{
|
||||
"202607150001_orchestrate_waf_rules.sql",
|
||||
"202607150002_reset_waf_rule_graphs.sql",
|
||||
"202607150003_drop_legacy_waf_rule_fields.sql",
|
||||
} {
|
||||
contents, err := os.ReadFile(filepath.Join(dir, name))
|
||||
require.NoError(t, err)
|
||||
@@ -45,7 +46,7 @@ func TestOpenFlareWAFGraphMigrationResetsGraphsAndOrdersBindings(t *testing.T) {
|
||||
sqlDB, err := conn.DB()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, conn.Exec(`CREATE TABLE of_waf_rule_groups (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)`).Error)
|
||||
require.NoError(t, conn.Exec(`CREATE TABLE of_waf_rule_groups (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, block_status_code INTEGER NOT NULL DEFAULT 418, block_response_body TEXT NOT NULL DEFAULT '', ip_whitelist TEXT NOT NULL DEFAULT '[]', ip_blacklist TEXT NOT NULL DEFAULT '[]', ip_whitelist_groups TEXT NOT NULL DEFAULT '[]', ip_blacklist_groups TEXT NOT NULL DEFAULT '[]', country_whitelist TEXT NOT NULL DEFAULT '[]', country_blacklist TEXT NOT NULL DEFAULT '[]', region_whitelist TEXT NOT NULL DEFAULT '[]', region_blacklist TEXT NOT NULL DEFAULT '[]', pow_enabled BOOLEAN NOT NULL DEFAULT 0, pow_config TEXT NOT NULL DEFAULT '{}')`).Error)
|
||||
require.NoError(t, conn.Exec(`CREATE TABLE of_waf_rule_group_bindings (id INTEGER PRIMARY KEY AUTOINCREMENT, rule_group_id INTEGER NOT NULL, proxy_route_id INTEGER NOT NULL)`).Error)
|
||||
require.NoError(t, conn.Exec(`INSERT INTO of_waf_rule_groups (id, name) VALUES (1, 'one'), (2, 'two')`).Error)
|
||||
require.NoError(t, conn.Exec(`INSERT INTO of_waf_rule_group_bindings (id, rule_group_id, proxy_route_id) VALUES (20, 2, 7), (10, 1, 7)`).Error)
|
||||
@@ -61,6 +62,9 @@ func TestOpenFlareWAFGraphMigrationResetsGraphsAndOrdersBindings(t *testing.T) {
|
||||
require.JSONEq(t, defaultWAFRuleGraph, group.Graph)
|
||||
assert.Equal(t, uint64(1), group.Revision)
|
||||
}
|
||||
for _, column := range []string{"block_status_code", "ip_whitelist", "pow_enabled"} {
|
||||
assert.False(t, conn.Migrator().HasColumn("of_waf_rule_groups", column))
|
||||
}
|
||||
|
||||
require.NoError(t, conn.Exec(`INSERT INTO of_waf_rule_groups (name) VALUES ('new')`).Error)
|
||||
var newGroup OpenFlareWAFRuleGroup
|
||||
@@ -105,3 +109,15 @@ func TestReplaceOpenFlareWAFRuleGroupBindingsPreservesInputOrder(t *testing.T) {
|
||||
assert.Equal(t, []uint{30, 10, 20}, []uint{bindings[0].RuleGroupID, bindings[1].RuleGroupID, bindings[2].RuleGroupID})
|
||||
assert.Equal(t, []int{0, 1, 2}, []int{bindings[0].Sequence, bindings[1].Sequence, bindings[2].Sequence})
|
||||
}
|
||||
|
||||
func TestLegacyWAFColumnsRemoved(t *testing.T) {
|
||||
conn, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, conn.AutoMigrate(&OpenFlareWAFRuleGroup{}))
|
||||
legacy := []string{"block_status_code", "block_response_body", "ip_whitelist", "ip_blacklist", "ip_whitelist_groups", "ip_blacklist_groups", "country_whitelist", "country_blacklist", "region_whitelist", "region_blacklist", "pow_enabled", "pow_config"}
|
||||
for _, column := range legacy {
|
||||
if conn.Migrator().HasColumn(&OpenFlareWAFRuleGroup{}, column) {
|
||||
t.Fatalf("legacy WAF column %s still exists", column)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user