policy/v2: fix empty grants/acls returning FilterAllowAll

compileFilterRules, compileGrants, and updateLocked guarded the
"no rules so allow all" fallback with len(pol.Grants) == 0, which
matches both an absent grants field and an explicit empty array.
JSON {"grants": []} unmarshals to a non-nil empty slice; it should
compile to zero filter rules (deny all) to match Tailscale SaaS,
but the length check sent it down the FilterAllowAll path.

Distinguish absent (nil) from explicit-empty by switching the guard
to pol.Grants == nil, the same asymmetry already used for ACLs.
{} keeps allowing all; {"acls": []} and {"grants": []} now both
deny all.

Fixes #3211
This commit is contained in:
Kristoffer Dalby 2026-04-28 09:21:18 +00:00
parent 174e409da6
commit 2e1a716a9a
6 changed files with 63 additions and 5 deletions

View file

@ -44,6 +44,20 @@ func TestPolicyManager(t *testing.T) {
wantFilter: tailcfg.FilterAllowAll,
wantMatchers: matcher.MatchesFromFilterRules(tailcfg.FilterAllowAll),
},
{
name: "empty-acls-denies-all",
pol: `{"acls": []}`,
nodes: types.Nodes{},
wantFilter: nil,
wantMatchers: matcher.MatchesFromFilterRules(nil),
},
{
name: "empty-grants-denies-all",
pol: `{"grants": []}`,
nodes: types.Nodes{},
wantFilter: nil,
wantMatchers: matcher.MatchesFromFilterRules(nil),
},
}
for _, tt := range tests {