policy/v2: sort approved routes in wildcard sources

They followed NodeStore map order, so the same policy read as changed.
This commit is contained in:
Kristoffer Dalby committed 2026-11-03 17:05:00 +01:00
1 parent 8ba627c3f4
commit 5741dba87d
2 files changed
+25

No files matched your search

+21
View File
@@ -16,6 +16,7 @@ import (
"github.com/juanfont/headscale/hscontrol/types"
"github.com/puzpuzpuz/xsync/v4"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go4.org/netipx"
"pgregory.net/rapid"
@@ -25,6 +26,26 @@ import (
"tailscale.com/types/views"
)
// TestApprovedSubnetRoutesIgnoreNodeOrder: the routes land in every wildcard
// rule, and the filter hash decides whether a policy write changed anything.
func TestApprovedSubnetRoutesIgnoreNodeOrder(t *testing.T) {
t.Parallel()
router := func(name, route string) *types.Node {
n := node(name, "100.64.0.1", "fd7a:115c:a1e0::1", types.User{Name: "owner"})
r := netip.MustParsePrefix(route)
n.Hostinfo = &tailcfg.Hostinfo{RoutableIPs: []netip.Prefix{r}}
n.ApprovedRoutes = []netip.Prefix{r}
return n
}
a, b := router("a", "10.2.0.0/16"), router("b", "10.1.0.0/16")
want := []string{"10.1.0.0/16", "10.2.0.0/16"}
assert.Equal(t, want, approvedSubnetRoutes(types.Nodes{a, b}.ViewSlice()))
assert.Equal(t, want, approvedSubnetRoutes(types.Nodes{b, a}.ViewSlice()))
}
func node(name, ipv4, ipv6 string, user types.User) *types.Node {
return &types.Node{
ID: 0,
+4
View File
@@ -386,6 +386,10 @@ func approvedSubnetRoutes(nodes views.Slice[types.NodeView]) []string {
}
}
// Nodes come in no fixed order. Without this, the same policy compiles to a
// new filter hash and reads as changed.
slices.Sort(routes)
return routes
}