fix(waf): correct whitelist logic to bypass and add config/IP-group edit broadcasts

- Transition WAF whitelist filter from strict block-on-miss to bypass-on-hit logic

- Hook up broadcastIPGroupToAgents to CreateIPGroup and UpdateIPGroup WAF logics

- Hook up BroadcastActiveConfig to PublishConfigVersion and ActivateConfigVersion version logics

- Update WAF Lua tests in manager_test.go
This commit is contained in:
ryan
2026-06-26 20:47:30 +08:00
parent 49eae80c78
commit b89dc9ec7e
6 changed files with 42 additions and 24 deletions
+5 -8
View File
@@ -699,15 +699,12 @@ func TestManagedPowLuaFilesUseInternalChallengeFlow(t *testing.T) {
}
}
func TestManagedWAFLuaTreatsWhitelistAsAllowlist(t *testing.T) {
if !strings.Contains(openRestyWAFRuntimeLua, "local function first_allowlist_group(groups)") {
t.Fatal("expected waf runtime to detect allowlist rule groups")
func TestManagedWAFLuaTreatsWhitelistAsBypass(t *testing.T) {
if !strings.Contains(openRestyWAFRuntimeLua, "if ip_matches(group.ip_whitelist, ip)") {
t.Fatal("expected waf runtime to bypass request when ip matches whitelist")
}
if !strings.Contains(openRestyWAFRuntimeLua, "local allowlist_group = first_allowlist_group(groups)") {
t.Fatal("expected waf runtime to enter allowlist mode when whitelist rules exist")
}
if !strings.Contains(openRestyWAFRuntimeLua, "return exit_with_group(allowlist_group)") {
t.Fatal("expected waf runtime to block requests that miss configured whitelists")
if strings.Contains(openRestyWAFRuntimeLua, "first_allowlist_group") {
t.Fatal("expected waf runtime not to block requests that miss configured whitelists")
}
}
-16
View File
@@ -219,17 +219,6 @@ local function exit_with_group(group)
return ngx.exit(ngx.status)
end
local function first_allowlist_group(groups)
for _, group in ipairs(groups) do
if table_has_items(group.ip_whitelist)
or table_has_items(group.ip_whitelist_group_ids)
or table_has_items(group.country_whitelist) then
return group
end
end
return nil
end
local config = load_config()
if not config then
if config_dict:add("_missing_config_logged", true, 60) then
@@ -264,11 +253,6 @@ for _, group in ipairs(groups) do
end
end
local allowlist_group = first_allowlist_group(groups)
if allowlist_group then
return exit_with_group(allowlist_group)
end
for _, group in ipairs(groups) do
if ip_matches(group.ip_blacklist, ip) or ip_matches_group_ids(group.ip_blacklist_group_ids, ip, ip_groups_config) then
return exit_with_group(group)
@@ -15,7 +15,9 @@ import (
"time"
"github.com/Rain-kl/Wavelet/internal/apps/openflare/routeidentity"
"github.com/Rain-kl/Wavelet/internal/apps/openflare/websocket"
"github.com/Rain-kl/Wavelet/internal/model"
pkgprotocol "github.com/Rain-kl/Wavelet/pkg/protocol"
openrestyrender "github.com/Rain-kl/Wavelet/pkg/render/openresty"
"gorm.io/gorm"
)
@@ -233,6 +235,10 @@ func PublishConfigVersion(ctx context.Context, createdBy string, force bool) (*m
}
return nil, err
}
websocket.BroadcastActiveConfig(pkgprotocol.ActiveConfigMeta{
Version: record.Version,
Checksum: record.Checksum,
})
return record, nil
}
@@ -246,6 +252,10 @@ func ActivateConfigVersion(ctx context.Context, id uint) (*model.ConfigVersion,
return nil, err
}
version.IsActive = true
websocket.BroadcastActiveConfig(pkgprotocol.ActiveConfigMeta{
Version: version.Version,
Checksum: version.Checksum,
})
return version, nil
}
+2
View File
@@ -454,6 +454,7 @@ func CreateIPGroup(ctx context.Context, input IPGroupInput) (*IPGroupView, error
if err = model.CreateOpenFlareWAFIPGroup(ctx, group); err != nil {
return nil, err
}
broadcastIPGroupToAgents(ctx, group.ID)
return GetIPGroup(ctx, group.ID)
}
@@ -470,6 +471,7 @@ func UpdateIPGroup(ctx context.Context, id uint, input IPGroupInput) (*IPGroupVi
if err = model.UpdateOpenFlareWAFIPGroup(ctx, group); err != nil {
return nil, err
}
broadcastIPGroupToAgents(ctx, group.ID)
return GetIPGroup(ctx, group.ID)
}
@@ -152,6 +152,28 @@ func BroadcastWAFIPGroups(payload any) int {
return success
}
// BroadcastActiveConfig pushes active config metadata to all connected agents.
func BroadcastActiveConfig(payload any) int {
if payload == nil {
return 0
}
message := Message{Type: agentMessageTypeActiveConfig, Payload: payload}
defaultAgentHub.mu.RLock()
clients := make([]*agentClient, 0, len(defaultAgentHub.clients))
for _, client := range defaultAgentHub.clients {
clients = append(clients, client)
}
defaultAgentHub.mu.RUnlock()
success := 0
for _, client := range clients {
if client.enqueue(message) {
success++
}
}
return success
}
// SendForceSyncConfig notifies an agent to force sync configuration.
func SendForceSyncConfig(nodeID string, payload any) bool {
return sendAgentMessage(nodeID, Message{Type: agentMessageTypeForceSyncConfig, Payload: payload})