-
Notifications
You must be signed in to change notification settings - Fork 245
/
compile.go
134 lines (107 loc) · 3.81 KB
/
compile.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package caveats
import (
"fmt"
"strings"
"github.com/authzed/cel-go/cel"
"github.com/authzed/cel-go/common"
"github.com/authzed/spicedb/pkg/caveats/types"
"github.com/authzed/spicedb/pkg/genutil/mapz"
impl "github.com/authzed/spicedb/pkg/proto/impl/v1"
)
const anonymousCaveat = ""
const maxCaveatExpressionSize = 100_000 // characters
// CompiledCaveat is a compiled form of a caveat.
type CompiledCaveat struct {
// env is the environment under which the CEL program was compiled.
celEnv *cel.Env
// ast is the AST form of the CEL program.
ast *cel.Ast
// name of the caveat
name string
}
// Name represents a user-friendly reference to a caveat
func (cc CompiledCaveat) Name() string {
return cc.name
}
// ExprString returns the string-form of the caveat.
func (cc CompiledCaveat) ExprString() (string, error) {
return cel.AstToString(cc.ast)
}
// Serialize serializes the compiled caveat into a byte string for storage.
func (cc CompiledCaveat) Serialize() ([]byte, error) {
cexpr, err := cel.AstToCheckedExpr(cc.ast)
if err != nil {
return nil, err
}
caveat := &impl.DecodedCaveat{
KindOneof: &impl.DecodedCaveat_Cel{
Cel: cexpr,
},
Name: cc.name,
}
return caveat.MarshalVT()
}
// ReferencedParameters returns the names of the parameters referenced in the expression.
func (cc CompiledCaveat) ReferencedParameters(parameters []string) *mapz.Set[string] {
referencedParams := mapz.NewSet[string]()
definedParameters := mapz.NewSet[string]()
definedParameters.Extend(parameters)
referencedParameters(definedParameters, cc.ast.Expr(), referencedParams)
return referencedParams
}
// CompileCaveatWithName compiles a caveat string into a compiled caveat with a given name,
// or returns the compilation errors.
func CompileCaveatWithName(env *Environment, exprString, name string) (*CompiledCaveat, error) {
c, err := CompileCaveatWithSource(env, name, common.NewStringSource(exprString, name))
if err != nil {
return nil, err
}
c.name = name
return c, nil
}
// CompileCaveatWithSource compiles a caveat source into a compiled caveat, or returns the compilation errors.
func CompileCaveatWithSource(env *Environment, name string, source common.Source) (*CompiledCaveat, error) {
celEnv, err := env.asCelEnvironment()
if err != nil {
return nil, err
}
if len(strings.TrimSpace(source.Content())) > maxCaveatExpressionSize {
return nil, fmt.Errorf("caveat expression provided exceeds maximum allowed size of %d characters", maxCaveatExpressionSize)
}
ast, issues := celEnv.CompileSource(source)
if issues != nil && issues.Err() != nil {
return nil, CompilationErrors{issues.Err(), issues}
}
if ast.OutputType() != cel.BoolType {
return nil, CompilationErrors{fmt.Errorf("caveat expression must result in a boolean value: found `%s`", ast.OutputType().String()), nil}
}
compiled := &CompiledCaveat{celEnv, ast, anonymousCaveat}
compiled.name = name
return compiled, nil
}
// compileCaveat compiles a caveat string into a compiled caveat, or returns the compilation errors.
func compileCaveat(env *Environment, exprString string) (*CompiledCaveat, error) {
s := common.NewStringSource(exprString, "caveat")
return CompileCaveatWithSource(env, "caveat", s)
}
// DeserializeCaveat deserializes a byte-serialized caveat back into a CompiledCaveat.
func DeserializeCaveat(serialized []byte, parameterTypes map[string]types.VariableType) (*CompiledCaveat, error) {
if len(serialized) == 0 {
return nil, fmt.Errorf("given empty serialized")
}
caveat := &impl.DecodedCaveat{}
err := caveat.UnmarshalVT(serialized)
if err != nil {
return nil, err
}
env, err := EnvForVariables(parameterTypes)
if err != nil {
return nil, err
}
celEnv, err := env.asCelEnvironment()
if err != nil {
return nil, err
}
ast := cel.CheckedExprToAst(caveat.GetCel())
return &CompiledCaveat{celEnv, ast, caveat.Name}, nil
}