mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-11-04 10:11:18 +01:00 
			
		
		
		
	This is step 1 of ~3, breaking up #14720 into reviewable chunks, with the aim to make syspolicy be a build-time configurable feature. In this first (very noisy) step, all the syspolicy string key constants move to a new constant-only (code-free) package. This will make future steps more reviewable, without this movement noise. There are no code or behavior changes here. The future steps of this series can be seen in #14720: removing global funcs from syspolicy resolution and using an interface that's plumbed around instead. Then adding build tags. Updates #12614 Change-Id: If73bf2c28b9c9b1a408fe868b0b6a25b03eeabd1 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
		
			
				
	
	
		
			346 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			346 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) Tailscale Inc & AUTHORS
 | 
						|
// SPDX-License-Identifier: BSD-3-Clause
 | 
						|
 | 
						|
package setting
 | 
						|
 | 
						|
import (
 | 
						|
	"slices"
 | 
						|
	"strings"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"tailscale.com/types/lazy"
 | 
						|
	"tailscale.com/types/ptr"
 | 
						|
	"tailscale.com/util/syspolicy/internal"
 | 
						|
	"tailscale.com/util/syspolicy/pkey"
 | 
						|
)
 | 
						|
 | 
						|
func TestSettingDefinition(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name                   string
 | 
						|
		setting                *Definition
 | 
						|
		osOverride             string
 | 
						|
		wantKey                pkey.Key
 | 
						|
		wantScope              Scope
 | 
						|
		wantType               Type
 | 
						|
		wantIsSupported        bool
 | 
						|
		wantSupportedPlatforms PlatformList
 | 
						|
		wantString             string
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:            "Nil",
 | 
						|
			setting:         nil,
 | 
						|
			wantKey:         "",
 | 
						|
			wantScope:       0,
 | 
						|
			wantType:        InvalidValue,
 | 
						|
			wantIsSupported: false,
 | 
						|
			wantString:      "(nil)",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "Device/Invalid",
 | 
						|
			setting:         NewDefinition("TestDevicePolicySetting", DeviceSetting, InvalidValue),
 | 
						|
			wantKey:         "TestDevicePolicySetting",
 | 
						|
			wantScope:       DeviceSetting,
 | 
						|
			wantType:        InvalidValue,
 | 
						|
			wantIsSupported: true,
 | 
						|
			wantString:      `Device("TestDevicePolicySetting", Invalid)`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "Device/Integer",
 | 
						|
			setting:         NewDefinition("TestDevicePolicySetting", DeviceSetting, IntegerValue),
 | 
						|
			wantKey:         "TestDevicePolicySetting",
 | 
						|
			wantScope:       DeviceSetting,
 | 
						|
			wantType:        IntegerValue,
 | 
						|
			wantIsSupported: true,
 | 
						|
			wantString:      `Device("TestDevicePolicySetting", Integer)`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "Profile/String",
 | 
						|
			setting:         NewDefinition("TestProfilePolicySetting", ProfileSetting, StringValue),
 | 
						|
			wantKey:         "TestProfilePolicySetting",
 | 
						|
			wantScope:       ProfileSetting,
 | 
						|
			wantType:        StringValue,
 | 
						|
			wantIsSupported: true,
 | 
						|
			wantString:      `Profile("TestProfilePolicySetting", String)`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "Device/StringList",
 | 
						|
			setting:         NewDefinition("AllowedSuggestedExitNodes", DeviceSetting, StringListValue),
 | 
						|
			wantKey:         "AllowedSuggestedExitNodes",
 | 
						|
			wantScope:       DeviceSetting,
 | 
						|
			wantType:        StringListValue,
 | 
						|
			wantIsSupported: true,
 | 
						|
			wantString:      `Device("AllowedSuggestedExitNodes", StringList)`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "Device/PreferenceOption",
 | 
						|
			setting:         NewDefinition("AdvertiseExitNode", DeviceSetting, PreferenceOptionValue),
 | 
						|
			wantKey:         "AdvertiseExitNode",
 | 
						|
			wantScope:       DeviceSetting,
 | 
						|
			wantType:        PreferenceOptionValue,
 | 
						|
			wantIsSupported: true,
 | 
						|
			wantString:      `Device("AdvertiseExitNode", PreferenceOption)`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "User/Boolean",
 | 
						|
			setting:         NewDefinition("TestUserPolicySetting", UserSetting, BooleanValue),
 | 
						|
			wantKey:         "TestUserPolicySetting",
 | 
						|
			wantScope:       UserSetting,
 | 
						|
			wantType:        BooleanValue,
 | 
						|
			wantIsSupported: true,
 | 
						|
			wantString:      `User("TestUserPolicySetting", Boolean)`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "User/Visibility",
 | 
						|
			setting:         NewDefinition("AdminConsole", UserSetting, VisibilityValue),
 | 
						|
			wantKey:         "AdminConsole",
 | 
						|
			wantScope:       UserSetting,
 | 
						|
			wantType:        VisibilityValue,
 | 
						|
			wantIsSupported: true,
 | 
						|
			wantString:      `User("AdminConsole", Visibility)`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "User/Duration",
 | 
						|
			setting:         NewDefinition("KeyExpirationNotice", UserSetting, DurationValue),
 | 
						|
			wantKey:         "KeyExpirationNotice",
 | 
						|
			wantScope:       UserSetting,
 | 
						|
			wantType:        DurationValue,
 | 
						|
			wantIsSupported: true,
 | 
						|
			wantString:      `User("KeyExpirationNotice", Duration)`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:                   "SupportedSetting",
 | 
						|
			setting:                NewDefinition("DesktopPolicySetting", DeviceSetting, StringValue, "macos", "windows"),
 | 
						|
			osOverride:             "windows",
 | 
						|
			wantKey:                "DesktopPolicySetting",
 | 
						|
			wantScope:              DeviceSetting,
 | 
						|
			wantType:               StringValue,
 | 
						|
			wantIsSupported:        true,
 | 
						|
			wantSupportedPlatforms: PlatformList{"macos", "windows"},
 | 
						|
			wantString:             `Device("DesktopPolicySetting", String)`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:                   "UnsupportedSetting",
 | 
						|
			setting:                NewDefinition("AndroidPolicySetting", DeviceSetting, StringValue, "android"),
 | 
						|
			osOverride:             "macos",
 | 
						|
			wantKey:                "AndroidPolicySetting",
 | 
						|
			wantScope:              DeviceSetting,
 | 
						|
			wantType:               StringValue,
 | 
						|
			wantIsSupported:        false,
 | 
						|
			wantSupportedPlatforms: PlatformList{"android"},
 | 
						|
			wantString:             `Device("AndroidPolicySetting", String)`,
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			if tt.osOverride != "" {
 | 
						|
				internal.OSForTesting.SetForTest(t, tt.osOverride, nil)
 | 
						|
			}
 | 
						|
			if !tt.setting.Equal(tt.setting) {
 | 
						|
				t.Errorf("the setting should be equal to itself")
 | 
						|
			}
 | 
						|
			if tt.setting != nil && !tt.setting.Equal(ptr.To(*tt.setting)) {
 | 
						|
				t.Errorf("the setting should be equal to its shallow copy")
 | 
						|
			}
 | 
						|
			if gotKey := tt.setting.Key(); gotKey != tt.wantKey {
 | 
						|
				t.Errorf("Key: got %q, want %q", gotKey, tt.wantKey)
 | 
						|
			}
 | 
						|
			if gotScope := tt.setting.Scope(); gotScope != tt.wantScope {
 | 
						|
				t.Errorf("Scope: got %v, want %v", gotScope, tt.wantScope)
 | 
						|
			}
 | 
						|
			if gotType := tt.setting.Type(); gotType != tt.wantType {
 | 
						|
				t.Errorf("Type: got %v, want %v", gotType, tt.wantType)
 | 
						|
			}
 | 
						|
			if gotIsSupported := tt.setting.IsSupported(); gotIsSupported != tt.wantIsSupported {
 | 
						|
				t.Errorf("IsSupported: got %v, want %v", gotIsSupported, tt.wantIsSupported)
 | 
						|
			}
 | 
						|
			if gotSupportedPlatforms := tt.setting.SupportedPlatforms(); !slices.Equal(gotSupportedPlatforms, tt.wantSupportedPlatforms) {
 | 
						|
				t.Errorf("SupportedPlatforms: got %v, want %v", gotSupportedPlatforms, tt.wantSupportedPlatforms)
 | 
						|
			}
 | 
						|
			if gotString := tt.setting.String(); gotString != tt.wantString {
 | 
						|
				t.Errorf("String: got %v, want %v", gotString, tt.wantString)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestRegisterSettingDefinition(t *testing.T) {
 | 
						|
	const testPolicySettingKey pkey.Key = "TestPolicySetting"
 | 
						|
	tests := []struct {
 | 
						|
		name    string
 | 
						|
		key     pkey.Key
 | 
						|
		wantEq  *Definition
 | 
						|
		wantErr error
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:   "GetRegistered",
 | 
						|
			key:    "TestPolicySetting",
 | 
						|
			wantEq: NewDefinition(testPolicySettingKey, DeviceSetting, StringValue),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:    "GetNonRegistered",
 | 
						|
			key:     "OtherPolicySetting",
 | 
						|
			wantEq:  nil,
 | 
						|
			wantErr: ErrNoSuchKey,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	resetSettingDefinitions(t)
 | 
						|
	Register(testPolicySettingKey, DeviceSetting, StringValue)
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			got, gotErr := DefinitionOf(tt.key)
 | 
						|
			if gotErr != tt.wantErr {
 | 
						|
				t.Errorf("gotErr %v, wantErr %v", gotErr, tt.wantErr)
 | 
						|
			}
 | 
						|
			if !got.Equal(tt.wantEq) {
 | 
						|
				t.Errorf("got %v, want %v", got, tt.wantEq)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestRegisterAfterUsePanics(t *testing.T) {
 | 
						|
	resetSettingDefinitions(t)
 | 
						|
 | 
						|
	Register("TestPolicySetting", DeviceSetting, StringValue)
 | 
						|
	DefinitionOf("TestPolicySetting")
 | 
						|
 | 
						|
	func() {
 | 
						|
		defer func() {
 | 
						|
			if gotPanic, wantPanic := recover(), "policy definitions are already in use"; gotPanic != wantPanic {
 | 
						|
				t.Errorf("gotPanic: %q, wantPanic: %q", gotPanic, wantPanic)
 | 
						|
			}
 | 
						|
		}()
 | 
						|
 | 
						|
		Register("TestPolicySetting", DeviceSetting, StringValue)
 | 
						|
	}()
 | 
						|
}
 | 
						|
 | 
						|
func TestRegisterDuplicateSettings(t *testing.T) {
 | 
						|
 | 
						|
	tests := []struct {
 | 
						|
		name       string
 | 
						|
		settings   []*Definition
 | 
						|
		wantEq     *Definition
 | 
						|
		wantErrStr string
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "NoConflict/Exact",
 | 
						|
			settings: []*Definition{
 | 
						|
				NewDefinition("TestPolicySetting", DeviceSetting, StringValue),
 | 
						|
				NewDefinition("TestPolicySetting", DeviceSetting, StringValue),
 | 
						|
			},
 | 
						|
			wantEq: NewDefinition("TestPolicySetting", DeviceSetting, StringValue),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "NoConflict/MergeOS-First",
 | 
						|
			settings: []*Definition{
 | 
						|
				NewDefinition("TestPolicySetting", DeviceSetting, StringValue, "android", "macos"),
 | 
						|
				NewDefinition("TestPolicySetting", DeviceSetting, StringValue), // all platforms
 | 
						|
			},
 | 
						|
			wantEq: NewDefinition("TestPolicySetting", DeviceSetting, StringValue), // all platforms
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "NoConflict/MergeOS-Second",
 | 
						|
			settings: []*Definition{
 | 
						|
				NewDefinition("TestPolicySetting", DeviceSetting, StringValue), // all platforms
 | 
						|
				NewDefinition("TestPolicySetting", DeviceSetting, StringValue, "android", "macos"),
 | 
						|
			},
 | 
						|
			wantEq: NewDefinition("TestPolicySetting", DeviceSetting, StringValue), // all platforms
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "NoConflict/MergeOS-Both",
 | 
						|
			settings: []*Definition{
 | 
						|
				NewDefinition("TestPolicySetting", DeviceSetting, StringValue, "macos"),
 | 
						|
				NewDefinition("TestPolicySetting", DeviceSetting, StringValue, "windows"),
 | 
						|
			},
 | 
						|
			wantEq: NewDefinition("TestPolicySetting", DeviceSetting, StringValue, "macos", "windows"),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "Conflict/Scope",
 | 
						|
			settings: []*Definition{
 | 
						|
				NewDefinition("TestPolicySetting", DeviceSetting, StringValue),
 | 
						|
				NewDefinition("TestPolicySetting", UserSetting, StringValue),
 | 
						|
			},
 | 
						|
			wantEq:     nil,
 | 
						|
			wantErrStr: `duplicate policy definition: "TestPolicySetting"`,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "Conflict/Type",
 | 
						|
			settings: []*Definition{
 | 
						|
				NewDefinition("TestPolicySetting", UserSetting, StringValue),
 | 
						|
				NewDefinition("TestPolicySetting", UserSetting, IntegerValue),
 | 
						|
			},
 | 
						|
			wantEq:     nil,
 | 
						|
			wantErrStr: `duplicate policy definition: "TestPolicySetting"`,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			resetSettingDefinitions(t)
 | 
						|
			for _, s := range tt.settings {
 | 
						|
				Register(s.Key(), s.Scope(), s.Type(), s.SupportedPlatforms()...)
 | 
						|
			}
 | 
						|
			got, err := DefinitionOf("TestPolicySetting")
 | 
						|
			var gotErrStr string
 | 
						|
			if err != nil {
 | 
						|
				gotErrStr = err.Error()
 | 
						|
			}
 | 
						|
			if gotErrStr != tt.wantErrStr {
 | 
						|
				t.Fatalf("ErrStr: got %q, want %q", gotErrStr, tt.wantErrStr)
 | 
						|
			}
 | 
						|
			if !got.Equal(tt.wantEq) {
 | 
						|
				t.Errorf("Definition got %v, want %v", got, tt.wantEq)
 | 
						|
			}
 | 
						|
			if !slices.Equal(got.SupportedPlatforms(), tt.wantEq.SupportedPlatforms()) {
 | 
						|
				t.Errorf("SupportedPlatforms got %v, want %v", got.SupportedPlatforms(), tt.wantEq.SupportedPlatforms())
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestListSettingDefinitions(t *testing.T) {
 | 
						|
	definitions := []*Definition{
 | 
						|
		NewDefinition("TestDevicePolicySetting", DeviceSetting, IntegerValue),
 | 
						|
		NewDefinition("TestProfilePolicySetting", ProfileSetting, StringValue),
 | 
						|
		NewDefinition("TestUserPolicySetting", UserSetting, BooleanValue),
 | 
						|
		NewDefinition("TestStringListPolicySetting", DeviceSetting, StringListValue),
 | 
						|
	}
 | 
						|
	if err := SetDefinitionsForTest(t, definitions...); err != nil {
 | 
						|
		t.Fatalf("SetDefinitionsForTest failed: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	cmp := func(l, r *Definition) int {
 | 
						|
		return strings.Compare(string(l.Key()), string(r.Key()))
 | 
						|
	}
 | 
						|
	want := append([]*Definition{}, definitions...)
 | 
						|
	slices.SortFunc(want, cmp)
 | 
						|
 | 
						|
	got, err := Definitions()
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("Definitions failed: %v", err)
 | 
						|
	}
 | 
						|
	slices.SortFunc(got, cmp)
 | 
						|
 | 
						|
	if !slices.Equal(got, want) {
 | 
						|
		t.Errorf("got %v, want %v", got, want)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func resetSettingDefinitions(t *testing.T) {
 | 
						|
	t.Cleanup(func() {
 | 
						|
		definitionsMu.Lock()
 | 
						|
		definitionsList = nil
 | 
						|
		definitions = lazy.SyncValue[DefinitionMap]{}
 | 
						|
		definitionsUsed = false
 | 
						|
		definitionsMu.Unlock()
 | 
						|
	})
 | 
						|
 | 
						|
	definitionsMu.Lock()
 | 
						|
	definitionsList = nil
 | 
						|
	definitions = lazy.SyncValue[DefinitionMap]{}
 | 
						|
	definitionsUsed = false
 | 
						|
	definitionsMu.Unlock()
 | 
						|
}
 |