util/syspolicy, ipn/ipnlocal: update syspolicy package to utilize syspolicy/rsop

In this PR, we update the syspolicy package to utilize syspolicy/rsop under the hood,
and remove syspolicy.CachingHandler, syspolicy.windowsHandler and related code
which is no longer used.

We mark the syspolicy.Handler interface and RegisterHandler/SetHandlerForTest functions
as deprecated, but keep them temporarily until they are no longer used in other repos.

We also update the package to register setting definitions for all existing policy settings
and to register the Registry-based, Windows-specific policy stores when running on Windows.

Finally, we update existing internal and external tests to use the new API and add a few more
tests and benchmarks.

Updates #12687

Signed-off-by: Nick Khyl <nickk@tailscale.com>
This commit is contained in:
Nick Khyl
2024-10-08 10:50:14 -05:00
committed by Nick Khyl
parent 7fe6e50858
commit e815ae0ec4
16 changed files with 832 additions and 935 deletions
+95
View File
@@ -0,0 +1,95 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package syspolicy
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"go/types"
"os"
"reflect"
"strconv"
"testing"
"tailscale.com/util/syspolicy/setting"
)
func TestKnownKeysRegistered(t *testing.T) {
keyConsts, err := listStringConsts[Key]("policy_keys.go")
if err != nil {
t.Fatalf("listStringConsts failed: %v", err)
}
m, err := setting.DefinitionMapOf(implicitDefinitions)
if err != nil {
t.Fatalf("definitionMapOf failed: %v", err)
}
for _, key := range keyConsts {
t.Run(string(key), func(t *testing.T) {
d := m[key]
if d == nil {
t.Fatalf("%q was not registered", key)
}
if d.Key() != key {
t.Fatalf("d.Key got: %s, want %s", d.Key(), key)
}
})
}
}
func TestNotAWellKnownSetting(t *testing.T) {
d, err := WellKnownSettingDefinition("TestSettingDoesNotExist")
if d != nil || err == nil {
t.Fatalf("got %v, %v; want nil, %v", d, err, ErrNoSuchKey)
}
}
func listStringConsts[T ~string](filename string) (map[string]T, error) {
fset := token.NewFileSet()
src, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
f, err := parser.ParseFile(fset, filename, src, 0)
if err != nil {
return nil, err
}
consts := make(map[string]T)
typeName := reflect.TypeFor[T]().Name()
for _, d := range f.Decls {
g, ok := d.(*ast.GenDecl)
if !ok || g.Tok != token.CONST {
continue
}
for _, s := range g.Specs {
vs, ok := s.(*ast.ValueSpec)
if !ok || len(vs.Names) != len(vs.Values) {
continue
}
if typ, ok := vs.Type.(*ast.Ident); !ok || typ.Name != typeName {
continue
}
for i, n := range vs.Names {
lit, ok := vs.Values[i].(*ast.BasicLit)
if !ok {
return nil, fmt.Errorf("unexpected string literal: %v = %v", n.Name, types.ExprString(vs.Values[i]))
}
val, err := strconv.Unquote(lit.Value)
if err != nil {
return nil, fmt.Errorf("unexpected string literal: %v = %v", n.Name, lit.Value)
}
consts[n.Name] = T(val)
}
}
}
return consts, nil
}