-
Notifications
You must be signed in to change notification settings - Fork 4
/
testall.go
97 lines (91 loc) · 3.09 KB
/
testall.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package iamcel
import (
"context"
"reflect"
"github.com/google/cel-go/checker/decls"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/interpreter/functions"
"go.einride.tech/iam/iampermission"
iamv1 "go.einride.tech/iam/proto/gen/einride/iam/v1"
expr "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// TestAllFunction is the name of the function for testing that all resources have a specified permission.
const TestAllFunction = "test_all"
const testAllFunctionOverload = "test_all_caller_strings_bool"
// NewTestAllFunctionDeclaration creates a new declaration for the test_all function.
func NewTestAllFunctionDeclaration() *expr.Decl {
return decls.NewFunction(
TestAllFunction,
decls.NewOverload(
testAllFunctionOverload,
[]*expr.Type{
decls.NewObjectType(string((&iamv1.Caller{}).ProtoReflect().Descriptor().FullName())),
decls.NewListType(decls.String),
},
decls.Bool,
),
)
}
// NewTestAllFunctionImplementation creates a new implementation for the test_all function.
func NewTestAllFunctionImplementation(
options *iamv1.MethodAuthorizationOptions,
tester PermissionTester,
) *functions.Overload {
return &functions.Overload{
Operator: testAllFunctionOverload,
Binary: func(callerVal, resourcesVal ref.Val) ref.Val {
caller, ok := callerVal.Value().(*iamv1.Caller)
if !ok {
return types.NewErr(
"test_all: unexpected type of arg 1, expected %T but got %T",
&iamv1.Caller{},
callerVal.Value(),
)
}
convertedResources, err := resourcesVal.ConvertToNative(reflect.TypeOf([]string(nil)))
if err != nil {
return types.NewErr("test_all: unexpected type of arg 2, expected []string but got %T", resourcesVal)
}
resources, ok := convertedResources.([]string)
if !ok {
return types.NewErr("test_all: unexpected type of arg 2, expected []string but got %T", resourcesVal)
}
if len(resources) == 0 {
return types.True
}
resourcePermissions := make(map[string]string, len(resources))
for _, resource := range resources {
permission, ok := iampermission.ResolveMethodPermission(options, resource)
if !ok {
return types.NewErr(
"%s: no permission configured for resource '%s'", codes.InvalidArgument, resource,
)
}
resourcePermissions[resource] = permission
}
// TODO: When cel-go supports async functions, use the caller context here.
ctx := context.Background()
if caller.GetContext().GetDeadline() != nil {
var cancel context.CancelFunc
ctx, cancel = context.WithDeadline(ctx, caller.GetContext().GetDeadline().AsTime())
defer cancel()
}
result, err := tester.TestPermissions(ctx, caller, resourcePermissions)
if err != nil {
if s, ok := status.FromError(err); ok {
return types.NewErr("%s: %s", s.Code(), s.Message())
}
return types.NewErr("test: error testing permission: %v", err)
}
for _, resource := range resources {
if !result[resource] {
return types.False
}
}
return types.True
},
}
}