diff options
-rw-r--r-- | go.mod | 5 | ||||
-rw-r--r-- | go.sum | 8 | ||||
-rw-r--r-- | modules/caddyhttp/celmatcher.go | 146 | ||||
-rw-r--r-- | modules/caddyhttp/fileserver/matcher.go | 105 |
4 files changed, 129 insertions, 135 deletions
@@ -12,7 +12,7 @@ require ( github.com/caddyserver/certmagic v0.20.0 github.com/dustin/go-humanize v1.0.1 github.com/go-chi/chi/v5 v5.0.10 - github.com/google/cel-go v0.15.1 + github.com/google/cel-go v0.20.0 github.com/google/uuid v1.3.1 github.com/klauspost/compress v1.17.0 github.com/klauspost/cpuid/v2 v2.2.5 @@ -49,7 +49,7 @@ require ( require ( cloud.google.com/go/iam v1.1.2 // indirect github.com/Microsoft/go-winio v0.6.0 // indirect - github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fxamacker/cbor/v2 v2.5.0 // indirect github.com/golang/glog v1.1.2 // indirect @@ -70,6 +70,7 @@ require ( go.opentelemetry.io/contrib/propagators/jaeger v1.17.0 // indirect go.opentelemetry.io/contrib/propagators/ot v1.17.0 // indirect go.uber.org/mock v0.3.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect ) @@ -44,8 +44,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -199,8 +199,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.15.1 h1:iTgVZor2x9okXtmTrqO8cg4uvqIeaBcWhXtruaWFMYQ= -github.com/google/cel-go v0.15.1/go.mod h1:YzWEoI07MC/a/wj9in8GeVatqfypkldgBlwXh9bCwqY= +github.com/google/cel-go v0.20.0 h1:h4n6DOCppEMpWERzllyNkntl7JrDyxoE543KWS6BLpc= +github.com/google/cel-go v0.20.0/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/certificate-transparency-go v1.1.8-0.20240110162603-74a5dd331745 h1:heyoXNxkRT155x4jTAiSv5BVSVkueifPUm+Q8LUXMRo= github.com/google/certificate-transparency-go v1.1.8-0.20240110162603-74a5dd331745/go.mod h1:zN0wUQgV9LjwLZeFHnrAbQi8hzMVvEWePyk+MhPOk7k= diff --git a/modules/caddyhttp/celmatcher.go b/modules/caddyhttp/celmatcher.go index 376135364..e1f15e869 100644 --- a/modules/caddyhttp/celmatcher.go +++ b/modules/caddyhttp/celmatcher.go @@ -27,6 +27,7 @@ import ( "github.com/google/cel-go/cel" "github.com/google/cel-go/common" + "github.com/google/cel-go/common/ast" "github.com/google/cel-go/common/operators" "github.com/google/cel-go/common/types" "github.com/google/cel-go/common/types/ref" @@ -36,7 +37,6 @@ import ( "github.com/google/cel-go/interpreter/functions" "github.com/google/cel-go/parser" "go.uber.org/zap" - exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" @@ -66,7 +66,7 @@ type MatchExpression struct { expandedExpr string prg cel.Program - ta ref.TypeAdapter + ta types.Adapter log *zap.Logger } @@ -227,7 +227,7 @@ func (m MatchExpression) caddyPlaceholderFunc(lhs, rhs ref.Val) ref.Val { } // httpRequestCELType is the type representation of a native HTTP request. -var httpRequestCELType = types.NewTypeValue("http.Request", traits.ReceiverType) +var httpRequestCELType = cel.ObjectType("http.Request", traits.ReceiverType) // celHTTPRequest wraps an http.Request with ref.Val interface methods. // @@ -263,7 +263,7 @@ func (cr celHTTPRequest) Equal(other ref.Val) ref.Val { func (celHTTPRequest) Type() ref.Type { return httpRequestCELType } func (cr celHTTPRequest) Value() any { return cr } -var pkixNameCELType = types.NewTypeValue("pkix.Name", traits.ReceiverType) +var pkixNameCELType = cel.ObjectType("pkix.Name", traits.ReceiverType) // celPkixName wraps an pkix.Name with // methods to satisfy the ref.Val interface. @@ -472,25 +472,20 @@ func CELMatcherRuntimeFunction(funcName string, fac CELMatcherFactory) functions // // The arguments are collected into a single list argument the following // function call returned: <funcName>(request, [args]) -func celMatcherStringListMacroExpander(funcName string) parser.MacroExpander { - return func(eh parser.ExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) { - matchArgs := []*exprpb.Expr{} +func celMatcherStringListMacroExpander(funcName string) cel.MacroFactory { + return func(eh cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error) { + matchArgs := []ast.Expr{} if len(args) == 0 { - return nil, &common.Error{ - Message: "matcher requires at least one argument", - } + return nil, eh.NewError(0, "matcher requires at least one argument") } for _, arg := range args { if isCELStringExpr(arg) { matchArgs = append(matchArgs, arg) } else { - return nil, &common.Error{ - Location: eh.OffsetLocation(arg.GetId()), - Message: "matcher arguments must be string constants", - } + return nil, eh.NewError(arg.ID(), "matcher arguments must be string constants") } } - return eh.GlobalCall(funcName, eh.Ident("request"), eh.NewList(matchArgs...)), nil + return eh.NewCall(funcName, eh.NewIdent("request"), eh.NewList(matchArgs...)), nil } } @@ -499,19 +494,14 @@ func celMatcherStringListMacroExpander(funcName string) parser.MacroExpander { // // The following function call is returned: <funcName>(request, arg) func celMatcherStringMacroExpander(funcName string) parser.MacroExpander { - return func(eh parser.ExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) { + return func(eh cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error) { if len(args) != 1 { - return nil, &common.Error{ - Message: "matcher requires one argument", - } + return nil, eh.NewError(0, "matcher requires one argument") } if isCELStringExpr(args[0]) { - return eh.GlobalCall(funcName, eh.Ident("request"), args[0]), nil - } - return nil, &common.Error{ - Location: eh.OffsetLocation(args[0].GetId()), - Message: "matcher argument must be a string literal", + return eh.NewCall(funcName, eh.NewIdent("request"), args[0]), nil } + return nil, eh.NewError(args[0].ID(), "matcher argument must be a string literal") } } @@ -520,49 +510,35 @@ func celMatcherStringMacroExpander(funcName string) parser.MacroExpander { // // The following function call is returned: <funcName>(request, arg) func celMatcherJSONMacroExpander(funcName string) parser.MacroExpander { - return func(eh parser.ExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) { + return func(eh cel.MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error) { if len(args) != 1 { - return nil, &common.Error{ - Message: "matcher requires a map literal argument", - } + return nil, eh.NewError(0, "matcher requires a map literal argument") } arg := args[0] - switch arg.GetExprKind().(type) { - case *exprpb.Expr_StructExpr: - structExpr := arg.GetStructExpr() - if structExpr.GetMessageName() != "" { - return nil, &common.Error{ - Location: eh.OffsetLocation(arg.GetId()), - Message: fmt.Sprintf( - "matcher input must be a map literal, not a %s", - structExpr.GetMessageName(), - ), - } - } - for _, entry := range structExpr.GetEntries() { - isStringPlaceholder := isCELStringExpr(entry.GetMapKey()) + + switch arg.Kind() { + case ast.StructKind: + return nil, eh.NewError(arg.ID(), + fmt.Sprintf("matcher input must be a map literal, not a %s", arg.AsStruct().TypeName())) + case ast.MapKind: + mapExpr := arg.AsMap() + for _, entry := range mapExpr.Entries() { + isStringPlaceholder := isCELStringExpr(entry.AsMapEntry().Key()) if !isStringPlaceholder { - return nil, &common.Error{ - Location: eh.OffsetLocation(entry.GetId()), - Message: "matcher map keys must be string literals", - } + return nil, eh.NewError(entry.ID(), "matcher map keys must be string literals") } - isStringListPlaceholder := isCELStringExpr(entry.GetValue()) || - isCELStringListLiteral(entry.GetValue()) + isStringListPlaceholder := isCELStringExpr(entry.AsMapEntry().Value()) || + isCELStringListLiteral(entry.AsMapEntry().Value()) if !isStringListPlaceholder { - return nil, &common.Error{ - Location: eh.OffsetLocation(entry.GetValue().GetId()), - Message: "matcher map values must be string or list literals", - } + return nil, eh.NewError(entry.AsMapEntry().Value().ID(), "matcher map values must be string or list literals") } } - return eh.GlobalCall(funcName, eh.Ident("request"), arg), nil + return eh.NewCall(funcName, eh.NewIdent("request"), arg), nil + case ast.UnspecifiedExprKind, ast.CallKind, ast.ComprehensionKind, ast.IdentKind, ast.ListKind, ast.LiteralKind, ast.SelectKind: + // appeasing the linter :) } - return nil, &common.Error{ - Location: eh.OffsetLocation(arg.GetId()), - Message: "matcher requires a map literal argument", - } + return nil, eh.NewError(arg.ID(), "matcher requires a map literal argument") } } @@ -607,69 +583,77 @@ func CELValueToMapStrList(data ref.Val) (map[string][]string, error) { } // isCELStringExpr indicates whether the expression is a supported string expression -func isCELStringExpr(e *exprpb.Expr) bool { +func isCELStringExpr(e ast.Expr) bool { return isCELStringLiteral(e) || isCELCaddyPlaceholderCall(e) || isCELConcatCall(e) } // isCELStringLiteral returns whether the expression is a CEL string literal. -func isCELStringLiteral(e *exprpb.Expr) bool { - switch e.GetExprKind().(type) { - case *exprpb.Expr_ConstExpr: - constant := e.GetConstExpr() - switch constant.GetConstantKind().(type) { - case *exprpb.Constant_StringValue: +func isCELStringLiteral(e ast.Expr) bool { + switch e.Kind() { + case ast.LiteralKind: + constant := e.AsLiteral() + switch constant.Type() { + case types.StringType: return true } + case ast.UnspecifiedExprKind, ast.CallKind, ast.ComprehensionKind, ast.IdentKind, ast.ListKind, ast.MapKind, ast.SelectKind, ast.StructKind: + // appeasing the linter :) } return false } // isCELCaddyPlaceholderCall returns whether the expression is a caddy placeholder call. -func isCELCaddyPlaceholderCall(e *exprpb.Expr) bool { - switch e.GetExprKind().(type) { - case *exprpb.Expr_CallExpr: - call := e.GetCallExpr() - if call.GetFunction() == "caddyPlaceholder" { +func isCELCaddyPlaceholderCall(e ast.Expr) bool { + switch e.Kind() { + case ast.CallKind: + call := e.AsCall() + if call.FunctionName() == "caddyPlaceholder" { return true } + case ast.UnspecifiedExprKind, ast.ComprehensionKind, ast.IdentKind, ast.ListKind, ast.LiteralKind, ast.MapKind, ast.SelectKind, ast.StructKind: + // appeasing the linter :) } return false } // isCELConcatCall tests whether the expression is a concat function (+) with string, placeholder, or // other concat call arguments. -func isCELConcatCall(e *exprpb.Expr) bool { - switch e.GetExprKind().(type) { - case *exprpb.Expr_CallExpr: - call := e.GetCallExpr() - if call.GetTarget() != nil { +func isCELConcatCall(e ast.Expr) bool { + switch e.Kind() { + case ast.CallKind: + call := e.AsCall() + if call.Target().Kind() != ast.UnspecifiedExprKind { return false } - if call.GetFunction() != operators.Add { + if call.FunctionName() != operators.Add { return false } - for _, arg := range call.GetArgs() { + for _, arg := range call.Args() { if !isCELStringExpr(arg) { return false } } return true + case ast.UnspecifiedExprKind, ast.ComprehensionKind, ast.IdentKind, ast.ListKind, ast.LiteralKind, ast.MapKind, ast.SelectKind, ast.StructKind: + // appeasing the linter :) } return false } // isCELStringListLiteral returns whether the expression resolves to a list literal // containing only string constants or a placeholder call. -func isCELStringListLiteral(e *exprpb.Expr) bool { - switch e.GetExprKind().(type) { - case *exprpb.Expr_ListExpr: - list := e.GetListExpr() - for _, elem := range list.GetElements() { +func isCELStringListLiteral(e ast.Expr) bool { + switch e.Kind() { + case ast.ListKind: + list := e.AsList() + for _, elem := range list.Elements() { if !isCELStringExpr(elem) { return false } } return true + case ast.UnspecifiedExprKind, ast.CallKind, ast.ComprehensionKind, ast.IdentKind, ast.LiteralKind, ast.MapKind, ast.SelectKind, ast.StructKind: + // appeasing the linter :) } return false } diff --git a/modules/caddyhttp/fileserver/matcher.go b/modules/caddyhttp/fileserver/matcher.go index d4a40b58d..c315b8e38 100644 --- a/modules/caddyhttp/fileserver/matcher.go +++ b/modules/caddyhttp/fileserver/matcher.go @@ -27,11 +27,12 @@ import ( "github.com/google/cel-go/cel" "github.com/google/cel-go/common" + "github.com/google/cel-go/common/ast" "github.com/google/cel-go/common/operators" + "github.com/google/cel-go/common/types" "github.com/google/cel-go/common/types/ref" "github.com/google/cel-go/parser" "go.uber.org/zap" - exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" @@ -220,30 +221,30 @@ func (MatchFile) CELLibrary(ctx caddy.Context) (cel.Library, error) { } func celFileMatcherMacroExpander() parser.MacroExpander { - return func(eh parser.ExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) { + return func(eh parser.ExprHelper, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error) { if len(args) == 0 { - return eh.GlobalCall("file", - eh.Ident("request"), + return eh.NewCall("file", + eh.NewIdent("request"), eh.NewMap(), ), nil } if len(args) == 1 { arg := args[0] if isCELStringLiteral(arg) || isCELCaddyPlaceholderCall(arg) { - return eh.GlobalCall("file", - eh.Ident("request"), + return eh.NewCall("file", + eh.NewIdent("request"), eh.NewMap(eh.NewMapEntry( - eh.LiteralString("try_files"), + eh.NewLiteral(types.String("try_files")), eh.NewList(arg), false, )), ), nil } if isCELTryFilesLiteral(arg) { - return eh.GlobalCall("file", eh.Ident("request"), arg), nil + return eh.NewCall("file", eh.NewIdent("request"), arg), nil } return nil, &common.Error{ - Location: eh.OffsetLocation(arg.GetId()), + Location: eh.OffsetLocation(arg.ID()), Message: "matcher requires either a map or string literal argument", } } @@ -251,15 +252,15 @@ func celFileMatcherMacroExpander() parser.MacroExpander { for _, arg := range args { if !(isCELStringLiteral(arg) || isCELCaddyPlaceholderCall(arg)) { return nil, &common.Error{ - Location: eh.OffsetLocation(arg.GetId()), + Location: eh.OffsetLocation(arg.ID()), Message: "matcher only supports repeated string literal arguments", } } } - return eh.GlobalCall("file", - eh.Ident("request"), + return eh.NewCall("file", + eh.NewIdent("request"), eh.NewMap(eh.NewMapEntry( - eh.LiteralString("try_files"), + eh.NewLiteral(types.String("try_files")), eh.NewList(args...), false, )), @@ -569,20 +570,17 @@ func indexFold(haystack, needle string) int { // isCELTryFilesLiteral returns whether the expression resolves to a map literal containing // only string keys with or a placeholder call. -func isCELTryFilesLiteral(e *exprpb.Expr) bool { - switch e.GetExprKind().(type) { - case *exprpb.Expr_StructExpr: - structExpr := e.GetStructExpr() - if structExpr.GetMessageName() != "" { - return false - } - for _, entry := range structExpr.GetEntries() { - mapKey := entry.GetMapKey() - mapVal := entry.GetValue() +func isCELTryFilesLiteral(e ast.Expr) bool { + switch e.Kind() { + case ast.MapKind: + mapExpr := e.AsMap() + for _, entry := range mapExpr.Entries() { + mapKey := entry.AsMapEntry().Key() + mapVal := entry.AsMapEntry().Value() if !isCELStringLiteral(mapKey) { return false } - mapKeyStr := mapKey.GetConstExpr().GetStringValue() + mapKeyStr := mapKey.AsLiteral().ConvertToType(types.StringType).Value() if mapKeyStr == "try_files" || mapKeyStr == "split_path" { if !isCELStringListLiteral(mapVal) { return false @@ -596,74 +594,85 @@ func isCELTryFilesLiteral(e *exprpb.Expr) bool { } } return true + + case ast.UnspecifiedExprKind, ast.CallKind, ast.ComprehensionKind, ast.IdentKind, ast.ListKind, ast.LiteralKind, ast.SelectKind, ast.StructKind: + // appeasing the linter :) } return false } // isCELStringExpr indicates whether the expression is a supported string expression -func isCELStringExpr(e *exprpb.Expr) bool { +func isCELStringExpr(e ast.Expr) bool { return isCELStringLiteral(e) || isCELCaddyPlaceholderCall(e) || isCELConcatCall(e) } // isCELStringLiteral returns whether the expression is a CEL string literal. -func isCELStringLiteral(e *exprpb.Expr) bool { - switch e.GetExprKind().(type) { - case *exprpb.Expr_ConstExpr: - constant := e.GetConstExpr() - switch constant.GetConstantKind().(type) { - case *exprpb.Constant_StringValue: +func isCELStringLiteral(e ast.Expr) bool { + switch e.Kind() { + case ast.LiteralKind: + constant := e.AsLiteral() + switch constant.Type() { + case types.StringType: return true } + case ast.UnspecifiedExprKind, ast.CallKind, ast.ComprehensionKind, ast.IdentKind, ast.ListKind, ast.MapKind, ast.SelectKind, ast.StructKind: + // appeasing the linter :) } return false } // isCELCaddyPlaceholderCall returns whether the expression is a caddy placeholder call. -func isCELCaddyPlaceholderCall(e *exprpb.Expr) bool { - switch e.GetExprKind().(type) { - case *exprpb.Expr_CallExpr: - call := e.GetCallExpr() - if call.GetFunction() == "caddyPlaceholder" { +func isCELCaddyPlaceholderCall(e ast.Expr) bool { + switch e.Kind() { + case ast.CallKind: + call := e.AsCall() + if call.FunctionName() == "caddyPlaceholder" { return true } + case ast.UnspecifiedExprKind, ast.ComprehensionKind, ast.IdentKind, ast.ListKind, ast.LiteralKind, ast.MapKind, ast.SelectKind, ast.StructKind: + // appeasing the linter :) } return false } // isCELConcatCall tests whether the expression is a concat function (+) with string, placeholder, or // other concat call arguments. -func isCELConcatCall(e *exprpb.Expr) bool { - switch e.GetExprKind().(type) { - case *exprpb.Expr_CallExpr: - call := e.GetCallExpr() - if call.GetTarget() != nil { +func isCELConcatCall(e ast.Expr) bool { + switch e.Kind() { + case ast.CallKind: + call := e.AsCall() + if call.Target().Kind() != ast.UnspecifiedExprKind { return false } - if call.GetFunction() != operators.Add { + if call.FunctionName() != operators.Add { return false } - for _, arg := range call.GetArgs() { + for _, arg := range call.Args() { if !isCELStringExpr(arg) { return false } } return true + case ast.UnspecifiedExprKind, ast.ComprehensionKind, ast.IdentKind, ast.ListKind, ast.LiteralKind, ast.MapKind, ast.SelectKind, ast.StructKind: + // appeasing the linter :) } return false } // isCELStringListLiteral returns whether the expression resolves to a list literal // containing only string constants or a placeholder call. -func isCELStringListLiteral(e *exprpb.Expr) bool { - switch e.GetExprKind().(type) { - case *exprpb.Expr_ListExpr: - list := e.GetListExpr() - for _, elem := range list.GetElements() { +func isCELStringListLiteral(e ast.Expr) bool { + switch e.Kind() { + case ast.ListKind: + list := e.AsList() + for _, elem := range list.Elements() { if !isCELStringExpr(elem) { return false } } return true + case ast.UnspecifiedExprKind, ast.CallKind, ast.ComprehensionKind, ast.IdentKind, ast.LiteralKind, ast.MapKind, ast.SelectKind, ast.StructKind: + // appeasing the linter :) } return false } |