mirror of
https://github.com/siderolabs/omni.git
synced 2026-05-04 22:26:13 +02:00
Bump copyright for conformance to 2026 Signed-off-by: Edward Sammut Alessi <edward.sammutalessi@siderolabs.com>
142 lines
4.1 KiB
Go
142 lines
4.1 KiB
Go
// Copyright (c) 2026 Sidero Labs, Inc.
|
|
//
|
|
// Use of this software is governed by the Business Source License
|
|
// included in the LICENSE file.
|
|
|
|
package scope_test
|
|
|
|
import (
|
|
"slices"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/siderolabs/omni/internal/pkg/auth/scope"
|
|
)
|
|
|
|
func TestScopeCheck(t *testing.T) {
|
|
for _, tt := range []struct { //nolint:govet
|
|
name string
|
|
actorScopes []scope.Scope
|
|
requiredScopes []scope.Scope
|
|
expectedError string
|
|
}{
|
|
{
|
|
name: "empty",
|
|
},
|
|
{
|
|
name: "actor okay",
|
|
actorScopes: []scope.Scope{
|
|
scope.ClusterAny,
|
|
scope.UserAny,
|
|
scope.MachineAny,
|
|
},
|
|
requiredScopes: []scope.Scope{
|
|
scope.New(scope.ObjectCluster, scope.ActionRead, scope.PerspectiveNone),
|
|
scope.New(scope.ObjectUser, scope.ActionDestroy, scope.PerspectiveNone),
|
|
},
|
|
},
|
|
{
|
|
name: "missing scope",
|
|
actorScopes: []scope.Scope{
|
|
scope.UserAny,
|
|
scope.MachineAny,
|
|
},
|
|
requiredScopes: []scope.Scope{
|
|
scope.New(scope.ObjectCluster, scope.ActionRead, scope.PerspectiveNone),
|
|
scope.New(scope.ObjectUser, scope.ActionDestroy, scope.PerspectiveNone),
|
|
},
|
|
expectedError: "missing required scope: cluster:read",
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
actorScopes := scope.NewScopes(tt.actorScopes...)
|
|
|
|
err := actorScopes.Check(tt.requiredScopes...)
|
|
if tt.expectedError != "" {
|
|
require.Error(t, err)
|
|
assert.EqualError(t, err, tt.expectedError)
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseScopes(t *testing.T) {
|
|
scopes := scope.NewScopes(scope.ClusterAny, scope.MachineAny)
|
|
|
|
assert.Equal(t, []string{"cluster:*", "machine:*"}, scopes.Strings())
|
|
|
|
parsedScopes, err := scope.ParseScopes(scopes.Strings())
|
|
require.NoError(t, err)
|
|
assert.Equal(t, scopes, parsedScopes)
|
|
}
|
|
|
|
func TestIntersection(t *testing.T) {
|
|
scopeUserRead := scope.New(scope.ObjectUser, scope.ActionRead, scope.PerspectiveNone)
|
|
scopeClusterRead := scope.New(scope.ObjectCluster, scope.ActionRead, scope.PerspectiveNone)
|
|
scopeClusterCreate := scope.New(scope.ObjectCluster, scope.ActionCreate, scope.PerspectiveNone)
|
|
scopeClusterUpgrade := scope.New(scope.ObjectCluster, scope.ActionModify, scope.PerspectiveKubernetesUpgrade)
|
|
scopeMachineDestroy := scope.New(scope.ObjectMachine, scope.ActionDestroy, scope.PerspectiveNone)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
scopes1 scope.Scopes
|
|
scopes2 scope.Scopes
|
|
expected scope.Scopes
|
|
}{
|
|
{
|
|
name: "with-any",
|
|
scopes1: scope.NewScopes(scope.ClusterAny, scope.MachineAny),
|
|
scopes2: scope.NewScopes(scope.ClusterAny, scope.MachineAny, scope.UserAny),
|
|
expected: scope.NewScopes(scope.ClusterAny, scope.MachineAny),
|
|
},
|
|
{
|
|
name: "with-empty",
|
|
scopes1: scope.NewScopes(scopeUserRead, scope.MachineAny),
|
|
scopes2: scope.NewScopes(),
|
|
expected: scope.NewScopes(),
|
|
},
|
|
{
|
|
name: "mixed-1",
|
|
scopes1: scope.NewScopes(scopeClusterCreate, scope.MachineAny),
|
|
scopes2: scope.NewScopes(scope.ClusterAny, scope.MachineAny),
|
|
expected: scope.NewScopes(scopeClusterCreate, scope.MachineAny),
|
|
},
|
|
{
|
|
name: "mixed-2",
|
|
scopes1: scope.NewScopes(scope.UserDefaultScopes...),
|
|
scopes2: scope.NewScopes(scopeClusterRead),
|
|
expected: scope.NewScopes(scopeClusterRead),
|
|
},
|
|
{
|
|
name: "mixed-inverted",
|
|
scopes2: scope.NewScopes(scope.ClusterAny, scope.MachineAny),
|
|
scopes1: scope.NewScopes(scopeClusterCreate, scope.MachineAny),
|
|
expected: scope.NewScopes(scopeClusterCreate, scope.MachineAny),
|
|
},
|
|
{
|
|
name: "complex",
|
|
scopes1: scope.NewScopes(scopeUserRead, scopeMachineDestroy, scopeClusterUpgrade),
|
|
scopes2: scope.NewScopes(scope.ClusterAny, scope.MachineAny),
|
|
expected: scope.NewScopes(scopeMachineDestroy, scopeClusterUpgrade),
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
intersection := tc.scopes1.Intersect(tc.scopes2)
|
|
|
|
expectedStrs := tc.expected.Strings()
|
|
actualStrs := intersection.Strings()
|
|
|
|
slices.Sort(expectedStrs)
|
|
slices.Sort(actualStrs)
|
|
|
|
assert.Equal(t, expectedStrs, actualStrs)
|
|
})
|
|
}
|
|
}
|