From 2948b8ffe86f2b9ee923aa88b229d3515060f910 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Thu, 3 Sep 2026 18:22:48 +0800 Subject: [PATCH] fix: normalize Docker firewall rule sync (#13704) --- agent/app/service/firewall_sync.go | 4 +++- agent/utils/firewall/docker_guard/policy.go | 17 ++++++++++++++++- frontend/src/views/host/firewall/sync/index.vue | 4 +++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/agent/app/service/firewall_sync.go b/agent/app/service/firewall_sync.go index 60c3e338e..f1736756b 100644 --- a/agent/app/service/firewall_sync.go +++ b/agent/app/service/firewall_sync.go @@ -790,7 +790,9 @@ func (p databaseSyncPlan) preview() dto.FirewallRuleSyncPreview { result.Total++ case firewallRuleSyncBlocked: result.Blocked++ - result.Total++ + if item.ReasonCode != firewallsync.ReasonReadOnlyRule { + result.Total++ + } case firewallsync.StatusRemove: result.Removed++ } diff --git a/agent/utils/firewall/docker_guard/policy.go b/agent/utils/firewall/docker_guard/policy.go index d8c72d422..131f88ea1 100644 --- a/agent/utils/firewall/docker_guard/policy.go +++ b/agent/utils/firewall/docker_guard/policy.go @@ -91,7 +91,10 @@ func PolicySyncKey(policy Policy) string { if mode == ModeAllow && len(policy.Sources) == 0 { mode = ModeAll } - sources := append([]string(nil), policy.Sources...) + sources := make([]string, 0, len(policy.Sources)) + for _, source := range policy.Sources { + sources = append(sources, canonicalPolicySource(source)) + } sort.Strings(sources) return strings.Join([]string{ policy.UUID, policy.Family, CanonicalHost(policy.HostIP), strconv.Itoa(int(policy.HostPort)), @@ -99,6 +102,18 @@ func PolicySyncKey(policy Policy) string { }, "\x00") } +func canonicalPolicySource(value string) string { + value = strings.TrimSpace(value) + if prefix, err := netip.ParsePrefix(value); err == nil { + return prefix.Masked().String() + } + if address, err := netip.ParseAddr(value); err == nil { + address = address.Unmap() + return netip.PrefixFrom(address, address.BitLen()).String() + } + return value +} + func PolicyStatesEqual(left, right []Policy) bool { if len(left) != len(right) { return false diff --git a/frontend/src/views/host/firewall/sync/index.vue b/frontend/src/views/host/firewall/sync/index.vue index cc1e40a75..c71df7fb8 100644 --- a/frontend/src/views/host/firewall/sync/index.vue +++ b/frontend/src/views/host/firewall/sync/index.vue @@ -205,7 +205,9 @@ const syncDisabled = computed(() => { const detailItems = computed(() => { if (!preview.value || !detailFilter.value) return []; const items = preview.value.items || []; - if (detailFilter.value === 'total') return items.filter((item) => item.status !== 'remove'); + if (detailFilter.value === 'total') { + return items.filter((item) => item.status !== 'remove' && item.reasonCode !== 'read_only_rule'); + } return items.filter((item) => item.status === detailFilter.value); });