Brad Fitzpatrick 1ca4ae598a ipn/ipnlocal: use policyclient.Client always, stop using global syspolicy funcs
Step 4 of N. See earlier commits in the series (via the issue) for the
plan.

This adds the missing methods to policyclient.Client and then uses it
everywhere in ipn/ipnlocal and locks it in with a new dep test.

Still plenty of users of the global syspolicy elsewhere in the tree,
but this is a lot of them.

Updates #16998
Updates #12614

Change-Id: I25b136539ae1eedbcba80124de842970db0ca314
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2025-09-02 10:28:35 -07:00

121 lines
4.7 KiB
Go

// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// Package policyclient contains the minimal syspolicy interface as needed by
// client code using syspolicy. It's the part that's always linked in, even if the rest
// of syspolicy is omitted from the build.
package policyclient
import (
"time"
"tailscale.com/util/syspolicy/pkey"
"tailscale.com/util/syspolicy/ptype"
)
// Client is the interface between code making questions about the system policy
// and the actual implementation.
type Client interface {
// GetString returns a string policy setting with the specified key,
// or defaultValue (and a nil error) if it does not exist.
GetString(key pkey.Key, defaultValue string) (string, error)
// GetStringArray returns a string array policy setting with the specified key,
// or defaultValue (and a nil error) if it does not exist.
GetStringArray(key pkey.Key, defaultValue []string) ([]string, error)
// GetBoolean returns a boolean policy setting with the specified key,
// or defaultValue (and a nil error) if it does not exist.
GetBoolean(key pkey.Key, defaultValue bool) (bool, error)
// GetUint64 returns a numeric policy setting with the specified key,
// or defaultValue (and a nil error) if it does not exist.
GetUint64(key pkey.Key, defaultValue uint64) (uint64, error)
// GetDuration loads a policy from the registry that can be managed by an
// enterprise policy management system and describes a duration for some
// action. The registry value should be a string that time.ParseDuration
// understands. If the registry value is "" or can not be processed,
// defaultValue (and a nil error) is returned instead.
GetDuration(key pkey.Key, defaultValue time.Duration) (time.Duration, error)
// GetPreferenceOption loads a policy from the registry that can be
// managed by an enterprise policy management system and allows administrative
// overrides of users' choices in a way that we do not want tailcontrol to have
// the authority to set. It describes user-decides/always/never options, where
// "always" and "never" remove the user's ability to make a selection. If not
// present or set to a different value, "user-decides" is the default.
GetPreferenceOption(key pkey.Key) (ptype.PreferenceOption, error)
// GetVisibility returns whether a UI element should be visible based on
// the system's configuration.
// If unconfigured, implementations should return [ptype.VisibleByPolicy]
// and a nil error.
GetVisibility(key pkey.Key) (ptype.Visibility, error)
// SetDebugLoggingEnabled enables or disables debug logging for the policy client.
SetDebugLoggingEnabled(enabled bool)
// HasAnyOf returns whether at least one of the specified policy settings is
// configured, or an error if no keys are provided or the check fails.
HasAnyOf(keys ...pkey.Key) (bool, error)
// RegisterChangeCallback registers a callback function that will be called
// whenever a policy change is detected. It returns a function to unregister
// the callback and an error if the registration fails.
RegisterChangeCallback(cb func(PolicyChange)) (unregister func(), err error)
}
// PolicyChange is the interface representing a change in policy settings.
type PolicyChange interface {
// HasChanged reports whether the policy setting identified by the given key
// has changed.
HasChanged(pkey.Key) bool
// HasChangedAnyOf reports whether any of the provided policy settings
// changed in this change.
HasChangedAnyOf(keys ...pkey.Key) bool
}
// NoPolicyClient is a no-op implementation of [Client] that only
// returns default values.
type NoPolicyClient struct{}
func (NoPolicyClient) GetBoolean(key pkey.Key, defaultValue bool) (bool, error) {
return defaultValue, nil
}
func (NoPolicyClient) GetString(key pkey.Key, defaultValue string) (string, error) {
return defaultValue, nil
}
func (NoPolicyClient) GetStringArray(key pkey.Key, defaultValue []string) ([]string, error) {
return defaultValue, nil
}
func (NoPolicyClient) GetUint64(key pkey.Key, defaultValue uint64) (uint64, error) {
return defaultValue, nil
}
func (NoPolicyClient) GetDuration(name pkey.Key, defaultValue time.Duration) (time.Duration, error) {
return defaultValue, nil
}
func (NoPolicyClient) GetPreferenceOption(name pkey.Key) (ptype.PreferenceOption, error) {
return ptype.ShowChoiceByPolicy, nil
}
func (NoPolicyClient) GetVisibility(name pkey.Key) (ptype.Visibility, error) {
return ptype.VisibleByPolicy, nil
}
func (NoPolicyClient) HasAnyOf(keys ...pkey.Key) (bool, error) {
return false, nil
}
func (NoPolicyClient) SetDebugLoggingEnabled(enabled bool) {}
func (NoPolicyClient) RegisterChangeCallback(cb func(PolicyChange)) (unregister func(), err error) {
return func() {}, nil
}