@ -632,7 +632,7 @@ func TestConfigureExitNode(t *testing.T) {
exitNodeIDPolicy * tailcfg . StableNodeID
exitNodeIDPolicy * tailcfg . StableNodeID
exitNodeIPPolicy * netip . Addr
exitNodeIPPolicy * netip . Addr
exitNodeAllowedIDs [ ] tailcfg . StableNodeID // nil if all IDs are allowed for auto exit nodes
exitNodeAllowedIDs [ ] tailcfg . StableNodeID // nil if all IDs are allowed for auto exit nodes
exitNodeAllowOverride bool // whether [ syspolic y.AllowExitNodeOverride] should be set to true
exitNodeAllowOverride bool // whether [ pke y.AllowExitNodeOverride] should be set to true
wantChangePrefsErr error // if non-nil, the error we expect from [LocalBackend.EditPrefsAs]
wantChangePrefsErr error // if non-nil, the error we expect from [LocalBackend.EditPrefsAs]
wantPrefs ipn . Prefs
wantPrefs ipn . Prefs
wantExitNodeToggleErr error // if non-nil, the error we expect from [LocalBackend.SetUseExitNodeEnabled]
wantExitNodeToggleErr error // if non-nil, the error we expect from [LocalBackend.SetUseExitNodeEnabled]
@ -970,7 +970,7 @@ func TestConfigureExitNode(t *testing.T) {
name : "auto-any-via-policy/no-netmap/with-disallowed-existing" , // same, but now with a syspolicy setting that does not allow the existing exit node ID
name : "auto-any-via-policy/no-netmap/with-disallowed-existing" , // same, but now with a syspolicy setting that does not allow the existing exit node ID
prefs : ipn . Prefs {
prefs : ipn . Prefs {
ControlURL : controlURL ,
ControlURL : controlURL ,
ExitNodeID : exitNode2 . StableID ( ) , // not allowed by [ syspolic y.AllowedSuggestedExitNodes]
ExitNodeID : exitNode2 . StableID ( ) , // not allowed by [ pke y.AllowedSuggestedExitNodes]
} ,
} ,
netMap : nil ,
netMap : nil ,
report : report ,
report : report ,
@ -989,7 +989,7 @@ func TestConfigureExitNode(t *testing.T) {
name : "auto-any-via-policy/with-netmap/with-allowed-existing" , // same, but now with a syspolicy setting that does not allow the existing exit node ID
name : "auto-any-via-policy/with-netmap/with-allowed-existing" , // same, but now with a syspolicy setting that does not allow the existing exit node ID
prefs : ipn . Prefs {
prefs : ipn . Prefs {
ControlURL : controlURL ,
ControlURL : controlURL ,
ExitNodeID : exitNode1 . StableID ( ) , // not allowed by [ syspolic y.AllowedSuggestedExitNodes]
ExitNodeID : exitNode1 . StableID ( ) , // not allowed by [ pke y.AllowedSuggestedExitNodes]
} ,
} ,
netMap : clientNetmap ,
netMap : clientNetmap ,
report : report ,
report : report ,
@ -1072,7 +1072,7 @@ func TestConfigureExitNode(t *testing.T) {
wantHostinfoExitNodeID : exitNode1 . StableID ( ) ,
wantHostinfoExitNodeID : exitNode1 . StableID ( ) ,
} ,
} ,
{
{
name : "auto-any-via-policy/allow-override/change" , // changing the exit node is allowed by [ syspolic y.AllowExitNodeOverride]
name : "auto-any-via-policy/allow-override/change" , // changing the exit node is allowed by [ pke y.AllowExitNodeOverride]
prefs : ipn . Prefs {
prefs : ipn . Prefs {
ControlURL : controlURL ,
ControlURL : controlURL ,
} ,
} ,
@ -1094,7 +1094,7 @@ func TestConfigureExitNode(t *testing.T) {
wantHostinfoExitNodeID : exitNode2 . StableID ( ) ,
wantHostinfoExitNodeID : exitNode2 . StableID ( ) ,
} ,
} ,
{
{
name : "auto-any-via-policy/allow-override/clear" , // clearing the exit node ID is not allowed by [ syspolic y.AllowExitNodeOverride]
name : "auto-any-via-policy/allow-override/clear" , // clearing the exit node ID is not allowed by [ pke y.AllowExitNodeOverride]
prefs : ipn . Prefs {
prefs : ipn . Prefs {
ControlURL : controlURL ,
ControlURL : controlURL ,
} ,
} ,
@ -1118,7 +1118,7 @@ func TestConfigureExitNode(t *testing.T) {
wantHostinfoExitNodeID : exitNode1 . StableID ( ) ,
wantHostinfoExitNodeID : exitNode1 . StableID ( ) ,
} ,
} ,
{
{
name : "auto-any-via-policy/allow-override/toggle-off" , // similarly, toggling off the exit node is not allowed even with [ syspolic y.AllowExitNodeOverride]
name : "auto-any-via-policy/allow-override/toggle-off" , // similarly, toggling off the exit node is not allowed even with [ pke y.AllowExitNodeOverride]
prefs : ipn . Prefs {
prefs : ipn . Prefs {
ControlURL : controlURL ,
ControlURL : controlURL ,
} ,
} ,
@ -1179,36 +1179,32 @@ func TestConfigureExitNode(t *testing.T) {
wantHostinfoExitNodeID : exitNode1 . StableID ( ) ,
wantHostinfoExitNodeID : exitNode1 . StableID ( ) ,
} ,
} ,
}
}
syspolicy . RegisterWellKnownSettingsForTest ( t )
for _ , tt := range tests {
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
t . Run ( tt . name , func ( t * testing . T ) {
t . Parallel ( )
var pol testPolicy
// Configure policy settings, if any.
// Configure policy settings, if any.
store := source . NewTestStore ( t )
if tt . exitNodeIDPolicy != nil {
if tt . exitNodeIDPolicy != nil {
store. SetStrings ( source . TestSettingOf ( pkey . ExitNodeID , string ( * tt . exitNodeIDPolicy ) ) )
pol. Set ( pkey . ExitNodeID , string ( * tt . exitNodeIDPolicy ) )
}
}
if tt . exitNodeIPPolicy != nil {
if tt . exitNodeIPPolicy != nil {
store. SetStrings ( source . TestSettingOf ( pkey . ExitNodeIP , tt . exitNodeIPPolicy . String ( ) ) )
pol. Set ( pkey . ExitNodeIP , tt . exitNodeIPPolicy . String ( ) )
}
}
if tt . exitNodeAllowedIDs != nil {
if tt . exitNodeAllowedIDs != nil {
store. SetStringLists ( source . TestSettingOf ( pkey . AllowedSuggestedExitNodes , toStrings ( tt . exitNodeAllowedIDs ) ) )
pol. Set ( pkey . AllowedSuggestedExitNodes , toStrings ( tt . exitNodeAllowedIDs ) )
}
}
if tt . exitNodeAllowOverride {
if tt . exitNodeAllowOverride {
store . SetBooleans ( source . TestSettingOf ( pkey . AllowExitNodeOverride , true ) )
pol . Set ( pkey . AllowExitNodeOverride , true )
}
if store . IsEmpty ( ) {
// No syspolicy settings, so don't register a store.
// This allows the test to run in parallel with other tests.
t . Parallel ( )
} else {
// Register the store for syspolicy settings to make them available to the LocalBackend.
syspolicy . MustRegisterStoreForTest ( t , "TestStore" , setting . DeviceScope , store )
}
}
// Create a new LocalBackend with the given prefs.
// Create a new LocalBackend with the given prefs.
// Any syspolicy settings will be applied to the initial prefs.
// Any syspolicy settings will be applied to the initial prefs.
lb := newTestLocalBackend ( t )
sys := tsd . NewSystem ( )
sys . PolicyClient . Set ( pol )
lb := newTestLocalBackendWithSys ( t , sys )
lb . SetPrefsForTest ( tt . prefs . Clone ( ) )
lb . SetPrefsForTest ( tt . prefs . Clone ( ) )
// Then set the netcheck report and netmap, if any.
// Then set the netcheck report and netmap, if any.
if tt . report != nil {
if tt . report != nil {
lb . MagicConn ( ) . SetLastNetcheckReportForTest ( t . Context ( ) , tt . report )
lb . MagicConn ( ) . SetLastNetcheckReportForTest ( t . Context ( ) , tt . report )
@ -5543,28 +5539,62 @@ func TestReadWriteRouteInfo(t *testing.T) {
}
}
}
}
// staticPolicy maps policy keys to their corresponding values,
// testPolicy is a [policyclient.Client] with a static mapping of values.
// which must be of the correct type (string, []string, bool, etc).
// The map value must be of the correct type (string, []string, bool, etc).
//
//
// It is used for testing purposes to simulate policy client behavior.
// It is used for testing purposes to simulate policy client behavior.
// It panics if the values are the wrong type.
// It panics if the values are the wrong type.
type staticPolicy map [ pkey . Key ] any
type testPolicy struct {
type testPolicy struct {
staticPolicy
v map [ pkey . Key ] any
policyclient . Client
policyclient . NoPolicyClient
}
func ( sp * testPolicy ) Set ( key pkey . Key , value any ) {
if sp . v == nil {
sp . v = make ( map [ pkey . Key ] any )
}
sp . v [ key ] = value
}
}
func ( sp testPolicy ) GetStringArray ( key pkey . Key , defaultVal [ ] string ) ( [ ] string , error ) {
func ( sp testPolicy ) GetStringArray ( key pkey . Key , defaultVal [ ] string ) ( [ ] string , error ) {
if val , ok := sp . staticPolicy [ key ] ; ok {
if val , ok := sp . v [ key ] ; ok {
if arr , ok := val . ( [ ] string ) ; ok {
if arr , ok := val . ( [ ] string ) ; ok {
return arr , nil
return arr , nil
}
}
return nil , fmt . Error f( "key %s is not a []string" , key )
panic ( fmt . Sprint f( "key %s is not a []string" , key ) )
}
}
return defaultVal , nil
return defaultVal , nil
}
}
func ( sp testPolicy ) GetString ( key pkey . Key , defaultVal string ) ( string , error ) {
if val , ok := sp . v [ key ] ; ok {
if str , ok := val . ( string ) ; ok {
return str , nil
}
panic ( fmt . Sprintf ( "key %s is not a string" , key ) )
}
return defaultVal , nil
}
func ( sp testPolicy ) GetBoolean ( key pkey . Key , defaultVal bool ) ( bool , error ) {
if val , ok := sp . v [ key ] ; ok {
if b , ok := val . ( bool ) ; ok {
return b , nil
}
panic ( fmt . Sprintf ( "key %s is not a bool" , key ) )
}
return defaultVal , nil
}
func ( sp testPolicy ) HasAnyOf ( keys ... pkey . Key ) ( bool , error ) {
for _ , key := range keys {
if _ , ok := sp . v [ key ] ; ok {
return true , nil
}
}
return false , nil
}
func TestFillAllowedSuggestions ( t * testing . T ) {
func TestFillAllowedSuggestions ( t * testing . T ) {
tests := [ ] struct {
tests := [ ] struct {
name string
name string
@ -5598,13 +5628,10 @@ func TestFillAllowedSuggestions(t *testing.T) {
for _ , tt := range tests {
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
t . Run ( tt . name , func ( t * testing . T ) {
polc := testPolicy {
var pol testPolicy
staticPolicy : staticPolicy {
pol . Set ( pkey . AllowedSuggestedExitNodes , tt . allowPolicy )
pkey . AllowedSuggestedExitNodes : tt . allowPolicy ,
} ,
}
got := fillAllowedSuggestions ( pol c )
got := fillAllowedSuggestions ( pol )
if got == nil {
if got == nil {
if tt . want == nil {
if tt . want == nil {
return
return