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

@ -109,7 +109,7 @@ func (pm *PolicyManager) updateLocked() (bool, error) {
pm.needsPerNodeFilter = hasPerNodeGrants(pm.compiledGrants)
var filter []tailcfg.FilterRule
if pm.pol == nil || (pm.pol.ACLs == nil && len(pm.pol.Grants) == 0) {
if pm.pol == nil || (pm.pol.ACLs == nil && pm.pol.Grants == nil) {
filter = tailcfg.FilterAllowAll
} else {
filter = globalFilterRules(pm.compiledGrants)