From ba686011da7a905cf9a1430e81b0271cf9450a80 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sat, 24 Feb 2024 23:05:12 +0100 Subject: [PATCH 01/49] Update dependencies --- go.mod | 19 ++++++++++--------- go.sum | 38 ++++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index 87ead362..d9840202 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/NYTimes/gziphandler v1.1.1 github.com/codingsince1985/checksum v1.3.0 github.com/envoyproxy/protoc-gen-validate v1.0.4 - github.com/gatewayd-io/gatewayd-plugin-sdk v0.1.10 + github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.0 github.com/getsentry/sentry-go v0.27.0 github.com/go-co-op/gocron v1.37.0 github.com/google/go-github/v53 v53.2.0 @@ -19,19 +19,19 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/prometheus/client_golang v1.18.0 github.com/prometheus/client_model v0.6.0 - github.com/prometheus/common v0.47.0 + github.com/prometheus/common v0.48.0 github.com/rs/zerolog v1.32.0 github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 github.com/spf13/cast v1.6.0 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 github.com/zenizh/go-capturer v0.0.0-20211219060012-52ea6c8fed04 - go.opentelemetry.io/otel v1.23.1 - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.23.1 - go.opentelemetry.io/otel/sdk v1.23.1 - go.opentelemetry.io/otel/trace v1.23.1 - golang.org/x/exp v0.0.0-20240213143201-ec583247a57a + go.opentelemetry.io/otel v1.24.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 + go.opentelemetry.io/otel/sdk v1.24.0 + go.opentelemetry.io/otel/trace v1.24.0 + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 google.golang.org/genproto/googleapis/api v0.0.0-20240221002015-b0ce06bbee7c google.golang.org/grpc v1.62.0 google.golang.org/protobuf v1.32.0 @@ -48,6 +48,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/expr-lang/expr v1.16.1 // indirect github.com/fatih/color v1.16.0 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect @@ -71,7 +72,7 @@ require ( github.com/robfig/cron/v3 v3.0.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect - go.opentelemetry.io/otel/metric v1.23.1 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.1.0 // indirect go.uber.org/atomic v1.11.0 // indirect golang.org/x/crypto v0.19.0 // indirect diff --git a/go.sum b/go.sum index 90256b69..19df162e 100644 --- a/go.sum +++ b/go.sum @@ -69,6 +69,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/expr-lang/expr v1.16.1 h1:Na8CUcMdyGbnNpShY7kzcHCU7WqxuL+hnxgHZ4vaz/A= +github.com/expr-lang/expr v1.16.1/go.mod h1:uCkhfG+x7fcZ5A5sXHKuQ07jGZRl6J0FCAaf2k4PtVQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= @@ -81,8 +83,8 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gatewayd-io/gatewayd-plugin-sdk v0.1.10 h1:jtHzHtekVEK13d6hqleFZ41D8SWABF4R2JHhOHFQOmc= -github.com/gatewayd-io/gatewayd-plugin-sdk v0.1.10/go.mod h1:AS9WVWdp0av0D2sZkRM9ZOZMMp3DpNnwDsnmwNGCCrM= +github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.0 h1:JG5FaGn+gj32qvvoou2PNraPB+MfO1Qe01tw4VVUqrY= +github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.0/go.mod h1:1XS2ufw+8VRTHAbDf18Y7rSPlOczeQ/baUWPqJrDkeE= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -311,8 +313,8 @@ github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOA github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= -github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= @@ -372,18 +374,18 @@ github.com/zenizh/go-capturer v0.0.0-20211219060012-52ea6c8fed04/go.mod h1:FiwNQ go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= -go.opentelemetry.io/otel v1.23.1 h1:Za4UzOqJYS+MUczKI320AtqZHZb7EqxO00jAHE0jmQY= -go.opentelemetry.io/otel v1.23.1/go.mod h1:Td0134eafDLcTS4y+zQ26GE8u3dEuRBiBCTUIRHaikA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1 h1:o8iWeVFa1BcLtVEV0LzrCxV2/55tB3xLxADr6Kyoey4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1/go.mod h1:SEVfdK4IoBnbT2FXNM/k8yC08MrfbhWk3U4ljM8B3HE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.23.1 h1:p3A5+f5l9e/kuEBwLOrnpkIDHQFlHmbiVxMURWRK6gQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.23.1/go.mod h1:OClrnXUjBqQbInvjJFjYSnMxBSCXBF8r3b34WqjiIrQ= -go.opentelemetry.io/otel/metric v1.23.1 h1:PQJmqJ9u2QaJLBOELl1cxIdPcpbwzbkjfEyelTl2rlo= -go.opentelemetry.io/otel/metric v1.23.1/go.mod h1:mpG2QPlAfnK8yNhNJAxDZruU9Y1/HubbC+KyH8FaCWI= -go.opentelemetry.io/otel/sdk v1.23.1 h1:O7JmZw0h76if63LQdsBMKQDWNb5oEcOThG9IrxscV+E= -go.opentelemetry.io/otel/sdk v1.23.1/go.mod h1:LzdEVR5am1uKOOwfBWFef2DCi1nu3SA8XQxx2IerWFk= -go.opentelemetry.io/otel/trace v1.23.1 h1:4LrmmEd8AU2rFvU1zegmvqW7+kWarxtNOPyeL6HmYY8= -go.opentelemetry.io/otel/trace v1.23.1/go.mod h1:4IpnpJFwr1mo/6HL8XIPJaE9y0+u1KcVmuW7dwFSVrI= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -405,8 +407,8 @@ golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= -golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= From 527f7cf109cc6a31afbf7cd871106157c018cadf Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sat, 24 Feb 2024 23:43:12 +0100 Subject: [PATCH 02/49] Add Act registry --- act/builtins.go | 120 ++++++++++++++++++++++++++++++++++ act/registry.go | 167 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 act/builtins.go create mode 100644 act/registry.go diff --git a/act/builtins.go b/act/builtins.go new file mode 100644 index 00000000..5f67b450 --- /dev/null +++ b/act/builtins.go @@ -0,0 +1,120 @@ +package act + +import ( + sdkAct "github.com/gatewayd-io/gatewayd-plugin-sdk/act" + "github.com/gatewayd-io/gatewayd-plugin-sdk/logging" + "github.com/rs/zerolog" + "github.com/spf13/cast" +) + +const LOG_DEFAULT_FIELD_COUNT = 3 + +var ( + builtinsPolicies = []*sdkAct.Policy{ + sdkAct.MustNewPolicy("passthrough", "true", nil), + sdkAct.MustNewPolicy( + "terminate", + `Signal.terminate == true && Policy.terminate == "stop"`, + map[string]any{"terminate": "stop"}, + ), + sdkAct.MustNewPolicy( + "log", + `Signal.log == true && Policy.log == "enabled"`, + map[string]any{"log": "enabled"}, + ), + sdkAct.MustNewPolicy( + "cache", + `Signal.cache == true && Policy.cache == "enabled"`, + map[string]any{"cache": "enabled"}, + ), + } + + builtinActions = []*sdkAct.Action{ + { + Name: "passthrough", + Metadata: nil, + Sync: true, + Terminal: false, + Run: func(_ zerolog.Logger, data map[string]any) (any, error) { return true, nil }, + }, + { + Name: "terminate", + Metadata: nil, + Sync: true, + Terminal: true, + Run: func(_ zerolog.Logger, data map[string]any) (any, error) { return true, nil }, + }, + { + Name: "log", + Metadata: nil, + Sync: false, + Terminal: false, + Run: func(logger zerolog.Logger, data map[string]any) (any, error) { + fields := map[string]any{} + // Only log the fields that are not level, message, or log. + if len(data) > LOG_DEFAULT_FIELD_COUNT { + for k, v := range data { + if k == "level" || k == "message" || k == "log" { + continue + } + fields[k] = v + } + } + logger.WithLevel( + logging.GetZeroLogLevel(cast.ToString(data["level"])), + ).Fields(fields).Msg(cast.ToString(data["message"])) + return true, nil + }, + }, + } + + // TODO: figure out if the default output should match the default policy. + DefaultOutput = func() *sdkAct.Output { + return &sdkAct.Output{ + MatchedPolicy: "passthrough", + Verdict: true, + Terminal: false, + Sync: true, + } + } +) + +func Terminate() *sdkAct.Signal { + return &sdkAct.Signal{ + Name: "terminate", + Metadata: map[string]any{ + "terminate": true, + }, + } +} + +func Log(level, message string, fields map[string]any) *sdkAct.Signal { + metadata := map[string]any{ + "log": true, + "level": level, + "message": message, + } + + if fields != nil { + for k, v := range fields { + if k == "level" || k == "message" { + continue + } + metadata[k] = v + } + } + + return &sdkAct.Signal{ + Name: "log", + Metadata: metadata, + } +} + +func Cache() *sdkAct.Signal { + return &sdkAct.Signal{ + Name: "cache", + Metadata: map[string]any{ + "cache": true, + }, + } +} diff --git a/act/registry.go b/act/registry.go new file mode 100644 index 00000000..25fb4f6b --- /dev/null +++ b/act/registry.go @@ -0,0 +1,167 @@ +package act + +import ( + "context" + "errors" + "time" + + sdkAct "github.com/gatewayd-io/gatewayd-plugin-sdk/act" + "github.com/rs/zerolog" +) + +type IRegistry interface { + Add(policy *sdkAct.Policy) + Apply(signals []sdkAct.Signal) []*sdkAct.Output + Run(output *sdkAct.Output) (any, error) +} + +// Registry keeps track of all policies and actions. +type Registry struct { + logger zerolog.Logger + timeout time.Duration // Timeout for policy evaluation + + Policies map[string]*sdkAct.Policy + Actions map[string]*sdkAct.Action + DefaultPolicy *sdkAct.Policy +} + +// NewRegistry creates a new registry with the specified default policy and timeout. +func NewRegistry(defaultPolicy string, timeout time.Duration, logger zerolog.Logger) *Registry { + policies := make(map[string]*sdkAct.Policy) + for _, policy := range builtinsPolicies { + policies[policy.Name] = policy + logger.Debug().Str("name", policy.Name).Msg("Registered builtin policy") + } + + actions := make(map[string]*sdkAct.Action) + for _, action := range builtinActions { + actions[action.Name] = action + logger.Debug().Str("name", action.Name).Msg("Registered builtin action") + } + + // The default policy must exist, otherwise use passthrough. + if _, exists := policies[defaultPolicy]; !exists || defaultPolicy == "" { + logger.Warn().Str("name", defaultPolicy).Msg( + "The specified default policy does not exist, using passthrough") + defaultPolicy = "passthrough" + } + + return &Registry{ + logger: logger, + timeout: timeout, + Actions: actions, + Policies: policies, + DefaultPolicy: policies[defaultPolicy], + } +} + +// Add adds a policy to the registry. +func (r *Registry) Add(policy *sdkAct.Policy) { + if policy == nil { + r.logger.Warn().Msg("Policy is nil, not adding") + return + } + + if _, exists := r.Policies[policy.Name]; exists { + r.logger.Warn().Str("name", policy.Name).Msg("Policy already exists, overwriting") + } + + // Builtin policies are can be overwritten by user-defined policies. + r.Policies[policy.Name] = policy +} + +// Apply applies the signals to the registry and returns the outputs. +func (r *Registry) Apply(signals []sdkAct.Signal) []*sdkAct.Output { + DefaultOutputs := []*sdkAct.Output{ + DefaultOutput(), + } + + if len(signals) == 0 { + return DefaultOutputs + } + + // TODO: Check for non-contradictory actions (forward vs. drop) + + outputs := []*sdkAct.Output{} + for _, signal := range signals { + output, err := r.apply(signal) + if err != nil { + r.logger.Error().Err(err).Str("name", signal.Name).Msg("Error applying signal") + continue + } + outputs = append(outputs, output) + } + + if len(outputs) == 0 { + return DefaultOutputs + } + + return outputs +} + +// apply applies the signal to the registry and returns the output. +func (r *Registry) apply(signal sdkAct.Signal) (*sdkAct.Output, error) { + action, ok := r.Actions[signal.Name] + if !ok { + return nil, errors.New("No matching action") + } + + policy, ok := r.Policies[action.Name] + if !ok { + return nil, errors.New("No matching policy") + } + + ctx, cancel := context.WithTimeout(context.Background(), r.timeout) + defer cancel() + + // Action dictates the sync mode, not the signal. + verdict, err := policy.Eval( + ctx, sdkAct.Input{ + Name: signal.Name, + Policy: policy.Metadata, + Signal: signal.Metadata, + Sync: action.Sync, + }, + ) + if err != nil { + return nil, err + } + + return &sdkAct.Output{ + MatchedPolicy: policy.Name, + Verdict: verdict, + Metadata: signal.Metadata, + Terminal: action.Terminal, + Sync: action.Sync, + }, nil +} + +// Run runs the output and returns the result. +func (r *Registry) Run(output *sdkAct.Output) (any, error) { + if output == nil { + r.logger.Warn().Msg("Output is nil, not running") + return nil, errors.New("Output is nil") + } + + action, ok := r.Actions[output.MatchedPolicy] + if !ok { + r.logger.Warn().Str("matched_policy", output.MatchedPolicy).Msg( + "Action does not exist, not running") + return nil, errors.New("Action does not exist") + } + + if action.Sync { + r.logger.Debug().Fields(map[string]interface{}{ + "execution_mode": "sync", + "action": action.Name, + }).Msgf("Running action") + return action.Run(r.logger, output.Metadata) + } else { + r.logger.Debug().Fields(map[string]interface{}{ + "execution_mode": "async", + "action": action.Name, + }).Msgf("Running action") + go action.Run(r.logger, output.Metadata) + return nil, nil + } +} From bbd97debe874f78dbc0ab2363f12fb069cf7f629 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sat, 24 Feb 2024 23:44:02 +0100 Subject: [PATCH 03/49] Fix issue after updating dependency (prometheus_client for Go) --- metrics/merger.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/metrics/merger.go b/metrics/merger.go index 1e87634e..48c0c542 100644 --- a/metrics/merger.go +++ b/metrics/merger.go @@ -160,7 +160,8 @@ func (m *Merger) MergeMetrics(pluginMetrics map[string][]byte) *gerr.GatewayDErr // TODO: There should be a better, more efficient way to merge metrics from plugins. var metricsOutput bytes.Buffer - enc := expfmt.NewEncoder(io.Writer(&metricsOutput), expfmt.FmtText) + enc := expfmt.NewEncoder(io.Writer(&metricsOutput), + expfmt.NewFormat(expfmt.FormatType(expfmt.TypeTextPlain))) for pluginName, metrics := range pluginMetrics { // Skip empty metrics. if metrics == nil { From dc7816f997e07b40fc46fe8982c6ce4eaf302628 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sat, 24 Feb 2024 23:48:43 +0100 Subject: [PATCH 04/49] Implement Act system in the plugin registry --- plugin/plugin_registry.go | 130 +++++++++++++++++++++++++++++--------- plugin/utils.go | 60 ++++++++++++++++++ 2 files changed, 160 insertions(+), 30 deletions(-) diff --git a/plugin/plugin_registry.go b/plugin/plugin_registry.go index 7171d424..fc42273a 100644 --- a/plugin/plugin_registry.go +++ b/plugin/plugin_registry.go @@ -4,12 +4,15 @@ import ( "context" "crypto/sha256" "encoding/hex" + "fmt" "sort" "time" "github.com/Masterminds/semver/v3" + sdkAct "github.com/gatewayd-io/gatewayd-plugin-sdk/act" sdkPlugin "github.com/gatewayd-io/gatewayd-plugin-sdk/plugin" v1 "github.com/gatewayd-io/gatewayd-plugin-sdk/plugin/v1" + "github.com/gatewayd-io/gatewayd/act" "github.com/gatewayd-io/gatewayd/config" gerr "github.com/gatewayd-io/gatewayd/errors" "github.com/gatewayd-io/gatewayd/logging" @@ -28,10 +31,10 @@ type IHook interface { Hooks() map[v1.HookName]map[sdkPlugin.Priority]sdkPlugin.Method Run( ctx context.Context, - args map[string]interface{}, + args map[string]any, hookName v1.HookName, opts ...grpc.CallOption, - ) (map[string]interface{}, *gerr.GatewayDError) + ) (map[string]any, *gerr.GatewayDError) } //nolint:interfacebloat @@ -47,16 +50,19 @@ type IRegistry interface { Shutdown() LoadPlugins(ctx context.Context, plugins []config.Plugin, startTimeout time.Duration) RegisterHooks(ctx context.Context, pluginID sdkPlugin.Identifier) + Apply(hookName, priority string, result *v1.Struct) ([]*sdkAct.Output, bool) + PolicyRegistry() act.IRegistry // Hook management IHook } type Registry struct { - plugins pool.IPool - hooks map[v1.HookName]map[sdkPlugin.Priority]sdkPlugin.Method - ctx context.Context //nolint:containedctx - devMode bool + plugins pool.IPool + policiesRegistry act.IRegistry + hooks map[v1.HookName]map[sdkPlugin.Priority]sdkPlugin.Method + ctx context.Context //nolint:containedctx + devMode bool Logger zerolog.Logger Compatibility config.CompatibilityPolicy @@ -69,6 +75,7 @@ var _ IRegistry = (*Registry)(nil) // NewRegistry creates a new plugin registry. func NewRegistry( ctx context.Context, + policiesRegistry act.IRegistry, compatibility config.CompatibilityPolicy, termination config.TerminationPolicy, logger zerolog.Logger, @@ -78,13 +85,14 @@ func NewRegistry( defer span.End() return &Registry{ - plugins: pool.NewPool(regCtx, config.EmptyPoolCapacity), - hooks: map[v1.HookName]map[sdkPlugin.Priority]sdkPlugin.Method{}, - ctx: regCtx, - devMode: devMode, - Logger: logger, - Compatibility: compatibility, - Termination: termination, + plugins: pool.NewPool(regCtx, config.EmptyPoolCapacity), + policiesRegistry: policiesRegistry, + hooks: map[v1.HookName]map[sdkPlugin.Priority]sdkPlugin.Method{}, + ctx: regCtx, + devMode: devMode, + Logger: logger, + Compatibility: compatibility, + Termination: termination, } } @@ -236,7 +244,7 @@ func (reg *Registry) AddHook(hookName v1.HookName, priority sdkPlugin.Priority, } else { if _, ok := reg.hooks[hookName][priority]; ok { reg.Logger.Warn().Fields( - map[string]interface{}{ + map[string]any{ "hookName": hookName.String(), "priority": priority, }, @@ -254,10 +262,10 @@ func (reg *Registry) AddHook(hookName v1.HookName, priority sdkPlugin.Priority, // The opts are passed to the hooks as well to allow them to use the grpc.CallOption. func (reg *Registry) Run( ctx context.Context, - args map[string]interface{}, + args map[string]any, hookName v1.HookName, opts ...grpc.CallOption, -) (map[string]interface{}, *gerr.GatewayDError) { +) (map[string]any, *gerr.GatewayDError) { _, span := otel.Tracer(config.TracerName).Start(reg.ctx, "Run") defer span.End() @@ -296,6 +304,7 @@ func (reg *Registry) Run( // Run hooks, passing the result of the previous hook to the next one. returnVal := &v1.Struct{} + outputs := []*sdkAct.Output{} // The signature of parameters and args MUST be the same for this to work. for idx, priority := range priorities { var result *v1.Struct @@ -308,7 +317,7 @@ func (reg *Registry) Run( if err != nil { reg.Logger.Error().Err(err).Fields( - map[string]interface{}{ + map[string]any{ "hookName": hookName.String(), "priority": priority, }, @@ -316,21 +325,75 @@ func (reg *Registry) Run( span.RecordError(err) } - // Update the last return value with the current result + if result == nil { + // Remove the hook from the registry, log the error and execute the next hook. + reg.Logger.Error().Fields( + map[string]any{ + "hookName": hookName.String(), + "priority": priority, + }, + ).Msg("Hook returned nil result, so it won't work properly") + delete(reg.hooks[hookName], priority) + continue + } + + out, terminal := reg.Apply(hookName.String(), fmt.Sprint(priority), result) + outputs = append(outputs, out...) + + if terminal { + // Any signal matching a policy with a terminal action + // will terminate the execution of the rest of the hooks. + reg.Logger.Debug().Msg("Terminal signal received") + span.AddEvent("Terminal signal received") + resultMap := result.AsMap() + resultMap[sdkAct.Outputs] = outputs + resultMap[sdkAct.Terminal] = true + return resultMap, nil + } + returnVal = result + } - // If the termination policy is set to Stop, check if the terminate flag - // is set to true. If it is, abort the execution of the rest of the registered hooks. - if reg.Termination == config.Stop { - // If the terminate flag is set to true, - // abort the execution of the rest of the registered hooks. - if terminate, ok := result.GetFields()["terminate"]; ok && terminate.GetBoolValue() { - break - } + returnMap := returnVal.AsMap() + returnMap[sdkAct.Outputs] = outputs + return returnMap, nil +} + +// Apply applies policies to the result. +func (reg *Registry) Apply( + hookName, priority string, result *v1.Struct, +) ([]*sdkAct.Output, bool) { + _, span := otel.Tracer(config.TracerName).Start(reg.ctx, "Apply") + defer span.End() + + // Get signals from the result. + signals := GetSignals(result.AsMap(), reg.Logger, reg.PolicyRegistry()) + // Apply policies to the signals. + // The outputs contains the verdicts of the policies and their metadata. + // And using this list, the caller can take further actions. + outputs := ApplyPolicies(hookName, signals, reg.Logger, reg.PolicyRegistry()) + + // If no policies are found, return a default output. + if len(outputs) == 0 { + reg.Logger.Debug().Msg("No policies found for the given signals") + return nil, false + } + + // Check if any of the policies have a terminal action. + var terminal bool + for _, output := range outputs { + // if output.Verdict && output.MatchedPolicy == "log" { + // reg.Logger.Debug().Msgf("Log: %+v", output.Metadata) + // reg.PolicyRegistry().Run(output) + // } + + if output.Verdict && output.Terminal { + terminal = true + break } } - return returnVal.AsMap(), nil + return outputs, terminal } // LoadPlugins loads plugins from the config file. @@ -499,7 +562,7 @@ func (reg *Registry) LoadPlugins( for _, req := range plugin.Requires { if !reg.Exists(req.Name, req.Version, req.RemoteURL) { reg.Logger.Debug().Fields( - map[string]interface{}{ + map[string]any{ "name": plugin.ID.Name, "requirement": req.Name, }, @@ -511,7 +574,7 @@ func (reg *Registry) LoadPlugins( continue } reg.Logger.Debug().Fields( - map[string]interface{}{ + map[string]any{ "name": plugin.ID.Name, "requirement": req.Name, }, @@ -666,7 +729,7 @@ func (reg *Registry) RegisterHooks(ctx context.Context, pluginID sdkPlugin.Ident continue } - reg.Logger.Debug().Fields(map[string]interface{}{ + reg.Logger.Debug().Fields(map[string]any{ "hook": hookName.String(), "priority": pluginImpl.Priority, "name": pluginImpl.ID.Name, @@ -675,3 +738,10 @@ func (reg *Registry) RegisterHooks(ctx context.Context, pluginID sdkPlugin.Ident reg.AddHook(hookName, pluginImpl.Priority, hookMethod) } } + +// PolicyRegistry returns the policy registry. +func (reg *Registry) PolicyRegistry() act.IRegistry { + _, span := otel.Tracer(config.TracerName).Start(reg.ctx, "PolicyRegistry") + defer span.End() + return reg.policiesRegistry +} diff --git a/plugin/utils.go b/plugin/utils.go index bf546ef3..e4d25898 100644 --- a/plugin/utils.go +++ b/plugin/utils.go @@ -3,6 +3,11 @@ package plugin import ( "os/exec" "time" + + sdkAct "github.com/gatewayd-io/gatewayd-plugin-sdk/act" + "github.com/gatewayd-io/gatewayd/act" + "github.com/rs/zerolog" + "github.com/spf13/cast" ) // NewCommand returns a command with the given arguments and environment variables. @@ -45,3 +50,58 @@ func CastToPrimitiveTypes(args map[string]interface{}) map[string]interface{} { } return args } + +// GetSignals decodes the signals from the result map and returns them as a list of Signal objects. +func GetSignals(result map[string]any, logger zerolog.Logger, reg act.IRegistry) []sdkAct.Signal { + decodedSignals := []sdkAct.Signal{} + + if signals, ok := result[sdkAct.Signals]; ok { + signals := cast.ToSlice(signals) + for _, signal := range signals { + signalMap := cast.ToStringMap(signal) + name := cast.ToString(signalMap[sdkAct.Name]) + metadata := cast.ToStringMap(signalMap[sdkAct.Metadata]) + + if name != "" { + // Add the signal to the list of signals. + decodedSignals = append(decodedSignals, sdkAct.Signal{ + Name: name, + Metadata: metadata, + }) + } + } + } + + return decodedSignals +} + +// ApplyPolicies applies the policies to the signals and returns the outputs. +func ApplyPolicies( + hookName string, signals []sdkAct.Signal, logger zerolog.Logger, reg act.IRegistry, +) []*sdkAct.Output { + if len(signals) == 0 { + return nil + } + + signalNames := []string{} + for _, signal := range signals { + signalNames = append(signalNames, signal.Name) + } + + logger.Debug().Fields( + map[string]interface{}{ + "hook": hookName, + "signals": signalNames, + }, + ).Msg("Detected signals from the plugin hook") + + outputs := reg.Apply(signals) + logger.Debug().Fields( + map[string]interface{}{ + "hook": hookName, + "outputs": outputs, + }, + ).Msg("Applied policies to signals") + + return outputs +} From fcbf3809f5d010e1db5241cce6d59c977d3ecd75 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sat, 24 Feb 2024 23:49:43 +0100 Subject: [PATCH 05/49] Add config options for policies --- config/config.go | 3 +++ config/constants.go | 4 ++++ config/types.go | 9 +++++++++ 3 files changed, 16 insertions(+) diff --git a/config/config.go b/config/config.go index 3ddb0714..d1b293e9 100644 --- a/config/config.go +++ b/config/config.go @@ -213,6 +213,9 @@ func (c *Config) LoadDefaults(ctx context.Context) { ReloadOnCrash: true, Timeout: DefaultPluginTimeout, StartTimeout: DefaultPluginStartTimeout, + DefaultPolicy: DefaultPolicy, + PolicyTimeout: DefaultPolicyTimeout, + Policies: []Policy{}, } if c.GlobalKoanf != nil { diff --git a/config/constants.go b/config/constants.go index a698bd6e..cc6fed56 100644 --- a/config/constants.go +++ b/config/constants.go @@ -130,4 +130,8 @@ const ( // Policies. DefaultCompatibilityPolicy = Strict DefaultTerminationPolicy = Stop + + // Act. + DefaultPolicy = "passthrough" + DefaultPolicyTimeout = 30 * time.Second ) diff --git a/config/types.go b/config/types.go index aaa4a3fd..e2956c6d 100644 --- a/config/types.go +++ b/config/types.go @@ -15,6 +15,12 @@ type Plugin struct { URL string `json:"url"` } +type Policy struct { + Name string `json:"name" jsonschema:"required"` + Policy string `json:"policy" jsonschema:"required"` + Metadata map[string]any `json:"metadata,omitempty"` +} + type PluginConfig struct { CompatibilityPolicy string `json:"compatibilityPolicy" jsonschema:"enum=strict,enum=loose"` TerminationPolicy string `json:"terminationPolicy" jsonschema:"enum=continue,enum=stop"` @@ -25,6 +31,9 @@ type PluginConfig struct { Timeout time.Duration `json:"timeout" jsonschema:"oneof_type=string;integer"` StartTimeout time.Duration `json:"startTimeout" jsonschema:"oneof_type=string;integer"` Plugins []Plugin `json:"plugins"` + DefaultPolicy string `json:"defaultPolicy" jsonschema:"enum=passthrough,enum=terminate"` // TODO: Add more policies. + PolicyTimeout time.Duration `json:"policyTimeout" jsonschema:"oneof_type=string;integer"` + Policies []Policy `json:"policies"` } type Client struct { From 6617bf1443dd50321948d3f2dee811d5b7c9a7f0 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sat, 24 Feb 2024 23:52:26 +0100 Subject: [PATCH 06/49] Refactor proxy to use the new Act system --- network/proxy.go | 49 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/network/proxy.go b/network/proxy.go index 3af93ca7..34953426 100644 --- a/network/proxy.go +++ b/network/proxy.go @@ -6,8 +6,10 @@ import ( "errors" "io" "net" + "slices" "time" + "github.com/gatewayd-io/gatewayd-plugin-sdk/act" v1 "github.com/gatewayd-io/gatewayd-plugin-sdk/plugin/v1" "github.com/gatewayd-io/gatewayd/config" gerr "github.com/gatewayd-io/gatewayd/errors" @@ -18,6 +20,7 @@ import ( "github.com/go-co-op/gocron" "github.com/rs/zerolog" "go.opentelemetry.io/otel" + "golang.org/x/exp/maps" ) type IProxy interface { @@ -385,6 +388,7 @@ func (pr *Proxy) PassThroughToServer(conn *ConnWrapper, stack *Stack) *gerr.Gate stack.Push(&Request{Data: request}) // If the hook wants to terminate the connection, do it. + // TODO: Should the output be reconstructed here? Or should it be done in the plugin registry? if pr.shouldTerminate(result) { if modResponse, modReceived := pr.getPluginModifiedResponse(result); modResponse != nil { metrics.ProxyPassThroughsToClient.Inc() @@ -821,15 +825,50 @@ func (pr *Proxy) sendTrafficToClient( } // shouldTerminate is a function that retrieves the terminate field from the hook result. -// Only the OnTrafficFromClient hook will terminate the connection. +// Only the OnTrafficFromClient hook will terminate the request. func (pr *Proxy) shouldTerminate(result map[string]interface{}) bool { _, span := otel.Tracer(config.TracerName).Start(pr.ctx, "shouldTerminate") defer span.End() - // If the hook wants to terminate the connection, do it. - if result != nil { - if terminate, ok := result["terminate"].(bool); ok && terminate { - pr.logger.Debug().Str("function", "proxy.passthrough").Msg("Terminating connection") + if result == nil { + return false + } + + keys := maps.Keys(result) + // This is a shortcut to avoid running the actions' functions. + // The terminate field is only present if the action wants to terminate the request, + // that is the `Terminate` field is set in one of the outputs. + if slices.Contains(keys, act.Terminal) { + go func(outputs []*act.Output) { + for _, output := range outputs { + _, err := pr.pluginRegistry.PolicyRegistry().Run(output) + if err != nil { + pr.logger.Error().Err(err).Msg("Error running policy") + } + } + }(result[act.Outputs].([]*act.Output)) + pr.logger.Debug().Fields( + map[string]interface{}{ + "function": "proxy.passthrough", + "reason": "terminate", + }, + ).Msg("Terminating request") + return result[act.Terminal].(bool) + } + + // If the hook wants to terminate the request, do it. + outputs := result[act.Outputs].([]*act.Output) + for _, output := range outputs { + if output.MatchedPolicy == "terminate" && output.Verdict { + pr.logger.Debug().Fields( + map[string]interface{}{ + "function": "proxy.passthrough", + "policy": output.MatchedPolicy, + "verdict": output.Verdict, + "metadata": output.Metadata, + "sync": output.Sync, + }, + ).Msg("Terminating request") return true } } From 28a369a1d57f64436df4edc9cde7a0ab802b270f Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sat, 24 Feb 2024 23:53:01 +0100 Subject: [PATCH 07/49] Initialize Act system on run --- cmd/run.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/cmd/run.go b/cmd/run.go index 0e7ccc95..7abf92a4 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -16,8 +16,10 @@ import ( "time" "github.com/NYTimes/gziphandler" + sdkAct "github.com/gatewayd-io/gatewayd-plugin-sdk/act" sdkPlugin "github.com/gatewayd-io/gatewayd-plugin-sdk/plugin" v1 "github.com/gatewayd-io/gatewayd-plugin-sdk/plugin/v1" + "github.com/gatewayd-io/gatewayd/act" "github.com/gatewayd-io/gatewayd/api" "github.com/gatewayd-io/gatewayd/config" gerr "github.com/gatewayd-io/gatewayd/errors" @@ -37,6 +39,7 @@ import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" + "golang.org/x/exp/maps" "google.golang.org/grpc" "google.golang.org/grpc/credentials" ) @@ -54,6 +57,7 @@ var ( globalConfigFile string conf *config.Config pluginRegistry *plugin.Registry + policiesRegistry *act.Registry metricsServer *http.Server UsageReportURL = "localhost:59091" @@ -249,10 +253,30 @@ var runCmd = &cobra.Command{ "Running GatewayD in development mode (not recommended for production)") } + // Create a new policy registry. + policiesRegistry = act.NewRegistry( + conf.Plugin.DefaultPolicy, conf.Plugin.PolicyTimeout, logger) + + // Load policies from the configuration file and add them to the registry. + for _, plc := range conf.Plugin.Policies { + if policy, err := sdkAct.NewPolicy( + plc.Name, plc.Policy, plc.Metadata, + ); err != nil || policy == nil { + logger.Error().Err(err).Str("name", plc.Name).Msg("Failed to create policy") + } else { + policiesRegistry.Add(policy) + } + } + + logger.Info().Fields(map[string]interface{}{ + "policies": maps.Keys(policiesRegistry.Policies), + }).Msg("Policies are loaded") + // Create a new plugin registry. // The plugins are loaded and hooks registered before the configuration is loaded. pluginRegistry = plugin.NewRegistry( runCtx, + policiesRegistry, config.If[config.CompatibilityPolicy]( config.Exists[string, config.CompatibilityPolicy]( config.CompatibilityPolicies, conf.Plugin.CompatibilityPolicy), From dae7d6cb412ff41f86635e10fd3e54834199b896 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sat, 24 Feb 2024 23:54:11 +0100 Subject: [PATCH 08/49] Allow expr --- .golangci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.golangci.yaml b/.golangci.yaml index 1437f382..73f3372e 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -68,6 +68,7 @@ linters-settings: - "gopkg.in/yaml.v3" - "github.com/zenizh/go-capturer" - "gopkg.in/natefinch/lumberjack.v2" + - "github.com/expr-lang/expr" test: files: - $test From 10c6aea7aaf8b2f096036d2f14fff06e56b9fcd3 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sat, 24 Feb 2024 23:55:18 +0100 Subject: [PATCH 09/49] Update tests to reflect changes implemented as part of the Act system --- api/api_test.go | 8 ++++++++ network/proxy_test.go | 25 +++++++++++++++++++++++++ network/server_test.go | 3 +++ plugin/plugin_registry_test.go | 5 +++++ 4 files changed, 41 insertions(+) diff --git a/api/api_test.go b/api/api_test.go index 1547a813..5eabeec4 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -6,6 +6,7 @@ import ( "testing" sdkPlugin "github.com/gatewayd-io/gatewayd-plugin-sdk/plugin" + "github.com/gatewayd-io/gatewayd/act" v1 "github.com/gatewayd-io/gatewayd/api/v1" "github.com/gatewayd-io/gatewayd/config" "github.com/gatewayd-io/gatewayd/network" @@ -105,8 +106,10 @@ func TestGetPluginConfig(t *testing.T) { } func TestGetPlugins(t *testing.T) { + actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) pluginRegistry := plugin.NewRegistry( context.TODO(), + actRegistry, config.Loose, config.Stop, zerolog.Logger{}, @@ -131,8 +134,10 @@ func TestGetPlugins(t *testing.T) { } func TestGetPluginsWithEmptyPluginRegistry(t *testing.T) { + actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) pluginRegistry := plugin.NewRegistry( context.TODO(), + actRegistry, config.Loose, config.Stop, zerolog.Logger{}, @@ -236,8 +241,11 @@ func TestGetServers(t *testing.T) { config.DefaultPluginTimeout, ) + actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) + pluginRegistry := plugin.NewRegistry( context.TODO(), + actRegistry, config.Loose, config.Stop, zerolog.Logger{}, diff --git a/network/proxy_test.go b/network/proxy_test.go index 717c0b19..264761b8 100644 --- a/network/proxy_test.go +++ b/network/proxy_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/gatewayd-io/gatewayd/act" "github.com/gatewayd-io/gatewayd/config" "github.com/gatewayd-io/gatewayd/logging" "github.com/gatewayd-io/gatewayd/plugin" @@ -43,12 +44,16 @@ func TestNewProxy(t *testing.T) { err := newPool.Put(client.ID, client) assert.Nil(t, err) + // Create a new Act registry + actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + // Create a proxy with a fixed buffer newPool proxy := NewProxy( context.Background(), newPool, plugin.NewRegistry( context.Background(), + actRegistry, config.Loose, config.Stop, logger, @@ -84,6 +89,9 @@ func BenchmarkNewProxy(b *testing.B) { // Create a connection newPool newPool := pool.NewPool(context.Background(), config.EmptyPoolCapacity) + // Create a new Act registry + actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + // Create a proxy with a fixed buffer newPool for i := 0; i < b.N; i++ { proxy := NewProxy( @@ -91,6 +99,7 @@ func BenchmarkNewProxy(b *testing.B) { newPool, plugin.NewRegistry( context.Background(), + actRegistry, config.Loose, config.Stop, logger, @@ -128,12 +137,16 @@ func BenchmarkProxyConnectDisconnect(b *testing.B) { } newPool.Put("client", NewClient(context.Background(), &clientConfig, logger, nil)) //nolint:errcheck + // Create a new Act registry + actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + // Create a proxy with a fixed buffer newPool proxy := NewProxy( context.Background(), newPool, plugin.NewRegistry( context.Background(), + actRegistry, config.Loose, config.Stop, logger, @@ -178,12 +191,16 @@ func BenchmarkProxyPassThrough(b *testing.B) { } newPool.Put("client", NewClient(context.Background(), &clientConfig, logger, nil)) //nolint:errcheck + // Create a new Act registry + actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + // Create a proxy with a fixed buffer newPool proxy := NewProxy( context.Background(), newPool, plugin.NewRegistry( context.Background(), + actRegistry, config.Loose, config.Stop, logger, @@ -233,12 +250,16 @@ func BenchmarkProxyIsHealthyAndIsExhausted(b *testing.B) { client := NewClient(context.Background(), &clientConfig, logger, nil) newPool.Put("client", client) //nolint:errcheck + // Create a new Act registry + actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + // Create a proxy with a fixed buffer newPool proxy := NewProxy( context.Background(), newPool, plugin.NewRegistry( context.Background(), + actRegistry, config.Loose, config.Stop, logger, @@ -286,12 +307,16 @@ func BenchmarkProxyAvailableAndBusyConnections(b *testing.B) { client := NewClient(context.Background(), &clientConfig, logger, nil) newPool.Put("client", client) //nolint:errcheck + // Create a new Act registry + actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + // Create a proxy with a fixed buffer newPool proxy := NewProxy( context.Background(), newPool, plugin.NewRegistry( context.Background(), + actRegistry, config.Loose, config.Stop, logger, diff --git a/network/server_test.go b/network/server_test.go index c2cf1205..c834497b 100644 --- a/network/server_test.go +++ b/network/server_test.go @@ -11,6 +11,7 @@ import ( "time" v1 "github.com/gatewayd-io/gatewayd-plugin-sdk/plugin/v1" + "github.com/gatewayd-io/gatewayd/act" "github.com/gatewayd-io/gatewayd/config" "github.com/gatewayd-io/gatewayd/logging" "github.com/gatewayd-io/gatewayd/plugin" @@ -38,8 +39,10 @@ func TestRunServer(t *testing.T) { FileName: "server_test.log", }) + actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) pluginRegistry := plugin.NewRegistry( context.Background(), + actRegistry, config.Loose, config.Stop, logger, diff --git a/plugin/plugin_registry_test.go b/plugin/plugin_registry_test.go index aa35b39f..f65bb234 100644 --- a/plugin/plugin_registry_test.go +++ b/plugin/plugin_registry_test.go @@ -7,6 +7,7 @@ import ( sdkPlugin "github.com/gatewayd-io/gatewayd-plugin-sdk/plugin" v1 "github.com/gatewayd-io/gatewayd-plugin-sdk/plugin/v1" + "github.com/gatewayd-io/gatewayd/act" "github.com/gatewayd-io/gatewayd/config" "github.com/gatewayd-io/gatewayd/logging" "github.com/rs/zerolog" @@ -25,8 +26,10 @@ func NewPluginRegistry(t *testing.T) *Registry { NoColor: true, } logger := logging.NewLogger(context.Background(), cfg) + actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) reg := NewRegistry( context.Background(), + actRegistry, config.Loose, config.Stop, logger, @@ -124,8 +127,10 @@ func BenchmarkHookRun(b *testing.B) { NoColor: true, } logger := logging.NewLogger(context.Background(), cfg) + actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) reg := NewRegistry( context.Background(), + actRegistry, config.Loose, config.Stop, logger, From e3c3b5394972c4f81abb18e6b50c79a9ab12fdb6 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sun, 25 Feb 2024 00:08:08 +0100 Subject: [PATCH 10/49] Update actions --- .github/workflows/release.yaml | 2 +- .github/workflows/test.yaml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ff0c833d..866534b5 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -20,7 +20,7 @@ jobs: with: fetch-depth: 0 - name: Set up Go 1.21 - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: "1.21" cache: true diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index aff74d7c..4edf75dc 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -43,17 +43,17 @@ jobs: --health-retries 5 steps: - name: Checkout 🛎️ - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install Go 🧑‍💻 - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: "1.21" - name: Lint code issues 🚨 - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v4 with: skip-pkg-cache: true @@ -89,17 +89,17 @@ jobs: --health-retries 5 steps: - name: Checkout 🛎️ - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install Go 🧑‍💻 - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: "1.21" - name: Checkout test plugin 🛎️ - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: gatewayd-io/plugin-template-go path: plugin-template-go From 42766a76c5a285ef13616bd68968045472babf8c Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sun, 25 Feb 2024 02:36:25 +0100 Subject: [PATCH 11/49] Move Signal helper functions to SDK Remove cache signal and policy --- act/builtins.go | 45 --------------------------------------------- 1 file changed, 45 deletions(-) diff --git a/act/builtins.go b/act/builtins.go index 5f67b450..18b61578 100644 --- a/act/builtins.go +++ b/act/builtins.go @@ -22,11 +22,6 @@ var ( `Signal.log == true && Policy.log == "enabled"`, map[string]any{"log": "enabled"}, ), - sdkAct.MustNewPolicy( - "cache", - `Signal.cache == true && Policy.cache == "enabled"`, - map[string]any{"cache": "enabled"}, - ), } builtinActions = []*sdkAct.Action{ @@ -78,43 +73,3 @@ var ( } } ) - -func Terminate() *sdkAct.Signal { - return &sdkAct.Signal{ - Name: "terminate", - Metadata: map[string]any{ - "terminate": true, - }, - } -} - -func Log(level, message string, fields map[string]any) *sdkAct.Signal { - metadata := map[string]any{ - "log": true, - "level": level, - "message": message, - } - - if fields != nil { - for k, v := range fields { - if k == "level" || k == "message" { - continue - } - metadata[k] = v - } - } - - return &sdkAct.Signal{ - Name: "log", - Metadata: metadata, - } -} - -func Cache() *sdkAct.Signal { - return &sdkAct.Signal{ - Name: "cache", - Metadata: map[string]any{ - "cache": true, - }, - } -} From e2143cfcd0749ab1f9be39e4f35252b4d617f3e6 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sun, 25 Feb 2024 02:39:28 +0100 Subject: [PATCH 12/49] Update SDK --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d9840202..48901c8d 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/NYTimes/gziphandler v1.1.1 github.com/codingsince1985/checksum v1.3.0 github.com/envoyproxy/protoc-gen-validate v1.0.4 - github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.0 + github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.1 github.com/getsentry/sentry-go v0.27.0 github.com/go-co-op/gocron v1.37.0 github.com/google/go-github/v53 v53.2.0 diff --git a/go.sum b/go.sum index 19df162e..2b016326 100644 --- a/go.sum +++ b/go.sum @@ -83,8 +83,8 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.0 h1:JG5FaGn+gj32qvvoou2PNraPB+MfO1Qe01tw4VVUqrY= -github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.0/go.mod h1:1XS2ufw+8VRTHAbDf18Y7rSPlOczeQ/baUWPqJrDkeE= +github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.1 h1:Cwi6A7tb0cI4/puznvHPemffo947IZr4Z2JvIvLYLZk= +github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.1/go.mod h1:1XS2ufw+8VRTHAbDf18Y7rSPlOczeQ/baUWPqJrDkeE= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= From 20322c055f1be1ef5b31106247ed4b8a62614e15 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sun, 25 Feb 2024 15:50:58 +0100 Subject: [PATCH 13/49] Use optional params for action run function --- act/builtins.go | 21 ++++++++++++++++++--- act/registry.go | 11 +++++++++-- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/act/builtins.go b/act/builtins.go index 18b61578..d6516202 100644 --- a/act/builtins.go +++ b/act/builtins.go @@ -30,21 +30,23 @@ var ( Metadata: nil, Sync: true, Terminal: false, - Run: func(_ zerolog.Logger, data map[string]any) (any, error) { return true, nil }, + Run: func(data map[string]any, params ...sdkAct.Parameter) (any, error) { + return true, nil + }, }, { Name: "terminate", Metadata: nil, Sync: true, Terminal: true, - Run: func(_ zerolog.Logger, data map[string]any) (any, error) { return true, nil }, + Run: func(data map[string]any, params ...sdkAct.Parameter) (any, error) { return true, nil }, }, { Name: "log", Metadata: nil, Sync: false, Terminal: false, - Run: func(logger zerolog.Logger, data map[string]any) (any, error) { + Run: func(data map[string]any, params ...sdkAct.Parameter) (any, error) { fields := map[string]any{} // Only log the fields that are not level, message, or log. if len(data) > LOG_DEFAULT_FIELD_COUNT { @@ -55,9 +57,22 @@ var ( fields[k] = v } } + + if len(params) == 0 || params[0].Key != "logger" { + // No logger parameter or the first parameter is not a logger. + return false, nil + } + + logger, ok := params[0].Value.(zerolog.Logger) + if !ok { + // The first parameter is not a logger. + return false, nil + } + logger.WithLevel( logging.GetZeroLogLevel(cast.ToString(data["level"])), ).Fields(fields).Msg(cast.ToString(data["message"])) + return true, nil }, }, diff --git a/act/registry.go b/act/registry.go index 25fb4f6b..b00d5c2f 100644 --- a/act/registry.go +++ b/act/registry.go @@ -155,13 +155,20 @@ func (r *Registry) Run(output *sdkAct.Output) (any, error) { "execution_mode": "sync", "action": action.Name, }).Msgf("Running action") - return action.Run(r.logger, output.Metadata) + return action.Run(output.Metadata, WithLogger(r.logger)) } else { r.logger.Debug().Fields(map[string]interface{}{ "execution_mode": "async", "action": action.Name, }).Msgf("Running action") - go action.Run(r.logger, output.Metadata) + go action.Run(output.Metadata, WithLogger(r.logger)) return nil, nil } } + +func WithLogger(logger zerolog.Logger) sdkAct.Parameter { + return sdkAct.Parameter{ + Key: "logger", + Value: logger, + } +} diff --git a/go.mod b/go.mod index 48901c8d..09105709 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/NYTimes/gziphandler v1.1.1 github.com/codingsince1985/checksum v1.3.0 github.com/envoyproxy/protoc-gen-validate v1.0.4 - github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.1 + github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.2 github.com/getsentry/sentry-go v0.27.0 github.com/go-co-op/gocron v1.37.0 github.com/google/go-github/v53 v53.2.0 diff --git a/go.sum b/go.sum index 2b016326..cb56943a 100644 --- a/go.sum +++ b/go.sum @@ -83,8 +83,8 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.1 h1:Cwi6A7tb0cI4/puznvHPemffo947IZr4Z2JvIvLYLZk= -github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.1/go.mod h1:1XS2ufw+8VRTHAbDf18Y7rSPlOczeQ/baUWPqJrDkeE= +github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.2 h1:3T7ckIBFziTCXb3WKRY9xPNY+FLslD20vzec3xEZL4Y= +github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.2/go.mod h1:1XS2ufw+8VRTHAbDf18Y7rSPlOczeQ/baUWPqJrDkeE= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= From ccb361b72c6fb48bd5d0468f880b3a8cbf58bf79 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sun, 25 Feb 2024 16:55:09 +0100 Subject: [PATCH 14/49] Upgrade to Go v1.22 --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 09105709..2bad9e1a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/gatewayd-io/gatewayd -go 1.21 +go 1.22 require ( github.com/Masterminds/semver/v3 v3.2.1 From cf9bfa066a03ea793681ba00022412475d7dfd5d Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sun, 25 Feb 2024 16:55:22 +0100 Subject: [PATCH 15/49] Pin golangci-lint version and use go install --- .github/workflows/test.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 4edf75dc..ffe10759 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -55,7 +55,9 @@ jobs: - name: Lint code issues 🚨 uses: golangci/golangci-lint-action@v4 with: + version: "v1.56" skip-pkg-cache: true + install-mode: "goinstall" - name: Run Go tests 🔬 run: go test -p 1 -cover -covermode atomic -coverprofile=profile.cov -v ./... From d0f834b3b818aca9b5ec84b5fd4acb35afcd9707 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sun, 25 Feb 2024 16:59:40 +0100 Subject: [PATCH 16/49] Update workflows and Docker image to use Go v0.22 --- .github/workflows/release.yaml | 4 ++-- .github/workflows/test.yaml | 4 ++-- Dockerfile | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 866534b5..928bd34f 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -19,10 +19,10 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Set up Go 1.21 + - name: Set up Go 1.22 uses: actions/setup-go@v5 with: - go-version: "1.21" + go-version: "1.22" cache: true - name: Install nfpm for building Linux packages run: go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ffe10759..39f06ab0 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -50,7 +50,7 @@ jobs: - name: Install Go 🧑‍💻 uses: actions/setup-go@v5 with: - go-version: "1.21" + go-version: "1.22" - name: Lint code issues 🚨 uses: golangci/golangci-lint-action@v4 @@ -98,7 +98,7 @@ jobs: - name: Install Go 🧑‍💻 uses: actions/setup-go@v5 with: - go-version: "1.21" + go-version: "1.22" - name: Checkout test plugin 🛎️ uses: actions/checkout@v4 diff --git a/Dockerfile b/Dockerfile index bdd0386e..d01054db 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 # Use the official golang image to build the binary. -FROM golang:1.21-alpine3.18 as builder +FROM golang:1.22-alpine3.18 as builder ARG TARGETOS ARG TARGETARCH From 12609d24935da6f75f7f058e7231f837f29dee45 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sun, 25 Feb 2024 21:53:09 +0100 Subject: [PATCH 17/49] Use pointer to struct to access fields --- act/registry.go | 2 ++ plugin/plugin_registry.go | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/act/registry.go b/act/registry.go index b00d5c2f..99db774f 100644 --- a/act/registry.go +++ b/act/registry.go @@ -25,6 +25,8 @@ type Registry struct { DefaultPolicy *sdkAct.Policy } +var _ IRegistry = (*Registry)(nil) + // NewRegistry creates a new registry with the specified default policy and timeout. func NewRegistry(defaultPolicy string, timeout time.Duration, logger zerolog.Logger) *Registry { policies := make(map[string]*sdkAct.Policy) diff --git a/plugin/plugin_registry.go b/plugin/plugin_registry.go index fc42273a..bc69cb02 100644 --- a/plugin/plugin_registry.go +++ b/plugin/plugin_registry.go @@ -51,7 +51,7 @@ type IRegistry interface { LoadPlugins(ctx context.Context, plugins []config.Plugin, startTimeout time.Duration) RegisterHooks(ctx context.Context, pluginID sdkPlugin.Identifier) Apply(hookName, priority string, result *v1.Struct) ([]*sdkAct.Output, bool) - PolicyRegistry() act.IRegistry + PolicyRegistry() *act.Registry // Hook management IHook @@ -59,7 +59,7 @@ type IRegistry interface { type Registry struct { plugins pool.IPool - policiesRegistry act.IRegistry + policiesRegistry *act.Registry hooks map[v1.HookName]map[sdkPlugin.Priority]sdkPlugin.Method ctx context.Context //nolint:containedctx devMode bool @@ -75,7 +75,7 @@ var _ IRegistry = (*Registry)(nil) // NewRegistry creates a new plugin registry. func NewRegistry( ctx context.Context, - policiesRegistry act.IRegistry, + policiesRegistry *act.Registry, compatibility config.CompatibilityPolicy, termination config.TerminationPolicy, logger zerolog.Logger, @@ -740,7 +740,7 @@ func (reg *Registry) RegisterHooks(ctx context.Context, pluginID sdkPlugin.Ident } // PolicyRegistry returns the policy registry. -func (reg *Registry) PolicyRegistry() act.IRegistry { +func (reg *Registry) PolicyRegistry() *act.Registry { _, span := otel.Tracer(config.TracerName).Start(reg.ctx, "PolicyRegistry") defer span.End() return reg.policiesRegistry From dced52e6c0b18b4047ba92389334fe01c532bca0 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sun, 25 Feb 2024 21:58:40 +0100 Subject: [PATCH 18/49] Marshal/unmarshal to JSON to deal with time.Duration field --- api/api.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/api/api.go b/api/api.go index 399a73e0..6341bbcf 100644 --- a/api/api.go +++ b/api/api.go @@ -100,7 +100,25 @@ func (a *API) GetGlobalConfig(_ context.Context, group *v1.Group) (*structpb.Str // GetPluginConfig returns the plugin configuration of the GatewayD. func (a *API) GetPluginConfig(context.Context, *emptypb.Empty) (*structpb.Struct, error) { - pluginConfig, err := structpb.NewStruct(a.Config.PluginKoanf.All()) + jsonData, err := json.Marshal(a.Config.PluginKoanf.All()) + if err != nil { + metrics.APIRequestsErrors.WithLabelValues( + "GET", "/v1/GatewayDPluginService/GetPluginConfig", codes.Internal.String(), + ).Inc() + return nil, status.Errorf(codes.Internal, "failed to marshal plugin config: %v", err) + } + + var pluginConfigMap map[string]any + + err = json.Unmarshal(jsonData, &pluginConfigMap) + if err != nil { + metrics.APIRequestsErrors.WithLabelValues( + "GET", "/v1/GatewayDPluginService/GetPluginConfig", codes.Internal.String(), + ).Inc() + return nil, status.Errorf(codes.Internal, "failed to unmarshal plugin config: %v", err) + } + + pluginConfig, err := structpb.NewStruct(pluginConfigMap) if err != nil { metrics.APIRequestsErrors.WithLabelValues( "GET", "/v1/GatewayDPluginService/GetPluginConfig", codes.Internal.String(), From e564acee5a2f53e24fb1b0ec8fdf158f6581e0e0 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sun, 25 Feb 2024 22:07:03 +0100 Subject: [PATCH 19/49] Use the latest main branch to fix issues before release --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2bad9e1a..63594ca3 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/invopop/jsonschema v0.12.0 github.com/knadh/koanf v1.5.0 github.com/mitchellh/mapstructure v1.5.0 - github.com/prometheus/client_golang v1.18.0 + github.com/prometheus/client_golang v1.18.1-0.20240223185837-14259fa70cfb github.com/prometheus/client_model v0.6.0 github.com/prometheus/common v0.48.0 github.com/rs/zerolog v1.32.0 diff --git a/go.sum b/go.sum index cb56943a..05d6062c 100644 --- a/go.sum +++ b/go.sum @@ -302,8 +302,8 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.18.1-0.20240223185837-14259fa70cfb h1:RQ5Z0SNTwzo4QbNg+3UWZ4JB6ioYOhX41gKAUnHDVVY= +github.com/prometheus/client_golang v1.18.1-0.20240223185837-14259fa70cfb/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= From 217a73529aea28145c8db808a3e9bb8230b040ee Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Sun, 25 Feb 2024 22:32:54 +0100 Subject: [PATCH 20/49] Fix linter errors and improve code --- act/builtins.go | 10 +++---- act/registry.go | 58 +++++++++++++++++++++++---------------- errors/errors.go | 17 ++++++++++++ network/proxy.go | 12 ++++++-- plugin/plugin_registry.go | 16 +++-------- plugin/utils.go | 2 +- 6 files changed, 70 insertions(+), 45 deletions(-) diff --git a/act/builtins.go b/act/builtins.go index d6516202..50bc1e39 100644 --- a/act/builtins.go +++ b/act/builtins.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cast" ) -const LOG_DEFAULT_FIELD_COUNT = 3 +const LogDefaultFieldCount = 3 var ( builtinsPolicies = []*sdkAct.Policy{ @@ -30,16 +30,14 @@ var ( Metadata: nil, Sync: true, Terminal: false, - Run: func(data map[string]any, params ...sdkAct.Parameter) (any, error) { - return true, nil - }, + Run: func(map[string]any, ...sdkAct.Parameter) (any, error) { return true, nil }, }, { Name: "terminate", Metadata: nil, Sync: true, Terminal: true, - Run: func(data map[string]any, params ...sdkAct.Parameter) (any, error) { return true, nil }, + Run: func(map[string]any, ...sdkAct.Parameter) (any, error) { return true, nil }, }, { Name: "log", @@ -49,7 +47,7 @@ var ( Run: func(data map[string]any, params ...sdkAct.Parameter) (any, error) { fields := map[string]any{} // Only log the fields that are not level, message, or log. - if len(data) > LOG_DEFAULT_FIELD_COUNT { + if len(data) > LogDefaultFieldCount { for k, v := range data { if k == "level" || k == "message" || k == "log" { continue diff --git a/act/registry.go b/act/registry.go index 99db774f..009e9bd3 100644 --- a/act/registry.go +++ b/act/registry.go @@ -2,17 +2,17 @@ package act import ( "context" - "errors" "time" sdkAct "github.com/gatewayd-io/gatewayd-plugin-sdk/act" + gerr "github.com/gatewayd-io/gatewayd/errors" "github.com/rs/zerolog" ) type IRegistry interface { Add(policy *sdkAct.Policy) Apply(signals []sdkAct.Signal) []*sdkAct.Output - Run(output *sdkAct.Output) (any, error) + Run(output *sdkAct.Output) (any, *gerr.GatewayDError) } // Registry keeps track of all policies and actions. @@ -102,15 +102,15 @@ func (r *Registry) Apply(signals []sdkAct.Signal) []*sdkAct.Output { } // apply applies the signal to the registry and returns the output. -func (r *Registry) apply(signal sdkAct.Signal) (*sdkAct.Output, error) { - action, ok := r.Actions[signal.Name] - if !ok { - return nil, errors.New("No matching action") +func (r *Registry) apply(signal sdkAct.Signal) (*sdkAct.Output, *gerr.GatewayDError) { + action, exists := r.Actions[signal.Name] + if !exists { + return nil, gerr.ErrActionNotMatched } - policy, ok := r.Policies[action.Name] - if !ok { - return nil, errors.New("No matching policy") + policy, exists := r.Policies[action.Name] + if !exists { + return nil, gerr.ErrPolicyNotMatched } ctx, cancel := context.WithTimeout(context.Background(), r.timeout) @@ -126,7 +126,7 @@ func (r *Registry) apply(signal sdkAct.Signal) (*sdkAct.Output, error) { }, ) if err != nil { - return nil, err + return nil, gerr.ErrEvalError.Wrap(err) } return &sdkAct.Output{ @@ -139,17 +139,18 @@ func (r *Registry) apply(signal sdkAct.Signal) (*sdkAct.Output, error) { } // Run runs the output and returns the result. -func (r *Registry) Run(output *sdkAct.Output) (any, error) { +func (r *Registry) Run(output *sdkAct.Output) (any, *gerr.GatewayDError) { if output == nil { - r.logger.Warn().Msg("Output is nil, not running") - return nil, errors.New("Output is nil") + r.logger.Warn().Msg("Output is nil, run aborted") + // TODO: Run the default action of the default policy. + return nil, gerr.ErrNilPointer } action, ok := r.Actions[output.MatchedPolicy] if !ok { r.logger.Warn().Str("matched_policy", output.MatchedPolicy).Msg( - "Action does not exist, not running") - return nil, errors.New("Action does not exist") + "Action does not exist, run aborted") + return nil, gerr.ErrActionNotExist } if action.Sync { @@ -157,15 +158,26 @@ func (r *Registry) Run(output *sdkAct.Output) (any, error) { "execution_mode": "sync", "action": action.Name, }).Msgf("Running action") - return action.Run(output.Metadata, WithLogger(r.logger)) - } else { - r.logger.Debug().Fields(map[string]interface{}{ - "execution_mode": "async", - "action": action.Name, - }).Msgf("Running action") - go action.Run(output.Metadata, WithLogger(r.logger)) - return nil, nil + output, err := action.Run(output.Metadata, WithLogger(r.logger)) + if err != nil { + r.logger.Error().Err(err).Str("action", action.Name).Msg("Error running action") + } + return output, gerr.ErrRunningAction.Wrap(err) } + + r.logger.Debug().Fields(map[string]interface{}{ + "execution_mode": "async", + "action": action.Name, + }).Msgf("Running action") + + go func(action *sdkAct.Action, output *sdkAct.Output, logger zerolog.Logger) { + _, err := action.Run(output.Metadata, WithLogger(logger)) + if err != nil { + logger.Error().Err(err).Str("action", action.Name).Msg("Error running action") + } + }(action, output, r.logger) + + return nil, gerr.ErrAsyncAction } func WithLogger(logger zerolog.Logger) sdkAct.Parameter { diff --git a/errors/errors.go b/errors/errors.go index 896ab170..606b6d20 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -41,6 +41,10 @@ const ( ErrCodeLintingFailed ErrCodeExtractFailed ErrCodeDownloadFailed + ErrCodeKeyNotFound + ErrCodeRunError + ErrCodeAsyncAction + ErrCodeEvalError ) var ( @@ -133,6 +137,19 @@ var ( ErrCodeExtractFailed, "failed to extract the archive", nil) ErrDownloadFailed = NewGatewayDError( ErrCodeDownloadFailed, "failed to download the file", nil) + + ErrActionNotExist = NewGatewayDError( + ErrCodeKeyNotFound, "action does not exist", nil) + ErrRunningAction = NewGatewayDError( + ErrCodeRunError, "error running action", nil) + ErrAsyncAction = NewGatewayDError( + ErrCodeAsyncAction, "async action", nil) + ErrActionNotMatched = NewGatewayDError( + ErrCodeKeyNotFound, "no matching action", nil) + ErrPolicyNotMatched = NewGatewayDError( + ErrCodeKeyNotFound, "no matching policy", nil) + ErrEvalError = NewGatewayDError( + ErrCodeEvalError, "error evaluating expression", nil) ) const ( diff --git a/network/proxy.go b/network/proxy.go index 34953426..ffc92fb8 100644 --- a/network/proxy.go +++ b/network/proxy.go @@ -19,6 +19,7 @@ import ( "github.com/getsentry/sentry-go" "github.com/go-co-op/gocron" "github.com/rs/zerolog" + "github.com/spf13/cast" "go.opentelemetry.io/otel" "golang.org/x/exp/maps" ) @@ -834,6 +835,12 @@ func (pr *Proxy) shouldTerminate(result map[string]interface{}) bool { return false } + outputs, ok := result[act.Outputs].([]*act.Output) + if !ok { + pr.logger.Error().Msg("Failed to cast the outputs to the []*act.Output type") + return false + } + keys := maps.Keys(result) // This is a shortcut to avoid running the actions' functions. // The terminate field is only present if the action wants to terminate the request, @@ -846,18 +853,17 @@ func (pr *Proxy) shouldTerminate(result map[string]interface{}) bool { pr.logger.Error().Err(err).Msg("Error running policy") } } - }(result[act.Outputs].([]*act.Output)) + }(outputs) pr.logger.Debug().Fields( map[string]interface{}{ "function": "proxy.passthrough", "reason": "terminate", }, ).Msg("Terminating request") - return result[act.Terminal].(bool) + return cast.ToBool(result[act.Terminal]) } // If the hook wants to terminate the request, do it. - outputs := result[act.Outputs].([]*act.Output) for _, output := range outputs { if output.MatchedPolicy == "terminate" && output.Verdict { pr.logger.Debug().Fields( diff --git a/plugin/plugin_registry.go b/plugin/plugin_registry.go index bc69cb02..fcf3f250 100644 --- a/plugin/plugin_registry.go +++ b/plugin/plugin_registry.go @@ -4,7 +4,6 @@ import ( "context" "crypto/sha256" "encoding/hex" - "fmt" "sort" "time" @@ -50,7 +49,7 @@ type IRegistry interface { Shutdown() LoadPlugins(ctx context.Context, plugins []config.Plugin, startTimeout time.Duration) RegisterHooks(ctx context.Context, pluginID sdkPlugin.Identifier) - Apply(hookName, priority string, result *v1.Struct) ([]*sdkAct.Output, bool) + Apply(hookName string, result *v1.Struct) ([]*sdkAct.Output, bool) PolicyRegistry() *act.Registry // Hook management @@ -337,7 +336,7 @@ func (reg *Registry) Run( continue } - out, terminal := reg.Apply(hookName.String(), fmt.Sprint(priority), result) + out, terminal := reg.Apply(hookName.String(), result) outputs = append(outputs, out...) if terminal { @@ -360,14 +359,12 @@ func (reg *Registry) Run( } // Apply applies policies to the result. -func (reg *Registry) Apply( - hookName, priority string, result *v1.Struct, -) ([]*sdkAct.Output, bool) { +func (reg *Registry) Apply(hookName string, result *v1.Struct) ([]*sdkAct.Output, bool) { _, span := otel.Tracer(config.TracerName).Start(reg.ctx, "Apply") defer span.End() // Get signals from the result. - signals := GetSignals(result.AsMap(), reg.Logger, reg.PolicyRegistry()) + signals := GetSignals(result.AsMap()) // Apply policies to the signals. // The outputs contains the verdicts of the policies and their metadata. // And using this list, the caller can take further actions. @@ -382,11 +379,6 @@ func (reg *Registry) Apply( // Check if any of the policies have a terminal action. var terminal bool for _, output := range outputs { - // if output.Verdict && output.MatchedPolicy == "log" { - // reg.Logger.Debug().Msgf("Log: %+v", output.Metadata) - // reg.PolicyRegistry().Run(output) - // } - if output.Verdict && output.Terminal { terminal = true break diff --git a/plugin/utils.go b/plugin/utils.go index e4d25898..4314a5f8 100644 --- a/plugin/utils.go +++ b/plugin/utils.go @@ -52,7 +52,7 @@ func CastToPrimitiveTypes(args map[string]interface{}) map[string]interface{} { } // GetSignals decodes the signals from the result map and returns them as a list of Signal objects. -func GetSignals(result map[string]any, logger zerolog.Logger, reg act.IRegistry) []sdkAct.Signal { +func GetSignals(result map[string]any) []sdkAct.Signal { decodedSignals := []sdkAct.Signal{} if signals, ok := result[sdkAct.Signals]; ok { From c9732828e50a4c3ac6fa6e37dd3617ca8b5b9fea Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Mon, 26 Feb 2024 21:38:34 +0100 Subject: [PATCH 21/49] Error sentinel is safe to be bypassed --- network/proxy.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/network/proxy.go b/network/proxy.go index ffc92fb8..597bd394 100644 --- a/network/proxy.go +++ b/network/proxy.go @@ -849,7 +849,9 @@ func (pr *Proxy) shouldTerminate(result map[string]interface{}) bool { go func(outputs []*act.Output) { for _, output := range outputs { _, err := pr.pluginRegistry.PolicyRegistry().Run(output) - if err != nil { + // If the action is async and we received a sentinel error, + // don't log the error. + if err != nil && !errors.Is(err, gerr.ErrAsyncAction) { pr.logger.Error().Err(err).Msg("Error running policy") } } From 6dc84d7aa9e9abaf791c6a8a7250787c1169a6a4 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Mon, 26 Feb 2024 21:39:10 +0100 Subject: [PATCH 22/49] Run default signal, action and policy --- act/builtins.go | 15 +++++---------- act/registry.go | 24 +++++++++++++++++------- go.mod | 4 ++-- go.sum | 8 ++++---- plugin/plugin_registry.go | 1 + plugin/utils.go | 4 ---- 6 files changed, 29 insertions(+), 27 deletions(-) diff --git a/act/builtins.go b/act/builtins.go index 50bc1e39..8c741bf7 100644 --- a/act/builtins.go +++ b/act/builtins.go @@ -10,6 +10,11 @@ import ( const LogDefaultFieldCount = 3 var ( + builtinSignals = []*sdkAct.Signal{ + sdkAct.Passthrough(), + sdkAct.Terminate(), + } + builtinsPolicies = []*sdkAct.Policy{ sdkAct.MustNewPolicy("passthrough", "true", nil), sdkAct.MustNewPolicy( @@ -75,14 +80,4 @@ var ( }, }, } - - // TODO: figure out if the default output should match the default policy. - DefaultOutput = func() *sdkAct.Output { - return &sdkAct.Output{ - MatchedPolicy: "passthrough", - Verdict: true, - Terminal: false, - Sync: true, - } - } ) diff --git a/act/registry.go b/act/registry.go index 009e9bd3..6ad96d37 100644 --- a/act/registry.go +++ b/act/registry.go @@ -20,15 +20,23 @@ type Registry struct { logger zerolog.Logger timeout time.Duration // Timeout for policy evaluation + Signals map[string]*sdkAct.Signal Policies map[string]*sdkAct.Policy Actions map[string]*sdkAct.Action DefaultPolicy *sdkAct.Policy + DefaultSignal *sdkAct.Signal } var _ IRegistry = (*Registry)(nil) // NewRegistry creates a new registry with the specified default policy and timeout. func NewRegistry(defaultPolicy string, timeout time.Duration, logger zerolog.Logger) *Registry { + signals := make(map[string]*sdkAct.Signal) + for _, signal := range builtinSignals { + signals[signal.Name] = signal + logger.Debug().Str("name", signal.Name).Msg("Registered builtin signal") + } + policies := make(map[string]*sdkAct.Policy) for _, policy := range builtinsPolicies { policies[policy.Name] = policy @@ -48,12 +56,16 @@ func NewRegistry(defaultPolicy string, timeout time.Duration, logger zerolog.Log defaultPolicy = "passthrough" } + logger.Debug().Str("name", defaultPolicy).Msg("Using default policy") + return &Registry{ logger: logger, timeout: timeout, + Signals: signals, Actions: actions, Policies: policies, DefaultPolicy: policies[defaultPolicy], + DefaultSignal: signals[defaultPolicy], } } @@ -74,12 +86,9 @@ func (r *Registry) Add(policy *sdkAct.Policy) { // Apply applies the signals to the registry and returns the outputs. func (r *Registry) Apply(signals []sdkAct.Signal) []*sdkAct.Output { - DefaultOutputs := []*sdkAct.Output{ - DefaultOutput(), - } - + // If there are no signals, apply the default policy. if len(signals) == 0 { - return DefaultOutputs + return r.Apply([]sdkAct.Signal{*r.DefaultSignal}) } // TODO: Check for non-contradictory actions (forward vs. drop) @@ -95,7 +104,7 @@ func (r *Registry) Apply(signals []sdkAct.Signal) []*sdkAct.Output { } if len(outputs) == 0 { - return DefaultOutputs + return r.Apply([]sdkAct.Signal{*r.DefaultSignal}) } return outputs @@ -161,8 +170,9 @@ func (r *Registry) Run(output *sdkAct.Output) (any, *gerr.GatewayDError) { output, err := action.Run(output.Metadata, WithLogger(r.logger)) if err != nil { r.logger.Error().Err(err).Str("action", action.Name).Msg("Error running action") + return output, gerr.ErrRunningAction.Wrap(err) } - return output, gerr.ErrRunningAction.Wrap(err) + return output, nil } r.logger.Debug().Fields(map[string]interface{}{ diff --git a/go.mod b/go.mod index 63594ca3..12bc3d4d 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/NYTimes/gziphandler v1.1.1 github.com/codingsince1985/checksum v1.3.0 github.com/envoyproxy/protoc-gen-validate v1.0.4 - github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.2 + github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.3 github.com/getsentry/sentry-go v0.27.0 github.com/go-co-op/gocron v1.37.0 github.com/google/go-github/v53 v53.2.0 @@ -75,7 +75,7 @@ require ( go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.1.0 // indirect go.uber.org/atomic v1.11.0 // indirect - golang.org/x/crypto v0.19.0 // indirect + golang.org/x/crypto v0.20.0 // indirect golang.org/x/net v0.21.0 // indirect golang.org/x/oauth2 v0.17.0 // indirect golang.org/x/sys v0.17.0 // indirect diff --git a/go.sum b/go.sum index 05d6062c..dd6803e6 100644 --- a/go.sum +++ b/go.sum @@ -83,8 +83,8 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.2 h1:3T7ckIBFziTCXb3WKRY9xPNY+FLslD20vzec3xEZL4Y= -github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.2/go.mod h1:1XS2ufw+8VRTHAbDf18Y7rSPlOczeQ/baUWPqJrDkeE= +github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.3 h1:TzPoseln2War6SzqiJ/3HSceSB5vbJ9gCECz7Wy7pqE= +github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.3/go.mod h1:1XS2ufw+8VRTHAbDf18Y7rSPlOczeQ/baUWPqJrDkeE= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -404,8 +404,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= diff --git a/plugin/plugin_registry.go b/plugin/plugin_registry.go index fcf3f250..c33663ab 100644 --- a/plugin/plugin_registry.go +++ b/plugin/plugin_registry.go @@ -371,6 +371,7 @@ func (reg *Registry) Apply(hookName string, result *v1.Struct) ([]*sdkAct.Output outputs := ApplyPolicies(hookName, signals, reg.Logger, reg.PolicyRegistry()) // If no policies are found, return a default output. + // Note: this should never happen, as the default policy is always loaded. if len(outputs) == 0 { reg.Logger.Debug().Msg("No policies found for the given signals") return nil, false diff --git a/plugin/utils.go b/plugin/utils.go index 4314a5f8..33904202 100644 --- a/plugin/utils.go +++ b/plugin/utils.go @@ -79,10 +79,6 @@ func GetSignals(result map[string]any) []sdkAct.Signal { func ApplyPolicies( hookName string, signals []sdkAct.Signal, logger zerolog.Logger, reg act.IRegistry, ) []*sdkAct.Output { - if len(signals) == 0 { - return nil - } - signalNames := []string{} for _, signal := range signals { signalNames = append(signalNames, signal.Name) From 122e12afcc35ce089df8083b355ebc39cb352f37 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Mon, 26 Feb 2024 22:01:36 +0100 Subject: [PATCH 23/49] Actions now receive the result map from the traffic hooks (onTrafficFromClient for now) --- act/registry.go | 29 +++++++++++++++++++++++------ network/proxy.go | 13 +++++++------ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/act/registry.go b/act/registry.go index 6ad96d37..1a9c4065 100644 --- a/act/registry.go +++ b/act/registry.go @@ -12,7 +12,7 @@ import ( type IRegistry interface { Add(policy *sdkAct.Policy) Apply(signals []sdkAct.Signal) []*sdkAct.Output - Run(output *sdkAct.Output) (any, *gerr.GatewayDError) + Run(output *sdkAct.Output, params ...sdkAct.Parameter) (any, *gerr.GatewayDError) } // Registry keeps track of all policies and actions. @@ -148,7 +148,9 @@ func (r *Registry) apply(signal sdkAct.Signal) (*sdkAct.Output, *gerr.GatewayDEr } // Run runs the output and returns the result. -func (r *Registry) Run(output *sdkAct.Output) (any, *gerr.GatewayDError) { +func (r *Registry) Run( + output *sdkAct.Output, params ...sdkAct.Parameter, +) (any, *gerr.GatewayDError) { if output == nil { r.logger.Warn().Msg("Output is nil, run aborted") // TODO: Run the default action of the default policy. @@ -162,12 +164,15 @@ func (r *Registry) Run(output *sdkAct.Output) (any, *gerr.GatewayDError) { return nil, gerr.ErrActionNotExist } + // Prepend the logger to the parameters. + params = append([]sdkAct.Parameter{WithLogger(r.logger)}, params...) + if action.Sync { r.logger.Debug().Fields(map[string]interface{}{ "execution_mode": "sync", "action": action.Name, }).Msgf("Running action") - output, err := action.Run(output.Metadata, WithLogger(r.logger)) + output, err := action.Run(output.Metadata, params...) if err != nil { r.logger.Error().Err(err).Str("action", action.Name).Msg("Error running action") return output, gerr.ErrRunningAction.Wrap(err) @@ -180,12 +185,17 @@ func (r *Registry) Run(output *sdkAct.Output) (any, *gerr.GatewayDError) { "action": action.Name, }).Msgf("Running action") - go func(action *sdkAct.Action, output *sdkAct.Output, logger zerolog.Logger) { - _, err := action.Run(output.Metadata, WithLogger(logger)) + go func( + action *sdkAct.Action, + output *sdkAct.Output, + params []sdkAct.Parameter, + logger zerolog.Logger, + ) { + _, err := action.Run(output.Metadata, params...) if err != nil { logger.Error().Err(err).Str("action", action.Name).Msg("Error running action") } - }(action, output, r.logger) + }(action, output, params, r.logger) return nil, gerr.ErrAsyncAction } @@ -196,3 +206,10 @@ func WithLogger(logger zerolog.Logger) sdkAct.Parameter { Value: logger, } } + +func WithResult(result map[string]any) sdkAct.Parameter { + return sdkAct.Parameter{ + Key: "result", + Value: result, + } +} diff --git a/network/proxy.go b/network/proxy.go index 597bd394..6ab22dbb 100644 --- a/network/proxy.go +++ b/network/proxy.go @@ -9,8 +9,9 @@ import ( "slices" "time" - "github.com/gatewayd-io/gatewayd-plugin-sdk/act" + sdkAct "github.com/gatewayd-io/gatewayd-plugin-sdk/act" v1 "github.com/gatewayd-io/gatewayd-plugin-sdk/plugin/v1" + "github.com/gatewayd-io/gatewayd/act" "github.com/gatewayd-io/gatewayd/config" gerr "github.com/gatewayd-io/gatewayd/errors" "github.com/gatewayd-io/gatewayd/metrics" @@ -835,7 +836,7 @@ func (pr *Proxy) shouldTerminate(result map[string]interface{}) bool { return false } - outputs, ok := result[act.Outputs].([]*act.Output) + outputs, ok := result[sdkAct.Outputs].([]*sdkAct.Output) if !ok { pr.logger.Error().Msg("Failed to cast the outputs to the []*act.Output type") return false @@ -845,10 +846,10 @@ func (pr *Proxy) shouldTerminate(result map[string]interface{}) bool { // This is a shortcut to avoid running the actions' functions. // The terminate field is only present if the action wants to terminate the request, // that is the `Terminate` field is set in one of the outputs. - if slices.Contains(keys, act.Terminal) { - go func(outputs []*act.Output) { + if slices.Contains(keys, sdkAct.Terminal) { + go func(outputs []*sdkAct.Output) { for _, output := range outputs { - _, err := pr.pluginRegistry.PolicyRegistry().Run(output) + _, err := pr.pluginRegistry.PolicyRegistry().Run(output, act.WithResult(result)) // If the action is async and we received a sentinel error, // don't log the error. if err != nil && !errors.Is(err, gerr.ErrAsyncAction) { @@ -862,7 +863,7 @@ func (pr *Proxy) shouldTerminate(result map[string]interface{}) bool { "reason": "terminate", }, ).Msg("Terminating request") - return cast.ToBool(result[act.Terminal]) + return cast.ToBool(result[sdkAct.Terminal]) } // If the hook wants to terminate the request, do it. From d6fa8fd2b43046fefe15a908d315a6a7e8e2c634 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Tue, 27 Feb 2024 22:15:54 +0100 Subject: [PATCH 24/49] Lower log level and add clarifying comment --- act/registry.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/act/registry.go b/act/registry.go index 1a9c4065..d5450735 100644 --- a/act/registry.go +++ b/act/registry.go @@ -152,8 +152,9 @@ func (r *Registry) Run( output *sdkAct.Output, params ...sdkAct.Parameter, ) (any, *gerr.GatewayDError) { if output == nil { - r.logger.Warn().Msg("Output is nil, run aborted") - // TODO: Run the default action of the default policy. + // This should never happen, since the output is always set by the registry + // to be the default policy if no signals are provided. + r.logger.Debug().Msg("Output is nil, run aborted") return nil, gerr.ErrNilPointer } From 6ee9b82f361fccbc6a9200dfd1d90ecf12f2525e Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Tue, 27 Feb 2024 23:59:48 +0100 Subject: [PATCH 25/49] Terminate connection with an error response if none is provided by the plugin Don't return any output when there is an error running the action Add pgx to allow list Refactor action functions into separate functions --- .golangci.yaml | 1 + act/builtins.go | 122 ++++++++++++++++++++++++++++++++++------------- act/registry.go | 2 +- errors/errors.go | 5 ++ go.mod | 4 ++ go.sum | 13 +++++ network/proxy.go | 55 +++++++++++++-------- 7 files changed, 150 insertions(+), 52 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 73f3372e..0f836393 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -69,6 +69,7 @@ linters-settings: - "github.com/zenizh/go-capturer" - "gopkg.in/natefinch/lumberjack.v2" - "github.com/expr-lang/expr" + - "github.com/jackc/pgx/v5/pgproto3" test: files: - $test diff --git a/act/builtins.go b/act/builtins.go index 8c741bf7..9d55a2a1 100644 --- a/act/builtins.go +++ b/act/builtins.go @@ -2,13 +2,20 @@ package act import ( sdkAct "github.com/gatewayd-io/gatewayd-plugin-sdk/act" + "github.com/gatewayd-io/gatewayd-plugin-sdk/databases/postgres" "github.com/gatewayd-io/gatewayd-plugin-sdk/logging" + gerr "github.com/gatewayd-io/gatewayd/errors" + "github.com/jackc/pgx/v5/pgproto3" "github.com/rs/zerolog" "github.com/spf13/cast" ) -const LogDefaultFieldCount = 3 +const ( + LogDefaultFieldCount = 3 + TerminateDefaultFieldCount = 2 +) +// TODO: Should we get rid of global variables? var ( builtinSignals = []*sdkAct.Signal{ sdkAct.Passthrough(), @@ -35,49 +42,100 @@ var ( Metadata: nil, Sync: true, Terminal: false, - Run: func(map[string]any, ...sdkAct.Parameter) (any, error) { return true, nil }, + Run: passthrough, }, { Name: "terminate", Metadata: nil, Sync: true, Terminal: true, - Run: func(map[string]any, ...sdkAct.Parameter) (any, error) { return true, nil }, + Run: terminate, }, { Name: "log", Metadata: nil, Sync: false, Terminal: false, - Run: func(data map[string]any, params ...sdkAct.Parameter) (any, error) { - fields := map[string]any{} - // Only log the fields that are not level, message, or log. - if len(data) > LogDefaultFieldCount { - for k, v := range data { - if k == "level" || k == "message" || k == "log" { - continue - } - fields[k] = v - } - } - - if len(params) == 0 || params[0].Key != "logger" { - // No logger parameter or the first parameter is not a logger. - return false, nil - } - - logger, ok := params[0].Value.(zerolog.Logger) - if !ok { - // The first parameter is not a logger. - return false, nil - } - - logger.WithLevel( - logging.GetZeroLogLevel(cast.ToString(data["level"])), - ).Fields(fields).Msg(cast.ToString(data["message"])) - - return true, nil - }, + Run: log, }, } ) + +func passthrough(data map[string]any, params ...sdkAct.Parameter) (any, error) { + return true, nil +} + +func terminate(data map[string]any, params ...sdkAct.Parameter) (any, error) { + if len(params) == 0 || params[0].Key != "logger" { + return nil, gerr.ErrLoggerRequired + } + + logger, ok := params[0].Value.(zerolog.Logger) + if !ok { + return nil, gerr.ErrLoggerRequired + } + + if len(params) >= TerminateDefaultFieldCount { + if params[1].Key != "result" { + logger.Debug().Msg( + "terminate action can optionally receive a result parameter") + return true, nil + } + + result, ok := params[1].Value.(map[string]any) + if !ok { + logger.Debug().Msg("terminate action can receive a result parameter") + return true, nil + } + + // If the result from the plugin does not contain a response, + // yet it is a terminal action (hence running this action), + // add an error response to the result and terminate the connection. + if _, exists := result["response"]; !exists { + logger.Trace().Fields(result).Msg( + "Terminating without response, returning an error response") + result["response"] = (&pgproto3.Terminate{}).Encode( + postgres.ErrorResponse( + "Request terminated", + "ERROR", + "42000", + "Policy terminated the request", + ), + ) + } + + return result, nil + } + + return true, nil +} + +func log(data map[string]any, params ...sdkAct.Parameter) (any, error) { + fields := map[string]any{} + // Only log the fields that are not level, message, or log. + if len(data) > LogDefaultFieldCount { + for k, v := range data { + if k == "level" || k == "message" || k == "log" { + continue + } + fields[k] = v + } + } + + if len(params) == 0 || params[0].Key != "logger" { + // No logger parameter or the first parameter is not a logger. + return false, nil + } + + logger, ok := params[0].Value.(zerolog.Logger) + if !ok { + // The first parameter is not a logger. + return false, nil + } + + logger.WithLevel( + logging.GetZeroLogLevel(cast.ToString(data["level"])), + ).Fields(fields).Msg(cast.ToString(data["message"])) + + return true, nil +} diff --git a/act/registry.go b/act/registry.go index d5450735..a3c0d605 100644 --- a/act/registry.go +++ b/act/registry.go @@ -176,7 +176,7 @@ func (r *Registry) Run( output, err := action.Run(output.Metadata, params...) if err != nil { r.logger.Error().Err(err).Str("action", action.Name).Msg("Error running action") - return output, gerr.ErrRunningAction.Wrap(err) + return nil, gerr.ErrRunningAction.Wrap(err) } return output, nil } diff --git a/errors/errors.go b/errors/errors.go index 606b6d20..84b631f0 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -1,5 +1,7 @@ package errors +import "errors" + const ( ErrCodeUnknown ErrCode = iota ErrCodeNilContext @@ -150,6 +152,9 @@ var ( ErrCodeKeyNotFound, "no matching policy", nil) ErrEvalError = NewGatewayDError( ErrCodeEvalError, "error evaluating expression", nil) + + // Unwrapped errors. + ErrLoggerRequired = errors.New("terminate action requires a logger parameter") ) const ( diff --git a/go.mod b/go.mod index 12bc3d4d..04f6b93a 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/hashicorp/go-hclog v1.6.2 github.com/hashicorp/go-plugin v1.6.0 github.com/invopop/jsonschema v0.12.0 + github.com/jackc/pgx/v5 v5.5.3 github.com/knadh/koanf v1.5.0 github.com/mitchellh/mapstructure v1.5.0 github.com/prometheus/client_golang v1.18.1-0.20240223185837-14259fa70cfb @@ -67,10 +68,13 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/oklog/run v1.1.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pganalyze/pg_query_go/v5 v5.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/tetratelabs/wazero v1.6.1-0.20240124004658-4185e533bb18 // indirect + github.com/wasilibs/go-pgquery v0.0.0-20240124010238-c9a912d768dc // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.1.0 // indirect diff --git a/go.sum b/go.sum index dd6803e6..9a1659c2 100644 --- a/go.sum +++ b/go.sum @@ -200,6 +200,12 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.5.3 h1:Ces6/M3wbDXYpM8JyyPD57ivTtJACFZJd885pdIaV2s= +github.com/jackc/pgx/v5 v5.5.3/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -286,6 +292,8 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pganalyze/pg_query_go/v5 v5.1.0 h1:MlxQqHZnvA3cbRQYyIrjxEjzo560P6MyTgtlaf3pmXg= +github.com/pganalyze/pg_query_go/v5 v5.1.0/go.mod h1:FsglvxidZsVN+Ltw3Ai6nTgPVcK2BPukH3jCDEqc1Ug= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= @@ -363,6 +371,10 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.1-0.20240124004658-4185e533bb18 h1:Gi/arySP4fsMGdfv1uLMBZ59P4trxQVybzo/jEmqSOE= +github.com/tetratelabs/wazero v1.6.1-0.20240124004658-4185e533bb18/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= +github.com/wasilibs/go-pgquery v0.0.0-20240124010238-c9a912d768dc h1:maN7B5k6qQd8JwyW9W4UjZ9J+30MNn1phiM5GeKdy+g= +github.com/wasilibs/go-pgquery v0.0.0-20240124010238-c9a912d768dc/go.mod h1:EdrSnP/ky2/FikNtQkVR+dTESNjbeY9TqLlxsRCddC8= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -575,6 +587,7 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= diff --git a/network/proxy.go b/network/proxy.go index 6ab22dbb..f3a9670f 100644 --- a/network/proxy.go +++ b/network/proxy.go @@ -391,7 +391,19 @@ func (pr *Proxy) PassThroughToServer(conn *ConnWrapper, stack *Stack) *gerr.Gate // If the hook wants to terminate the connection, do it. // TODO: Should the output be reconstructed here? Or should it be done in the plugin registry? - if pr.shouldTerminate(result) { + if terminate, resp := pr.shouldTerminate(result); terminate { + if resp != nil { + pr.logger.Trace().Fields( + map[string]interface{}{ + "function": "proxy.passthrough", + "result": resp, + }, + ).Msg("Terminating connection with a result from the action") + + // If the terminate action returned a result, use it. + result = resp + } + if modResponse, modReceived := pr.getPluginModifiedResponse(result); modResponse != nil { metrics.ProxyPassThroughsToClient.Inc() metrics.ProxyPassThroughTerminations.Inc() @@ -828,42 +840,47 @@ func (pr *Proxy) sendTrafficToClient( // shouldTerminate is a function that retrieves the terminate field from the hook result. // Only the OnTrafficFromClient hook will terminate the request. -func (pr *Proxy) shouldTerminate(result map[string]interface{}) bool { +func (pr *Proxy) shouldTerminate(result map[string]interface{}) (bool, map[string]interface{}) { _, span := otel.Tracer(config.TracerName).Start(pr.ctx, "shouldTerminate") defer span.End() if result == nil { - return false + return false, result } outputs, ok := result[sdkAct.Outputs].([]*sdkAct.Output) if !ok { pr.logger.Error().Msg("Failed to cast the outputs to the []*act.Output type") - return false + return false, result } - keys := maps.Keys(result) // This is a shortcut to avoid running the actions' functions. - // The terminate field is only present if the action wants to terminate the request, - // that is the `Terminate` field is set in one of the outputs. + // The Terminal field is only present if the action wants to terminate the request, + // that is the `__terminal__` field is set in one of the outputs. + keys := maps.Keys(result) if slices.Contains(keys, sdkAct.Terminal) { - go func(outputs []*sdkAct.Output) { - for _, output := range outputs { - _, err := pr.pluginRegistry.PolicyRegistry().Run(output, act.WithResult(result)) - // If the action is async and we received a sentinel error, - // don't log the error. - if err != nil && !errors.Is(err, gerr.ErrAsyncAction) { - pr.logger.Error().Err(err).Msg("Error running policy") - } + var actionResult map[string]interface{} + for _, output := range outputs { + actRes, err := pr.pluginRegistry.PolicyRegistry().Run( + output, act.WithResult(result)) + // If the action is async and we received a sentinel error, + // don't log the error. + if err != nil && !errors.Is(err, gerr.ErrAsyncAction) { + pr.logger.Error().Err(err).Msg("Error running policy") + } + // The terminate action should return a map. + switch v := actRes.(type) { + case map[string]interface{}: + actionResult = v } - }(outputs) + } pr.logger.Debug().Fields( map[string]interface{}{ "function": "proxy.passthrough", "reason": "terminate", }, ).Msg("Terminating request") - return cast.ToBool(result[sdkAct.Terminal]) + return cast.ToBool(result[sdkAct.Terminal]), actionResult } // If the hook wants to terminate the request, do it. @@ -878,11 +895,11 @@ func (pr *Proxy) shouldTerminate(result map[string]interface{}) bool { "sync": output.Sync, }, ).Msg("Terminating request") - return true + return true, result } } - return false + return false, result } // getPluginModifiedRequest is a function that retrieves the modified request From 7537d3807b4cc146f4942fb36cedbb5f5f1845b1 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 28 Feb 2024 00:37:07 +0100 Subject: [PATCH 26/49] Update signature of act.NewRegistry to remove global variables Refactor and replace global variables with functions Update tests to reflect changes --- act/builtins.go | 44 ++++++++++++++++++---------------- act/registry.go | 27 +++++++++++---------- api/api_test.go | 12 +++++++--- cmd/run.go | 6 +++-- network/proxy_test.go | 24 ++++++++++++++----- network/server_test.go | 4 +++- plugin/plugin_registry_test.go | 10 +++++--- 7 files changed, 79 insertions(+), 48 deletions(-) diff --git a/act/builtins.go b/act/builtins.go index 9d55a2a1..2365cedb 100644 --- a/act/builtins.go +++ b/act/builtins.go @@ -15,57 +15,61 @@ const ( TerminateDefaultFieldCount = 2 ) -// TODO: Should we get rid of global variables? -var ( - builtinSignals = []*sdkAct.Signal{ - sdkAct.Passthrough(), - sdkAct.Terminate(), +func BuiltinSignals() map[string]*sdkAct.Signal { + return map[string]*sdkAct.Signal{ + "passthrough": sdkAct.Passthrough(), + "terminate": sdkAct.Terminate(), + "log": {Name: "log"}, } +} - builtinsPolicies = []*sdkAct.Policy{ - sdkAct.MustNewPolicy("passthrough", "true", nil), - sdkAct.MustNewPolicy( +func BuiltinPolicies() map[string]*sdkAct.Policy { + return map[string]*sdkAct.Policy{ + "passthrough": sdkAct.MustNewPolicy("passthrough", "true", nil), + "terminate": sdkAct.MustNewPolicy( "terminate", `Signal.terminate == true && Policy.terminate == "stop"`, map[string]any{"terminate": "stop"}, ), - sdkAct.MustNewPolicy( + "log": sdkAct.MustNewPolicy( "log", `Signal.log == true && Policy.log == "enabled"`, map[string]any{"log": "enabled"}, ), } +} - builtinActions = []*sdkAct.Action{ - { +func BuiltinActions() map[string]*sdkAct.Action { + return map[string]*sdkAct.Action{ + "passthrough": { Name: "passthrough", Metadata: nil, Sync: true, Terminal: false, - Run: passthrough, + Run: Passthrough, }, - { + "terminate": { Name: "terminate", Metadata: nil, Sync: true, Terminal: true, - Run: terminate, + Run: Terminate, }, - { + "log": { Name: "log", Metadata: nil, Sync: false, Terminal: false, - Run: log, + Run: Log, }, } -) +} -func passthrough(data map[string]any, params ...sdkAct.Parameter) (any, error) { +func Passthrough(data map[string]any, params ...sdkAct.Parameter) (any, error) { return true, nil } -func terminate(data map[string]any, params ...sdkAct.Parameter) (any, error) { +func Terminate(data map[string]any, params ...sdkAct.Parameter) (any, error) { if len(params) == 0 || params[0].Key != "logger" { return nil, gerr.ErrLoggerRequired } @@ -110,7 +114,7 @@ func terminate(data map[string]any, params ...sdkAct.Parameter) (any, error) { return true, nil } -func log(data map[string]any, params ...sdkAct.Parameter) (any, error) { +func Log(data map[string]any, params ...sdkAct.Parameter) (any, error) { fields := map[string]any{} // Only log the fields that are not level, message, or log. if len(data) > LogDefaultFieldCount { diff --git a/act/registry.go b/act/registry.go index a3c0d605..cbb5c991 100644 --- a/act/registry.go +++ b/act/registry.go @@ -30,27 +30,28 @@ type Registry struct { var _ IRegistry = (*Registry)(nil) // NewRegistry creates a new registry with the specified default policy and timeout. -func NewRegistry(defaultPolicy string, timeout time.Duration, logger zerolog.Logger) *Registry { - signals := make(map[string]*sdkAct.Signal) +func NewRegistry( + builtinSignals map[string]*sdkAct.Signal, + builtinsPolicies map[string]*sdkAct.Policy, + builtinActions map[string]*sdkAct.Action, + defaultPolicy string, + timeout time.Duration, + logger zerolog.Logger, +) *Registry { for _, signal := range builtinSignals { - signals[signal.Name] = signal logger.Debug().Str("name", signal.Name).Msg("Registered builtin signal") } - policies := make(map[string]*sdkAct.Policy) for _, policy := range builtinsPolicies { - policies[policy.Name] = policy logger.Debug().Str("name", policy.Name).Msg("Registered builtin policy") } - actions := make(map[string]*sdkAct.Action) for _, action := range builtinActions { - actions[action.Name] = action logger.Debug().Str("name", action.Name).Msg("Registered builtin action") } // The default policy must exist, otherwise use passthrough. - if _, exists := policies[defaultPolicy]; !exists || defaultPolicy == "" { + if _, exists := builtinsPolicies[defaultPolicy]; !exists || defaultPolicy == "" { logger.Warn().Str("name", defaultPolicy).Msg( "The specified default policy does not exist, using passthrough") defaultPolicy = "passthrough" @@ -61,11 +62,11 @@ func NewRegistry(defaultPolicy string, timeout time.Duration, logger zerolog.Log return &Registry{ logger: logger, timeout: timeout, - Signals: signals, - Actions: actions, - Policies: policies, - DefaultPolicy: policies[defaultPolicy], - DefaultSignal: signals[defaultPolicy], + Signals: builtinSignals, + Policies: builtinsPolicies, + Actions: builtinActions, + DefaultPolicy: builtinsPolicies[defaultPolicy], + DefaultSignal: builtinSignals[defaultPolicy], } } diff --git a/api/api_test.go b/api/api_test.go index 5eabeec4..893010fd 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -106,7 +106,9 @@ func TestGetPluginConfig(t *testing.T) { } func TestGetPlugins(t *testing.T) { - actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) + actRegistry := act.NewRegistry( + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) pluginRegistry := plugin.NewRegistry( context.TODO(), actRegistry, @@ -134,7 +136,9 @@ func TestGetPlugins(t *testing.T) { } func TestGetPluginsWithEmptyPluginRegistry(t *testing.T) { - actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) + actRegistry := act.NewRegistry( + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) pluginRegistry := plugin.NewRegistry( context.TODO(), actRegistry, @@ -241,7 +245,9 @@ func TestGetServers(t *testing.T) { config.DefaultPluginTimeout, ) - actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) + actRegistry := act.NewRegistry( + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) pluginRegistry := plugin.NewRegistry( context.TODO(), diff --git a/cmd/run.go b/cmd/run.go index 7abf92a4..d5512fa9 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -253,9 +253,11 @@ var runCmd = &cobra.Command{ "Running GatewayD in development mode (not recommended for production)") } - // Create a new policy registry. + // Create a new policy registry given the built-in signals, policies, and actions. policiesRegistry = act.NewRegistry( - conf.Plugin.DefaultPolicy, conf.Plugin.PolicyTimeout, logger) + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + conf.Plugin.DefaultPolicy, conf.Plugin.PolicyTimeout, logger, + ) // Load policies from the configuration file and add them to the registry. for _, plc := range conf.Plugin.Policies { diff --git a/network/proxy_test.go b/network/proxy_test.go index 264761b8..d16dece6 100644 --- a/network/proxy_test.go +++ b/network/proxy_test.go @@ -45,7 +45,9 @@ func TestNewProxy(t *testing.T) { assert.Nil(t, err) // Create a new Act registry - actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + actRegistry := act.NewRegistry( + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) // Create a proxy with a fixed buffer newPool proxy := NewProxy( @@ -90,7 +92,9 @@ func BenchmarkNewProxy(b *testing.B) { newPool := pool.NewPool(context.Background(), config.EmptyPoolCapacity) // Create a new Act registry - actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + actRegistry := act.NewRegistry( + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) // Create a proxy with a fixed buffer newPool for i := 0; i < b.N; i++ { @@ -138,7 +142,9 @@ func BenchmarkProxyConnectDisconnect(b *testing.B) { newPool.Put("client", NewClient(context.Background(), &clientConfig, logger, nil)) //nolint:errcheck // Create a new Act registry - actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + actRegistry := act.NewRegistry( + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) // Create a proxy with a fixed buffer newPool proxy := NewProxy( @@ -192,7 +198,9 @@ func BenchmarkProxyPassThrough(b *testing.B) { newPool.Put("client", NewClient(context.Background(), &clientConfig, logger, nil)) //nolint:errcheck // Create a new Act registry - actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + actRegistry := act.NewRegistry( + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) // Create a proxy with a fixed buffer newPool proxy := NewProxy( @@ -251,7 +259,9 @@ func BenchmarkProxyIsHealthyAndIsExhausted(b *testing.B) { newPool.Put("client", client) //nolint:errcheck // Create a new Act registry - actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + actRegistry := act.NewRegistry( + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) // Create a proxy with a fixed buffer newPool proxy := NewProxy( @@ -308,7 +318,9 @@ func BenchmarkProxyAvailableAndBusyConnections(b *testing.B) { newPool.Put("client", client) //nolint:errcheck // Create a new Act registry - actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + actRegistry := act.NewRegistry( + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) // Create a proxy with a fixed buffer newPool proxy := NewProxy( diff --git a/network/server_test.go b/network/server_test.go index c834497b..4292c8ae 100644 --- a/network/server_test.go +++ b/network/server_test.go @@ -39,7 +39,9 @@ func TestRunServer(t *testing.T) { FileName: "server_test.log", }) - actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + actRegistry := act.NewRegistry( + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) pluginRegistry := plugin.NewRegistry( context.Background(), actRegistry, diff --git a/plugin/plugin_registry_test.go b/plugin/plugin_registry_test.go index f65bb234..ef0ada0a 100644 --- a/plugin/plugin_registry_test.go +++ b/plugin/plugin_registry_test.go @@ -22,11 +22,13 @@ func NewPluginRegistry(t *testing.T) *Registry { Output: []config.LogOutput{config.Console}, TimeFormat: zerolog.TimeFormatUnix, ConsoleTimeFormat: time.RFC3339, - Level: zerolog.DebugLevel, + Level: zerolog.InfoLevel, NoColor: true, } logger := logging.NewLogger(context.Background(), cfg) - actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + actRegistry := act.NewRegistry( + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) reg := NewRegistry( context.Background(), actRegistry, @@ -127,7 +129,9 @@ func BenchmarkHookRun(b *testing.B) { NoColor: true, } logger := logging.NewLogger(context.Background(), cfg) - actRegistry := act.NewRegistry(config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + actRegistry := act.NewRegistry( + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) reg := NewRegistry( context.Background(), actRegistry, From a36b4fc187ea3f7406f44164413ccd91fd74dbe0 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 28 Feb 2024 00:42:16 +0100 Subject: [PATCH 27/49] Fix linter issues --- act/builtins.go | 4 ++-- network/proxy.go | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/act/builtins.go b/act/builtins.go index 2365cedb..41dca12a 100644 --- a/act/builtins.go +++ b/act/builtins.go @@ -65,11 +65,11 @@ func BuiltinActions() map[string]*sdkAct.Action { } } -func Passthrough(data map[string]any, params ...sdkAct.Parameter) (any, error) { +func Passthrough(map[string]any, ...sdkAct.Parameter) (any, error) { return true, nil } -func Terminate(data map[string]any, params ...sdkAct.Parameter) (any, error) { +func Terminate(_ map[string]any, params ...sdkAct.Parameter) (any, error) { if len(params) == 0 || params[0].Key != "logger" { return nil, gerr.ErrLoggerRequired } diff --git a/network/proxy.go b/network/proxy.go index f3a9670f..aa703eb0 100644 --- a/network/proxy.go +++ b/network/proxy.go @@ -869,8 +869,7 @@ func (pr *Proxy) shouldTerminate(result map[string]interface{}) (bool, map[strin pr.logger.Error().Err(err).Msg("Error running policy") } // The terminate action should return a map. - switch v := actRes.(type) { - case map[string]interface{}: + if v, ok := actRes.(map[string]interface{}); ok { actionResult = v } } From a328900d4894cb2a5474e3aadb7d4a74d4d479c9 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 28 Feb 2024 00:58:33 +0100 Subject: [PATCH 28/49] Ignore contradictory signals --- act/registry.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/act/registry.go b/act/registry.go index cbb5c991..9fdfbc4f 100644 --- a/act/registry.go +++ b/act/registry.go @@ -92,10 +92,21 @@ func (r *Registry) Apply(signals []sdkAct.Signal) []*sdkAct.Output { return r.Apply([]sdkAct.Signal{*r.DefaultSignal}) } - // TODO: Check for non-contradictory actions (forward vs. drop) - + terminal := false outputs := []*sdkAct.Output{} for _, signal := range signals { + // Ignore contradictory actions (forward vs. terminate) if the signal is terminal. + // If the signal is terminal, all subsequent non-terminal signals are ignored. + // This is to prevent the user from shooting themselves in the foot. Also, it only + // makes sense to have a terminal signal if the action is synchronous and terminal. + if action, exists := r.Actions[signal.Name]; exists && action.Sync && action.Terminal { + terminal = true + } else if exists && terminal && action.Sync && !action.Terminal { + r.logger.Warn().Str("name", signal.Name).Msg( + "Contradictory action, ignoring signal") + continue + } + output, err := r.apply(signal) if err != nil { r.logger.Error().Err(err).Str("name", signal.Name).Msg("Error applying signal") From e08fbe051c344471e1e752dbd49ff8f711fe5dd7 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 28 Feb 2024 14:34:55 +0100 Subject: [PATCH 29/49] Use the latest (tagged) version of prometheus client for Go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 04f6b93a..16186473 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/jackc/pgx/v5 v5.5.3 github.com/knadh/koanf v1.5.0 github.com/mitchellh/mapstructure v1.5.0 - github.com/prometheus/client_golang v1.18.1-0.20240223185837-14259fa70cfb + github.com/prometheus/client_golang v1.19.0 github.com/prometheus/client_model v0.6.0 github.com/prometheus/common v0.48.0 github.com/rs/zerolog v1.32.0 diff --git a/go.sum b/go.sum index 9a1659c2..7e3e459d 100644 --- a/go.sum +++ b/go.sum @@ -310,8 +310,8 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.18.1-0.20240223185837-14259fa70cfb h1:RQ5Z0SNTwzo4QbNg+3UWZ4JB6ioYOhX41gKAUnHDVVY= -github.com/prometheus/client_golang v1.18.1-0.20240223185837-14259fa70cfb/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= From e51c89d568d665eb15254a07bae537815837fb45 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 28 Feb 2024 18:56:44 +0100 Subject: [PATCH 30/49] Remove unused code Add comments Unexport functions --- act/registry.go | 3 +++ network/proxy.go | 17 ----------------- plugin/plugin_registry.go | 6 +++--- plugin/utils.go | 14 +++++++------- 4 files changed, 13 insertions(+), 27 deletions(-) diff --git a/act/registry.go b/act/registry.go index 9fdfbc4f..e5f33b87 100644 --- a/act/registry.go +++ b/act/registry.go @@ -213,6 +213,7 @@ func (r *Registry) Run( return nil, gerr.ErrAsyncAction } +// WithLogger returns a parameter with the logger to be used by the action. func WithLogger(logger zerolog.Logger) sdkAct.Parameter { return sdkAct.Parameter{ Key: "logger", @@ -220,6 +221,8 @@ func WithLogger(logger zerolog.Logger) sdkAct.Parameter { } } +// WithResult returns a parameter with the result of the plugin hook +// to be used by the action. func WithResult(result map[string]any) sdkAct.Parameter { return sdkAct.Parameter{ Key: "result", diff --git a/network/proxy.go b/network/proxy.go index aa703eb0..3bf5f81b 100644 --- a/network/proxy.go +++ b/network/proxy.go @@ -390,7 +390,6 @@ func (pr *Proxy) PassThroughToServer(conn *ConnWrapper, stack *Stack) *gerr.Gate stack.Push(&Request{Data: request}) // If the hook wants to terminate the connection, do it. - // TODO: Should the output be reconstructed here? Or should it be done in the plugin registry? if terminate, resp := pr.shouldTerminate(result); terminate { if resp != nil { pr.logger.Trace().Fields( @@ -882,22 +881,6 @@ func (pr *Proxy) shouldTerminate(result map[string]interface{}) (bool, map[strin return cast.ToBool(result[sdkAct.Terminal]), actionResult } - // If the hook wants to terminate the request, do it. - for _, output := range outputs { - if output.MatchedPolicy == "terminate" && output.Verdict { - pr.logger.Debug().Fields( - map[string]interface{}{ - "function": "proxy.passthrough", - "policy": output.MatchedPolicy, - "verdict": output.Verdict, - "metadata": output.Metadata, - "sync": output.Sync, - }, - ).Msg("Terminating request") - return true, result - } - } - return false, result } diff --git a/plugin/plugin_registry.go b/plugin/plugin_registry.go index c33663ab..c55de0da 100644 --- a/plugin/plugin_registry.go +++ b/plugin/plugin_registry.go @@ -279,7 +279,7 @@ func (reg *Registry) Run( defer cancel() // Cast custom fields to their primitive types, like time.Duration to float64. - args = CastToPrimitiveTypes(args) + args = castToPrimitiveTypes(args) // Create v1.Struct from args. var params *v1.Struct @@ -364,11 +364,11 @@ func (reg *Registry) Apply(hookName string, result *v1.Struct) ([]*sdkAct.Output defer span.End() // Get signals from the result. - signals := GetSignals(result.AsMap()) + signals := getSignals(result.AsMap()) // Apply policies to the signals. // The outputs contains the verdicts of the policies and their metadata. // And using this list, the caller can take further actions. - outputs := ApplyPolicies(hookName, signals, reg.Logger, reg.PolicyRegistry()) + outputs := applyPolicies(hookName, signals, reg.Logger, reg.PolicyRegistry()) // If no policies are found, return a default output. // Note: this should never happen, as the default policy is always loaded. diff --git a/plugin/utils.go b/plugin/utils.go index 33904202..f237bf11 100644 --- a/plugin/utils.go +++ b/plugin/utils.go @@ -19,9 +19,9 @@ func NewCommand(cmd string, args []string, env []string) *exec.Cmd { return command } -// CastToPrimitiveTypes casts the values of a map to its primitive type +// castToPrimitiveTypes casts the values of a map to its primitive type // (e.g. time.Duration to float64) to prevent structpb invalid type(s) errors. -func CastToPrimitiveTypes(args map[string]interface{}) map[string]interface{} { +func castToPrimitiveTypes(args map[string]interface{}) map[string]interface{} { for key, value := range args { switch value := value.(type) { case time.Duration: @@ -29,7 +29,7 @@ func CastToPrimitiveTypes(args map[string]interface{}) map[string]interface{} { args[key] = value.String() case map[string]interface{}: // Recursively cast nested maps. - args[key] = CastToPrimitiveTypes(value) + args[key] = castToPrimitiveTypes(value) case []interface{}: // Recursively cast nested arrays. array := make([]interface{}, len(value)) @@ -51,8 +51,8 @@ func CastToPrimitiveTypes(args map[string]interface{}) map[string]interface{} { return args } -// GetSignals decodes the signals from the result map and returns them as a list of Signal objects. -func GetSignals(result map[string]any) []sdkAct.Signal { +// getSignals decodes the signals from the result map and returns them as a list of Signal objects. +func getSignals(result map[string]any) []sdkAct.Signal { decodedSignals := []sdkAct.Signal{} if signals, ok := result[sdkAct.Signals]; ok { @@ -75,8 +75,8 @@ func GetSignals(result map[string]any) []sdkAct.Signal { return decodedSignals } -// ApplyPolicies applies the policies to the signals and returns the outputs. -func ApplyPolicies( +// applyPolicies applies the policies to the signals and returns the outputs. +func applyPolicies( hookName string, signals []sdkAct.Signal, logger zerolog.Logger, reg act.IRegistry, ) []*sdkAct.Output { signalNames := []string{} From 6d02b36c84a5ae1c937bdcafe42e09319587f53a Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 28 Feb 2024 18:57:34 +0100 Subject: [PATCH 31/49] Add tests for Act utils functions --- plugin/utils_test.go | 60 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/plugin/utils_test.go b/plugin/utils_test.go index 80d83c60..7c6581fc 100644 --- a/plugin/utils_test.go +++ b/plugin/utils_test.go @@ -4,6 +4,11 @@ import ( "testing" "time" + sdkAct "github.com/gatewayd-io/gatewayd-plugin-sdk/act" + "github.com/gatewayd-io/gatewayd/act" + "github.com/gatewayd-io/gatewayd/config" + "github.com/rs/zerolog" + "github.com/spf13/cast" "github.com/stretchr/testify/assert" ) @@ -16,8 +21,8 @@ func Test_NewCommand(t *testing.T) { assert.Equal(t, []string{"test=123"}, cmd.Env) } -// Test_CastToPrimitiveTypes tests the CastToPrimitiveTypes function. -func Test_CastToPrimitiveTypes(t *testing.T) { +// Test_castToPrimitiveTypes tests the CastToPrimitiveTypes function. +func Test_castToPrimitiveTypes(t *testing.T) { actual := map[string]interface{}{ "string": "test", "int": 123, @@ -51,6 +56,55 @@ func Test_CastToPrimitiveTypes(t *testing.T) { }, } - casted := CastToPrimitiveTypes(actual) + casted := castToPrimitiveTypes(actual) assert.Equal(t, expected, casted) } + +// Test_getSignals tests the getSignals function. +func Test_getSignals(t *testing.T) { + result := map[string]interface{}{ + sdkAct.Signals: []any{ + (&sdkAct.Signal{ + Name: "test", + Metadata: map[string]any{"test": "test"}, + }).ToMap(), + sdkAct.Passthrough().ToMap(), + }, + } + signals := getSignals(result) + assert.Len(t, signals, 2) + assert.Equal(t, "test", signals[0].Name) + assert.Equal(t, "test", signals[0].Metadata["test"]) + assert.Equal(t, "passthrough", signals[1].Name) + assert.Nil(t, signals[1].Metadata) +} + +// Test_getSignals_empty tests the getSignals function with an empty result. +func Test_getSignals_empty(t *testing.T) { + result := map[string]interface{}{} + signals := getSignals(result) + assert.Len(t, signals, 0) +} + +// Test_applyPolicies tests the applyPolicies function with a passthrough policy. +// It also tests the Run function of the registered passthrough (built-in) action. +func Test_applyPolicies(t *testing.T) { + logger := zerolog.Logger{} + actRegistry := act.NewRegistry( + act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger, + ) + + output := applyPolicies( + "onTrafficFromClient", []sdkAct.Signal{*sdkAct.Passthrough()}, logger, actRegistry) + assert.Len(t, output, 1) + assert.Equal(t, "passthrough", output[0].MatchedPolicy) + assert.Nil(t, output[0].Metadata) + assert.True(t, output[0].Sync) + assert.False(t, output[0].Terminal) + assert.True(t, output[0].Verdict) + + result, gerr := actRegistry.Run(output[0], act.WithLogger(logger)) + assert.Nil(t, gerr) + assert.True(t, cast.ToBool(result)) +} From 33ea2747a0542761d836c35da39973fc9c5654e8 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 28 Feb 2024 19:01:54 +0100 Subject: [PATCH 32/49] Add tests for policy registry --- network/server_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/network/server_test.go b/network/server_test.go index 4292c8ae..0164acee 100644 --- a/network/server_test.go +++ b/network/server_test.go @@ -56,6 +56,16 @@ func TestRunServer(t *testing.T) { pluginRegistry.AddHook(v1.HookName_HOOK_NAME_ON_TRAFFIC_FROM_SERVER, 1, onOutgoingTraffic) pluginRegistry.AddHook(v1.HookName_HOOK_NAME_ON_TRAFFIC_TO_CLIENT, 1, onOutgoingTraffic) + assert.NotNil(t, pluginRegistry.PolicyRegistry()) + assert.NotNil(t, pluginRegistry.PolicyRegistry().Signals) + assert.NotNil(t, pluginRegistry.PolicyRegistry().Policies) + assert.NotNil(t, pluginRegistry.PolicyRegistry().Actions) + assert.Equal(t, pluginRegistry.PolicyRegistry().Signals, act.BuiltinSignals()) + assert.Equal(t, pluginRegistry.PolicyRegistry().Policies, act.BuiltinPolicies()) + assert.Equal(t, pluginRegistry.PolicyRegistry().Actions, act.BuiltinActions()) + assert.Equal(t, config.DefaultPolicy, pluginRegistry.PolicyRegistry().DefaultPolicy.Name) + assert.Equal(t, config.DefaultPolicy, pluginRegistry.PolicyRegistry().DefaultSignal.Name) + clientConfig := config.Client{ Network: "tcp", Address: "localhost:5432", From 9e6ccf635c720cc3a024b292ab705eb178111dff Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 28 Feb 2024 19:04:52 +0100 Subject: [PATCH 33/49] Add cast to allow list of tests --- .golangci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.golangci.yaml b/.golangci.yaml index 0f836393..ecb52445 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -86,6 +86,7 @@ linters-settings: - "github.com/panjf2000/gnet/v2" - "github.com/spf13/cobra" - "github.com/knadh/koanf" + - "github.com/spf13/cast" tagalign: align: false sort: false From 670bda4ca2e4cb1c7d53f1f24c8537b4d0fd2378 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 28 Feb 2024 19:09:40 +0100 Subject: [PATCH 34/49] Remove comparison of pointers --- network/server_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/network/server_test.go b/network/server_test.go index 0164acee..5a455779 100644 --- a/network/server_test.go +++ b/network/server_test.go @@ -60,9 +60,6 @@ func TestRunServer(t *testing.T) { assert.NotNil(t, pluginRegistry.PolicyRegistry().Signals) assert.NotNil(t, pluginRegistry.PolicyRegistry().Policies) assert.NotNil(t, pluginRegistry.PolicyRegistry().Actions) - assert.Equal(t, pluginRegistry.PolicyRegistry().Signals, act.BuiltinSignals()) - assert.Equal(t, pluginRegistry.PolicyRegistry().Policies, act.BuiltinPolicies()) - assert.Equal(t, pluginRegistry.PolicyRegistry().Actions, act.BuiltinActions()) assert.Equal(t, config.DefaultPolicy, pluginRegistry.PolicyRegistry().DefaultPolicy.Name) assert.Equal(t, config.DefaultPolicy, pluginRegistry.PolicyRegistry().DefaultSignal.Name) From f70efac4c281730dda77ebdfc75d8bd1fc8ccf40 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 28 Feb 2024 19:57:59 +0100 Subject: [PATCH 35/49] Add test for act/registry.go --- act/registry.go | 3 + act/registry_test.go | 144 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 act/registry_test.go diff --git a/act/registry.go b/act/registry.go index e5f33b87..5f0659ca 100644 --- a/act/registry.go +++ b/act/registry.go @@ -198,6 +198,8 @@ func (r *Registry) Run( "action": action.Name, }).Msgf("Running action") + // Run the action asynchronously. + // TODO: Add a way to cancel the action. go func( action *sdkAct.Action, output *sdkAct.Output, @@ -214,6 +216,7 @@ func (r *Registry) Run( } // WithLogger returns a parameter with the logger to be used by the action. +// This is automatically prepended to the parameters when running an action. func WithLogger(logger zerolog.Logger) sdkAct.Parameter { return sdkAct.Parameter{ Key: "logger", diff --git a/act/registry_test.go b/act/registry_test.go new file mode 100644 index 00000000..f2d5487e --- /dev/null +++ b/act/registry_test.go @@ -0,0 +1,144 @@ +package act + +import ( + "bytes" + "testing" + "time" + + sdkAct "github.com/gatewayd-io/gatewayd-plugin-sdk/act" + "github.com/gatewayd-io/gatewayd/config" + gerr "github.com/gatewayd-io/gatewayd/errors" + "github.com/rs/zerolog" + "github.com/spf13/cast" + "github.com/stretchr/testify/assert" +) + +// Test_NewRegistry tests the NewRegistry function. +func Test_NewRegistry(t *testing.T) { + logger := zerolog.Logger{} + + actRegistry := NewRegistry( + BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.NotNil(t, actRegistry) + assert.NotNil(t, actRegistry.Signals) + assert.NotNil(t, actRegistry.Policies) + assert.NotNil(t, actRegistry.Actions) + assert.Equal(t, config.DefaultPolicy, actRegistry.DefaultPolicy.Name) + assert.Equal(t, config.DefaultPolicy, actRegistry.DefaultSignal.Name) +} + +// Test_Add tests the Add function of the policy registry. +func Test_Add(t *testing.T) { + actRegistry := NewRegistry( + BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) + assert.NotNil(t, actRegistry) + + actRegistry.Add(&sdkAct.Policy{Name: "test-policy", Policy: "true"}) + assert.NotNil(t, actRegistry.Policies["test-policy"]) + assert.Equal(t, "test-policy", actRegistry.Policies["test-policy"].Name) + assert.Equal(t, "true", actRegistry.Policies["test-policy"].Policy) + assert.Nil(t, actRegistry.Policies["test-policy"].Metadata) +} + +// Test_Apply tests the Apply function of the policy registry. +func Test_Apply(t *testing.T) { + actRegistry := NewRegistry( + BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) + assert.NotNil(t, actRegistry) + + outputs := actRegistry.Apply([]sdkAct.Signal{ + *sdkAct.Passthrough(), + }) + assert.NotNil(t, outputs) + assert.Len(t, outputs, 1) + assert.Equal(t, "passthrough", outputs[0].MatchedPolicy) + assert.Nil(t, outputs[0].Metadata) + assert.True(t, outputs[0].Sync) + assert.True(t, outputs[0].Verdict) + assert.False(t, outputs[0].Terminal) +} + +// Test_Run tests the Run function of the policy registry with a non-terminal action. +func Test_Run(t *testing.T) { + logger := zerolog.Logger{} + actRegistry := NewRegistry( + BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.NotNil(t, actRegistry) + + outputs := actRegistry.Apply([]sdkAct.Signal{ + *sdkAct.Passthrough(), + }) + assert.NotNil(t, outputs) + + result, err := actRegistry.Run(outputs[0], WithLogger(logger)) + assert.Nil(t, err) + assert.True(t, cast.ToBool(result)) +} + +// Test_Run_Terminate tests the Run function of the policy registry with a terminal action. +func Test_Run_Terminate(t *testing.T) { + logger := zerolog.Logger{} + actRegistry := NewRegistry( + BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.NotNil(t, actRegistry) + + outputs := actRegistry.Apply([]sdkAct.Signal{ + *sdkAct.Terminate(), + }) + assert.NotNil(t, outputs) + assert.Equal(t, "terminate", outputs[0].MatchedPolicy) + assert.Equal(t, outputs[0].Metadata, map[string]interface{}{"terminate": true}) + assert.True(t, outputs[0].Sync) + assert.True(t, outputs[0].Verdict) + assert.True(t, outputs[0].Terminal) + + result, err := actRegistry.Run(outputs[0], WithResult(map[string]any{})) + assert.Nil(t, err) + resultMap := cast.ToStringMap(result) + assert.Contains(t, resultMap, "response") + assert.NotEmpty(t, resultMap["response"]) +} + +// Test_Run_Async tests the Run function of the policy registry with an asynchronous action. +func Test_Run_Async(t *testing.T) { + out := bytes.Buffer{} + logger := zerolog.New(&out) + actRegistry := NewRegistry( + BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.NotNil(t, actRegistry) + + outputs := actRegistry.Apply([]sdkAct.Signal{ + *sdkAct.Log("info", "test", map[string]any{"async": true}), + }) + assert.NotNil(t, outputs) + assert.Equal(t, "log", outputs[0].MatchedPolicy) + assert.Equal(t, + map[string]interface{}{ + "async": true, + "level": "info", + "log": true, + "message": "test", + }, + outputs[0].Metadata, + ) + assert.False(t, outputs[0].Sync) + assert.True(t, outputs[0].Verdict) + assert.False(t, outputs[0].Terminal) + + result, err := actRegistry.Run(outputs[0], WithResult(map[string]any{})) + assert.Equal(t, err, gerr.ErrAsyncAction, "expected async action sentinel error") + assert.Nil(t, result, "expected nil result") + + time.Sleep(time.Millisecond) // wait for async action to complete + + // The following is the expected log output from running the async action. + assert.Contains(t, out.String(), "{\"level\":\"debug\",\"action\":\"log\",\"execution_mode\":\"async\",\"message\":\"Running action\"}") //nolint:lll + // The following is the expected log output from the run function of the async action. + assert.Contains(t, out.String(), "{\"level\":\"info\",\"async\":true,\"message\":\"test\"}") +} From 062936874810da8c909fbd93dc12bf643f4bf499 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Thu, 29 Feb 2024 19:32:30 +0100 Subject: [PATCH 36/49] Rename variable for clarification --- act/registry.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/act/registry.go b/act/registry.go index 5f0659ca..6b25d479 100644 --- a/act/registry.go +++ b/act/registry.go @@ -17,8 +17,9 @@ type IRegistry interface { // Registry keeps track of all policies and actions. type Registry struct { - logger zerolog.Logger - timeout time.Duration // Timeout for policy evaluation + logger zerolog.Logger + // Timeout for policy evaluation. + policyTimeout time.Duration Signals map[string]*sdkAct.Signal Policies map[string]*sdkAct.Policy @@ -35,7 +36,7 @@ func NewRegistry( builtinsPolicies map[string]*sdkAct.Policy, builtinActions map[string]*sdkAct.Action, defaultPolicy string, - timeout time.Duration, + policyTimeout time.Duration, logger zerolog.Logger, ) *Registry { for _, signal := range builtinSignals { @@ -61,7 +62,7 @@ func NewRegistry( return &Registry{ logger: logger, - timeout: timeout, + policyTimeout: policyTimeout, Signals: builtinSignals, Policies: builtinsPolicies, Actions: builtinActions, @@ -134,7 +135,7 @@ func (r *Registry) apply(signal sdkAct.Signal) (*sdkAct.Output, *gerr.GatewayDEr return nil, gerr.ErrPolicyNotMatched } - ctx, cancel := context.WithTimeout(context.Background(), r.timeout) + ctx, cancel := context.WithTimeout(context.Background(), r.policyTimeout) defer cancel() // Action dictates the sync mode, not the signal. From fbf1ca808c0690c68db755ee25fa6ce46a1940cc Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Thu, 29 Feb 2024 19:41:34 +0100 Subject: [PATCH 37/49] Add policies and policyTimeout config params to sample config file --- gatewayd_plugins.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gatewayd_plugins.yaml b/gatewayd_plugins.yaml index ae229d1f..e31ac487 100644 --- a/gatewayd_plugins.yaml +++ b/gatewayd_plugins.yaml @@ -42,6 +42,12 @@ timeout: 30s # The start timeout controls how long to wait for a plugin to start before timing out. startTimeout: 1m +# The policy timeout controls how long to wait for the evluation of the policy before timing out. +policyTimeout: 30s + +# The policy is a list of policies to apply to the signals received from the plugins. +policies: [] + # The plugin configuration is a list of plugins to load. Each plugin is defined by a name, # a path to the plugin's executable, and a list of arguments to pass to the plugin. The # plugin's executable is expected to be a Go plugin that implements the GatewayD plugin From 00db220242bbf6825a858afc3f0bb23567f90af7 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Thu, 29 Feb 2024 19:55:41 +0100 Subject: [PATCH 38/49] Remove termination policy (#458) --- .github/workflows/test.yaml | 1 - api/api_test.go | 3 - api/v1/api.pb.go | 328 ++++++++++++++++----------------- api/v1/api.proto | 2 +- api/v1/api.swagger.json | 1 - cmd/run.go | 5 - config/config.go | 1 - config/constants.go | 9 - config/getters.go | 4 - config/types.go | 1 - gatewayd_plugins.yaml | 11 -- network/proxy_test.go | 6 - network/server_test.go | 1 - plugin/plugin_registry.go | 3 - plugin/plugin_registry_test.go | 2 - 15 files changed, 164 insertions(+), 214 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 39f06ab0..b86ca630 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -115,7 +115,6 @@ jobs: export SHA256SUM=$(sha256sum ptg | awk '{print $1}') cat < gatewayd_plugins.yaml compatibilityPolicy: "strict" - terminationPolicy: "stop" metricsMergerPeriod: 1s healthCheckPeriod: 1s reloadOnCrash: true diff --git a/api/api_test.go b/api/api_test.go index 893010fd..9d264a92 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -113,7 +113,6 @@ func TestGetPlugins(t *testing.T) { context.TODO(), actRegistry, config.Loose, - config.Stop, zerolog.Logger{}, true, ) @@ -143,7 +142,6 @@ func TestGetPluginsWithEmptyPluginRegistry(t *testing.T) { context.TODO(), actRegistry, config.Loose, - config.Stop, zerolog.Logger{}, true, ) @@ -253,7 +251,6 @@ func TestGetServers(t *testing.T) { context.TODO(), actRegistry, config.Loose, - config.Stop, zerolog.Logger{}, true, ) diff --git a/api/v1/api.pb.go b/api/v1/api.pb.go index 9315d738..004ced38 100644 --- a/api/v1/api.pb.go +++ b/api/v1/api.pb.go @@ -584,7 +584,7 @@ var file_api_v1_api_proto_rawDesc = []byte{ 0x6e, 0x66, 0x69, 0x67, 0x20, 0x62, 0x79, 0x2e, 0x32, 0x17, 0x7b, 0x22, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x7d, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x32, 0xab, 0x26, 0x0a, 0x17, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x41, 0x64, 0x6d, + 0x32, 0x90, 0x26, 0x0a, 0x17, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x50, 0x49, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xde, 0x02, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, @@ -690,21 +690,21 @@ var file_api_v1_api_proto_rawDesc = []byte{ 0x30, 0x30, 0x30, 0x30, 0x30, 0x7d, 0x7d, 0x7d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x12, 0x29, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x47, 0x65, 0x74, 0x47, 0x6c, 0x6f, - 0x62, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0xe7, 0x07, 0x0a, 0x0f, 0x47, 0x65, + 0x62, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0xcc, 0x07, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0xa2, - 0x07, 0x92, 0x41, 0xed, 0x06, 0x2a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4a, 0xd9, 0x06, 0x0a, 0x03, 0x32, 0x30, 0x30, 0x12, 0xd1, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0x87, + 0x07, 0x92, 0x41, 0xd2, 0x06, 0x2a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4a, 0xbe, 0x06, 0x0a, 0x03, 0x32, 0x30, 0x30, 0x12, 0xb6, 0x06, 0x0a, 0x44, 0x41, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x12, 0x1b, 0x0a, 0x19, 0x1a, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x22, 0xeb, 0x05, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x12, 0xd6, 0x05, 0x7b, 0x22, 0x63, 0x6f, + 0x72, 0x75, 0x63, 0x74, 0x22, 0xd0, 0x05, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x12, 0xbb, 0x05, 0x7b, 0x22, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x22, 0x2c, 0x22, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x72, @@ -747,168 +747,166 @@ var file_api_v1_api_proto_rawDesc = []byte{ 0x2c, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x22, 0x7d, 0x5d, 0x2c, 0x22, 0x72, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x6e, 0x43, 0x72, 0x61, 0x73, 0x68, - 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x6f, 0x70, - 0x22, 0x2c, 0x22, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x3a, 0x22, 0x33, 0x30, 0x73, - 0x22, 0x7d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x12, 0x29, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2f, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x12, 0xea, 0x07, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, - 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x73, 0x22, 0xac, 0x07, 0x92, 0x41, 0xfc, 0x06, 0x2a, 0x0a, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x75, - 0x67, 0x69, 0x6e, 0x73, 0x4a, 0xed, 0x06, 0x0a, 0x03, 0x32, 0x30, 0x30, 0x12, 0xe5, 0x06, 0x0a, - 0x3f, 0x41, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x69, - 0x73, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x65, - 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, - 0x12, 0x19, 0x0a, 0x17, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, - 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, 0x86, 0x06, 0x0a, 0x10, - 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, - 0x12, 0xf1, 0x05, 0x7b, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, - 0x22, 0x69, 0x64, 0x22, 0x3a, 0x7b, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x67, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2d, 0x63, 0x61, - 0x63, 0x68, 0x65, 0x22, 0x2c, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, - 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x22, 0x2c, 0x22, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x55, 0x72, - 0x6c, 0x22, 0x3a, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x64, 0x2d, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, - 0x22, 0x2c, 0x22, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x22, 0x3a, 0x22, 0x2e, 0x2e, - 0x2e, 0x22, 0x7d, 0x2c, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x3a, 0x22, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x20, 0x70, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x71, - 0x75, 0x65, 0x72, 0x79, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x2c, 0x22, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x2e, 0x2e, 0x2e, 0x22, 0x5d, 0x2c, - 0x22, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x22, 0x41, 0x47, 0x50, 0x4c, 0x2d, - 0x33, 0x2e, 0x30, 0x22, 0x2c, 0x22, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x72, 0x6c, - 0x22, 0x3a, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, 0x69, - 0x6f, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, 0x70, 0x6c, 0x75, 0x67, 0x69, - 0x6e, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x22, 0x2c, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x70, 0x69, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, - 0x22, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x3a, 0x31, 0x38, 0x30, 0x38, 0x30, - 0x22, 0x2c, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x44, 0x42, 0x4e, 0x61, 0x6d, 0x65, - 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x65, 0x78, 0x69, 0x74, 0x4f, 0x6e, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x75, 0x70, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x3a, 0x22, 0x46, 0x61, 0x6c, 0x73, 0x65, - 0x22, 0x2c, 0x22, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x22, 0x3a, 0x22, 0x31, 0x68, 0x22, 0x2c, - 0x22, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, - 0x3a, 0x22, 0x54, 0x72, 0x75, 0x65, 0x22, 0x2c, 0x22, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x3a, 0x22, 0x2f, 0x6d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x22, 0x2c, 0x22, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x55, 0x6e, 0x69, - 0x78, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x3a, 0x22, - 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, 0x70, 0x6c, - 0x75, 0x67, 0x69, 0x6e, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x22, - 0x2c, 0x22, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x22, 0x54, - 0x72, 0x75, 0x65, 0x22, 0x2c, 0x22, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x49, 0x6e, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, - 0x6c, 0x22, 0x3a, 0x22, 0x31, 0x6d, 0x22, 0x2c, 0x22, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, - 0x63, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x22, 0x3a, 0x22, 0x31, 0x6d, 0x22, 0x2c, 0x22, 0x72, 0x65, - 0x64, 0x69, 0x73, 0x55, 0x52, 0x4c, 0x22, 0x3a, 0x22, 0x72, 0x65, 0x64, 0x69, 0x73, 0x3a, 0x2f, - 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x3a, 0x36, 0x33, 0x37, 0x39, 0x2f, - 0x30, 0x22, 0x2c, 0x22, 0x73, 0x63, 0x61, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x22, - 0x31, 0x30, 0x30, 0x30, 0x22, 0x7d, 0x2c, 0x22, 0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x22, 0x3a, 0x5b, - 0x31, 0x34, 0x2c, 0x31, 0x36, 0x2c, 0x31, 0x38, 0x5d, 0x2c, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x73, 0x22, 0x3a, 0x7b, 0x7d, 0x2c, 0x22, 0x74, 0x61, 0x67, 0x73, 0x22, 0x3a, 0x5b, - 0x5d, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x5b, - 0x5d, 0x7d, 0x5d, 0x7d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x12, 0x24, 0x2f, 0x76, 0x31, 0x2f, - 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, - 0x12, 0x93, 0x02, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6f, 0x6c, 0x73, 0x12, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0xd5, - 0x01, 0x92, 0x41, 0xa7, 0x01, 0x2a, 0x08, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6f, 0x6c, 0x73, 0x4a, - 0x9a, 0x01, 0x0a, 0x03, 0x32, 0x30, 0x30, 0x12, 0x92, 0x01, 0x0a, 0x3d, 0x41, 0x20, 0x4a, 0x53, - 0x4f, 0x4e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65, 0x74, - 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6f, 0x6c, - 0x73, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x12, 0x1b, 0x0a, 0x19, 0x1a, 0x17, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0x34, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x12, 0x20, 0x7b, 0x22, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x63, 0x61, 0x70, 0x22, 0x3a, 0x31, 0x30, - 0x2c, 0x22, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x7d, 0x7d, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, - 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x47, 0x65, - 0x74, 0x50, 0x6f, 0x6f, 0x6c, 0x73, 0x12, 0xe1, 0x03, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x50, 0x72, - 0x6f, 0x78, 0x69, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x17, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0xa1, 0x03, 0x92, 0x41, 0xf1, 0x02, 0x2a, 0x0a, 0x47, - 0x65, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x73, 0x4a, 0xe2, 0x02, 0x0a, 0x03, 0x32, 0x30, - 0x30, 0x12, 0xda, 0x02, 0x0a, 0x3f, 0x41, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x6f, 0x62, 0x6a, + 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, + 0x3a, 0x22, 0x33, 0x30, 0x73, 0x22, 0x7d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x12, 0x29, 0x2f, + 0x76, 0x31, 0x2f, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x50, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0xea, 0x07, 0x0a, 0x0a, 0x47, 0x65, 0x74, + 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, 0xac, 0x07, 0x92, 0x41, 0xfc, 0x06, 0x2a, 0x0a, 0x47, + 0x65, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x4a, 0xed, 0x06, 0x0a, 0x03, 0x32, 0x30, + 0x30, 0x12, 0xe5, 0x06, 0x0a, 0x3f, 0x41, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x73, 0x20, 0x6d, 0x65, - 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x12, 0x1b, 0x0a, 0x19, 0x1a, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, - 0x63, 0x74, 0x22, 0xf9, 0x01, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x12, 0xe4, 0x01, 0x7b, 0x22, 0x64, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, - 0x22, 0x3a, 0x5b, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x35, 0x30, - 0x39, 0x39, 0x32, 0x22, 0x2c, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, - 0x35, 0x30, 0x39, 0x35, 0x36, 0x22, 0x2c, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, - 0x31, 0x3a, 0x35, 0x31, 0x30, 0x30, 0x36, 0x22, 0x2c, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, - 0x30, 0x2e, 0x31, 0x3a, 0x35, 0x30, 0x39, 0x37, 0x32, 0x22, 0x2c, 0x22, 0x31, 0x32, 0x37, 0x2e, - 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x35, 0x31, 0x30, 0x30, 0x32, 0x22, 0x2c, 0x22, 0x31, 0x32, - 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x35, 0x30, 0x39, 0x38, 0x30, 0x22, 0x2c, 0x22, - 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x35, 0x30, 0x39, 0x33, 0x30, 0x22, - 0x2c, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x35, 0x30, 0x39, 0x34, - 0x36, 0x22, 0x2c, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x35, 0x30, - 0x39, 0x39, 0x36, 0x22, 0x2c, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, - 0x35, 0x31, 0x30, 0x32, 0x32, 0x22, 0x5d, 0x2c, 0x22, 0x62, 0x75, 0x73, 0x79, 0x22, 0x3a, 0x5b, - 0x5d, 0x2c, 0x22, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x3a, 0x31, 0x30, 0x7d, 0x7d, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x26, 0x12, 0x24, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x44, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, - 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x73, 0x12, 0xd7, 0x02, 0x0a, 0x0a, 0x47, - 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x1a, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0x97, 0x02, 0x92, 0x41, 0xe7, - 0x01, 0x2a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x4a, 0xd8, 0x01, - 0x0a, 0x03, 0x32, 0x30, 0x30, 0x12, 0xd0, 0x01, 0x0a, 0x3f, 0x41, 0x20, 0x4a, 0x53, 0x4f, 0x4e, - 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, - 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, - 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x73, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x12, 0x1b, 0x0a, 0x19, 0x1a, 0x17, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0x70, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x12, 0x5c, 0x7b, 0x22, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x22, 0x3a, 0x22, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x3a, 0x31, 0x35, 0x34, 0x33, 0x32, - 0x22, 0x2c, 0x22, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x3a, 0x22, 0x74, 0x63, 0x70, - 0x22, 0x2c, 0x22, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x74, 0x69, - 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0x3a, 0x35, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x7d, 0x7d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x12, 0x24, - 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x50, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x73, 0x1a, 0x58, 0x92, 0x41, 0x55, 0x12, 0x23, 0x47, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x44, 0x20, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x20, 0x41, 0x50, 0x49, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x1a, 0x2e, - 0x12, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x6f, 0x63, 0x73, 0x2e, 0x67, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2e, 0x69, 0x6f, 0x2f, 0x75, 0x73, 0x69, 0x6e, 0x67, - 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2f, 0x41, 0x50, 0x49, 0x2f, 0x42, 0x8b, - 0x02, 0x92, 0x41, 0xdf, 0x01, 0x12, 0xc7, 0x01, 0x0a, 0x12, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x44, 0x20, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x20, 0x41, 0x50, 0x49, 0x22, 0x45, 0x0a, 0x08, - 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x12, 0x27, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, - 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x64, 0x1a, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, - 0x2e, 0x69, 0x6f, 0x2a, 0x63, 0x0a, 0x26, 0x47, 0x4e, 0x55, 0x20, 0x41, 0x66, 0x66, 0x65, 0x72, - 0x6f, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x76, 0x33, 0x2e, 0x30, 0x12, 0x39, 0x68, + 0x68, 0x65, 0x20, 0x47, 0x65, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x20, 0x6d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x12, 0x19, 0x0a, 0x17, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, + 0x22, 0x86, 0x06, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x12, 0xf1, 0x05, 0x7b, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69, 0x64, 0x22, 0x3a, 0x7b, 0x22, 0x6e, 0x61, 0x6d, 0x65, + 0x22, 0x3a, 0x22, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, 0x70, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x22, 0x2c, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x22, 0x2c, 0x22, 0x72, 0x65, 0x6d, + 0x6f, 0x74, 0x65, 0x55, 0x72, 0x6c, 0x22, 0x3a, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, 0x69, 0x6f, 0x2f, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2d, + 0x63, 0x61, 0x63, 0x68, 0x65, 0x22, 0x2c, 0x22, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, + 0x22, 0x3a, 0x22, 0x2e, 0x2e, 0x2e, 0x22, 0x7d, 0x2c, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, + 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x61, 0x63, 0x68, + 0x69, 0x6e, 0x67, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x73, 0x22, 0x2c, 0x22, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x2e, + 0x2e, 0x2e, 0x22, 0x5d, 0x2c, 0x22, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x22, + 0x41, 0x47, 0x50, 0x4c, 0x2d, 0x33, 0x2e, 0x30, 0x22, 0x2c, 0x22, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x55, 0x72, 0x6c, 0x22, 0x3a, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x22, 0x2c, 0x22, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x70, 0x69, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x22, 0x3a, 0x22, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x3a, + 0x31, 0x38, 0x30, 0x38, 0x30, 0x22, 0x2c, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x44, + 0x42, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x65, 0x78, 0x69, 0x74, 0x4f, + 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x3a, 0x22, + 0x46, 0x61, 0x6c, 0x73, 0x65, 0x22, 0x2c, 0x22, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x22, 0x3a, + 0x22, 0x31, 0x68, 0x22, 0x2c, 0x22, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x22, 0x54, 0x72, 0x75, 0x65, 0x22, 0x2c, 0x22, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x3a, 0x22, + 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x2c, 0x22, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x55, 0x6e, 0x69, 0x78, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x6f, 0x63, 0x6b, + 0x65, 0x74, 0x22, 0x3a, 0x22, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x64, 0x2d, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2e, + 0x73, 0x6f, 0x63, 0x6b, 0x22, 0x2c, 0x22, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x49, + 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x22, 0x3a, 0x22, 0x54, 0x72, 0x75, 0x65, 0x22, 0x2c, 0x22, 0x70, 0x65, 0x72, 0x69, 0x6f, + 0x64, 0x69, 0x63, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0x3a, 0x22, 0x31, 0x6d, 0x22, 0x2c, 0x22, 0x70, 0x65, + 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, + 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x22, 0x3a, 0x22, 0x31, 0x6d, + 0x22, 0x2c, 0x22, 0x72, 0x65, 0x64, 0x69, 0x73, 0x55, 0x52, 0x4c, 0x22, 0x3a, 0x22, 0x72, 0x65, + 0x64, 0x69, 0x73, 0x3a, 0x2f, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x3a, + 0x36, 0x33, 0x37, 0x39, 0x2f, 0x30, 0x22, 0x2c, 0x22, 0x73, 0x63, 0x61, 0x6e, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x22, 0x3a, 0x22, 0x31, 0x30, 0x30, 0x30, 0x22, 0x7d, 0x2c, 0x22, 0x68, 0x6f, 0x6f, + 0x6b, 0x73, 0x22, 0x3a, 0x5b, 0x31, 0x34, 0x2c, 0x31, 0x36, 0x2c, 0x31, 0x38, 0x5d, 0x2c, 0x22, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x22, 0x3a, 0x7b, 0x7d, 0x2c, 0x22, 0x74, 0x61, + 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x2c, 0x22, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, + 0x65, 0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x7d, 0x5d, 0x7d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x12, + 0x24, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x50, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x47, 0x65, 0x74, 0x50, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x73, 0x12, 0x93, 0x02, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6f, + 0x6c, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, + 0x75, 0x63, 0x74, 0x22, 0xd5, 0x01, 0x92, 0x41, 0xa7, 0x01, 0x2a, 0x08, 0x47, 0x65, 0x74, 0x50, + 0x6f, 0x6f, 0x6c, 0x73, 0x4a, 0x9a, 0x01, 0x0a, 0x03, 0x32, 0x30, 0x30, 0x12, 0x92, 0x01, 0x0a, + 0x3d, 0x41, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x69, + 0x73, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x65, + 0x74, 0x50, 0x6f, 0x6f, 0x6c, 0x73, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x12, 0x1b, + 0x0a, 0x19, 0x1a, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0x34, 0x0a, 0x10, 0x61, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x12, + 0x20, 0x7b, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x63, 0x61, + 0x70, 0x22, 0x3a, 0x31, 0x30, 0x2c, 0x22, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x3a, 0x31, 0x30, 0x7d, + 0x7d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x44, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2f, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6f, 0x6c, 0x73, 0x12, 0xe1, 0x03, 0x0a, 0x0a, + 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0xa1, 0x03, 0x92, 0x41, + 0xf1, 0x02, 0x2a, 0x0a, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x73, 0x4a, 0xe2, + 0x02, 0x0a, 0x03, 0x32, 0x30, 0x30, 0x12, 0xda, 0x02, 0x0a, 0x3f, 0x41, 0x20, 0x4a, 0x53, 0x4f, + 0x4e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x69, + 0x65, 0x73, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x12, 0x1b, 0x0a, 0x19, 0x1a, 0x17, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0xf9, 0x01, 0x0a, 0x10, 0x61, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x12, 0xe4, 0x01, 0x7b, + 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x76, 0x61, 0x69, + 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x3a, 0x5b, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, + 0x2e, 0x31, 0x3a, 0x35, 0x30, 0x39, 0x39, 0x32, 0x22, 0x2c, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, + 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x35, 0x30, 0x39, 0x35, 0x36, 0x22, 0x2c, 0x22, 0x31, 0x32, 0x37, + 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x35, 0x31, 0x30, 0x30, 0x36, 0x22, 0x2c, 0x22, 0x31, + 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x35, 0x30, 0x39, 0x37, 0x32, 0x22, 0x2c, + 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x35, 0x31, 0x30, 0x30, 0x32, + 0x22, 0x2c, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x35, 0x30, 0x39, + 0x38, 0x30, 0x22, 0x2c, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x35, + 0x30, 0x39, 0x33, 0x30, 0x22, 0x2c, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, + 0x3a, 0x35, 0x30, 0x39, 0x34, 0x36, 0x22, 0x2c, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, + 0x2e, 0x31, 0x3a, 0x35, 0x30, 0x39, 0x39, 0x36, 0x22, 0x2c, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, + 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x35, 0x31, 0x30, 0x32, 0x32, 0x22, 0x5d, 0x2c, 0x22, 0x62, 0x75, + 0x73, 0x79, 0x22, 0x3a, 0x5b, 0x5d, 0x2c, 0x22, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x3a, 0x31, + 0x30, 0x7d, 0x7d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x12, 0x24, 0x2f, 0x76, 0x31, 0x2f, 0x47, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2f, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x73, 0x12, + 0xd7, 0x02, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, + 0x97, 0x02, 0x92, 0x41, 0xe7, 0x01, 0x2a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x73, 0x4a, 0xd8, 0x01, 0x0a, 0x03, 0x32, 0x30, 0x30, 0x12, 0xd0, 0x01, 0x0a, 0x3f, 0x41, + 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x69, 0x73, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x12, 0x1b, + 0x0a, 0x19, 0x1a, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0x70, 0x0a, 0x10, 0x61, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x12, + 0x5c, 0x7b, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x22, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x3a, + 0x31, 0x35, 0x34, 0x33, 0x32, 0x22, 0x2c, 0x22, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, + 0x3a, 0x22, 0x74, 0x63, 0x70, 0x22, 0x2c, 0x22, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3a, + 0x30, 0x2c, 0x22, 0x74, 0x69, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, + 0x3a, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x7d, 0x7d, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x26, 0x12, 0x24, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x44, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x47, + 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x1a, 0x58, 0x92, 0x41, 0x55, 0x12, 0x23, + 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x20, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x69, 0x73, + 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x50, 0x49, 0x20, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x1a, 0x2e, 0x12, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x64, + 0x6f, 0x63, 0x73, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2e, 0x69, 0x6f, 0x2f, + 0x75, 0x73, 0x69, 0x6e, 0x67, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2f, 0x41, + 0x50, 0x49, 0x2f, 0x42, 0x8b, 0x02, 0x92, 0x41, 0xdf, 0x01, 0x12, 0xc7, 0x01, 0x0a, 0x12, 0x47, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x20, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x20, 0x41, 0x50, + 0x49, 0x22, 0x45, 0x0a, 0x08, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x44, 0x12, 0x27, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, - 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2a, - 0x01, 0x01, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, - 0x6a, 0x73, 0x6f, 0x6e, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x1a, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x64, 0x2e, 0x69, 0x6f, 0x2a, 0x63, 0x0a, 0x26, 0x47, 0x4e, 0x55, 0x20, + 0x41, 0x66, 0x66, 0x65, 0x72, 0x6f, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x76, 0x33, + 0x2e, 0x30, 0x12, 0x39, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, + 0x69, 0x6f, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2f, 0x62, 0x6c, 0x6f, 0x62, + 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x31, + 0x2e, 0x30, 0x2e, 0x30, 0x2a, 0x01, 0x01, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2d, 0x69, + 0x6f, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/v1/api.proto b/api/v1/api.proto index ed155bbe..2505dfcf 100644 --- a/api/v1/api.proto +++ b/api/v1/api.proto @@ -87,7 +87,7 @@ service GatewayDAdminAPIService { }, examples: { key: "application/json" - value: '{"compatibilityPolicy":"strict","enableMetricsMerger":true,"healthCheckPeriod":"5s","metricsMergerPeriod":"5s","plugins":[{"args":["--log-level","debug"],"checksum":"...","enabled":true,"env":["MAGIC_COOKIE_KEY=...","MAGIC_COOKIE_VALUE=...","REDIS_URL=redis://localhost:6379/0","EXPIRY=1h","METRICS_ENABLED=True","METRICS_UNIX_DOMAIN_SOCKET=/tmp/gatewayd-plugin-cache.sock","METRICS_PATH=/metrics","PERIODIC_INVALIDATOR_ENABLED=True","PERIODIC_INVALIDATOR_INTERVAL=1m","PERIODIC_INVALIDATOR_START_DELAY=1m","API_ADDRESS=localhost:18080","EXIT_ON_STARTUP_ERROR=False","SENTRY_DSN=..."],"localPath":"plugins/gatewayd-plugin-cache","name":"gatewayd-plugin-cache"}],"reloadOnCrash":true,"terminationPolicy":"stop","timeout":"30s"}' + value: '{"compatibilityPolicy":"strict","enableMetricsMerger":true,"healthCheckPeriod":"5s","metricsMergerPeriod":"5s","plugins":[{"args":["--log-level","debug"],"checksum":"...","enabled":true,"env":["MAGIC_COOKIE_KEY=...","MAGIC_COOKIE_VALUE=...","REDIS_URL=redis://localhost:6379/0","EXPIRY=1h","METRICS_ENABLED=True","METRICS_UNIX_DOMAIN_SOCKET=/tmp/gatewayd-plugin-cache.sock","METRICS_PATH=/metrics","PERIODIC_INVALIDATOR_ENABLED=True","PERIODIC_INVALIDATOR_INTERVAL=1m","PERIODIC_INVALIDATOR_START_DELAY=1m","API_ADDRESS=localhost:18080","EXIT_ON_STARTUP_ERROR=False","SENTRY_DSN=..."],"localPath":"plugins/gatewayd-plugin-cache","name":"gatewayd-plugin-cache"}],"reloadOnCrash":true,"timeout":"30s"}' } }; }; diff --git a/api/v1/api.swagger.json b/api/v1/api.swagger.json index d68871d6..e7d6213b 100644 --- a/api/v1/api.swagger.json +++ b/api/v1/api.swagger.json @@ -183,7 +183,6 @@ } ], "reloadOnCrash": true, - "terminationPolicy": "stop", "timeout": "30s" } } diff --git a/cmd/run.go b/cmd/run.go index d5512fa9..d4452ca9 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -284,11 +284,6 @@ var runCmd = &cobra.Command{ config.CompatibilityPolicies, conf.Plugin.CompatibilityPolicy), config.CompatibilityPolicies[conf.Plugin.CompatibilityPolicy], config.DefaultCompatibilityPolicy), - config.If[config.TerminationPolicy]( - config.Exists[string, config.TerminationPolicy]( - config.TerminationPolicies, conf.Plugin.TerminationPolicy), - config.TerminationPolicies[conf.Plugin.TerminationPolicy], - config.DefaultTerminationPolicy), logger, devMode, ) diff --git a/config/config.go b/config/config.go index d1b293e9..b0389259 100644 --- a/config/config.go +++ b/config/config.go @@ -206,7 +206,6 @@ func (c *Config) LoadDefaults(ctx context.Context) { c.pluginDefaults = PluginConfig{ CompatibilityPolicy: string(Strict), - TerminationPolicy: string(Stop), EnableMetricsMerger: true, MetricsMergerPeriod: DefaultMetricsMergerPeriod, HealthCheckPeriod: DefaultPluginHealthCheckPeriod, diff --git a/config/constants.go b/config/constants.go index cc6fed56..3fe9d5d5 100644 --- a/config/constants.go +++ b/config/constants.go @@ -7,7 +7,6 @@ import ( type ( Status uint CompatibilityPolicy string - TerminationPolicy string LogOutput uint ) @@ -23,13 +22,6 @@ const ( Loose CompatibilityPolicy = "loose" // Load the plugin, even if the requirements are not met ) -// TerminationPolicy is the termination policy for -// the functions registered to the OnTrafficFromClient hook. -const ( - Continue TerminationPolicy = "continue" // Continue to the next function - Stop TerminationPolicy = "stop" // Stop the execution of the functions -) - // LogOutput is the output type for the logger. const ( Console LogOutput = iota @@ -129,7 +121,6 @@ const ( // Policies. DefaultCompatibilityPolicy = Strict - DefaultTerminationPolicy = Stop // Act. DefaultPolicy = "passthrough" diff --git a/config/getters.go b/config/getters.go index b7587705..406ec208 100644 --- a/config/getters.go +++ b/config/getters.go @@ -13,10 +13,6 @@ var ( "strict": Strict, "loose": Loose, } - TerminationPolicies = map[string]TerminationPolicy{ - "continue": Continue, - "stop": Stop, - } logOutputs = map[string]LogOutput{ "console": Console, "stdout": Stdout, diff --git a/config/types.go b/config/types.go index e2956c6d..fd7ceecd 100644 --- a/config/types.go +++ b/config/types.go @@ -23,7 +23,6 @@ type Policy struct { type PluginConfig struct { CompatibilityPolicy string `json:"compatibilityPolicy" jsonschema:"enum=strict,enum=loose"` - TerminationPolicy string `json:"terminationPolicy" jsonschema:"enum=continue,enum=stop"` EnableMetricsMerger bool `json:"enableMetricsMerger"` MetricsMergerPeriod time.Duration `json:"metricsMergerPeriod" jsonschema:"oneof_type=string;integer"` HealthCheckPeriod time.Duration `json:"healthCheckPeriod" jsonschema:"oneof_type=string;integer"` diff --git a/gatewayd_plugins.yaml b/gatewayd_plugins.yaml index e31ac487..09178a6a 100644 --- a/gatewayd_plugins.yaml +++ b/gatewayd_plugins.yaml @@ -9,17 +9,6 @@ # plugin and that version is not the one currently loaded. compatibilityPolicy: "strict" -# The termination policy controls how to handle the termination of requests. If a plugin -# terminates a request, the termination policy controls whether to stop executing the -# remaining plugins or not. If the termination policy is set to "stop", the remaining plugins -# are not executed. If the termination policy is set to "continue", the remaining plugins are -# executed. Warning: if the termination policy is set to "continue", the output of the -# remaining plugins might be passed down to the next plugin, and the result depends on the -# what the remaining plugins do. -# - "stop" (default): the remaining plugins are not executed. -# - "continue": the remaining plugins are executed. -terminationPolicy: "stop" - # The metrics policy controls whether to collect and merge metrics from plugins or not. # The Prometheus metrics are collected from the plugins via a Unix domain socket. The metrics # are merged and exposed via the GatewayD metrics endpoint via HTTP. diff --git a/network/proxy_test.go b/network/proxy_test.go index d16dece6..7110e430 100644 --- a/network/proxy_test.go +++ b/network/proxy_test.go @@ -57,7 +57,6 @@ func TestNewProxy(t *testing.T) { context.Background(), actRegistry, config.Loose, - config.Stop, logger, false, ), @@ -105,7 +104,6 @@ func BenchmarkNewProxy(b *testing.B) { context.Background(), actRegistry, config.Loose, - config.Stop, logger, false, ), @@ -154,7 +152,6 @@ func BenchmarkProxyConnectDisconnect(b *testing.B) { context.Background(), actRegistry, config.Loose, - config.Stop, logger, false, ), @@ -210,7 +207,6 @@ func BenchmarkProxyPassThrough(b *testing.B) { context.Background(), actRegistry, config.Loose, - config.Stop, logger, false, ), @@ -271,7 +267,6 @@ func BenchmarkProxyIsHealthyAndIsExhausted(b *testing.B) { context.Background(), actRegistry, config.Loose, - config.Stop, logger, false, ), @@ -330,7 +325,6 @@ func BenchmarkProxyAvailableAndBusyConnections(b *testing.B) { context.Background(), actRegistry, config.Loose, - config.Stop, logger, false, ), diff --git a/network/server_test.go b/network/server_test.go index 5a455779..7ca01905 100644 --- a/network/server_test.go +++ b/network/server_test.go @@ -46,7 +46,6 @@ func TestRunServer(t *testing.T) { context.Background(), actRegistry, config.Loose, - config.Stop, logger, false, ) diff --git a/plugin/plugin_registry.go b/plugin/plugin_registry.go index c55de0da..1f73e1fc 100644 --- a/plugin/plugin_registry.go +++ b/plugin/plugin_registry.go @@ -65,7 +65,6 @@ type Registry struct { Logger zerolog.Logger Compatibility config.CompatibilityPolicy - Termination config.TerminationPolicy StartTimeout time.Duration } @@ -76,7 +75,6 @@ func NewRegistry( ctx context.Context, policiesRegistry *act.Registry, compatibility config.CompatibilityPolicy, - termination config.TerminationPolicy, logger zerolog.Logger, devMode bool, ) *Registry { @@ -91,7 +89,6 @@ func NewRegistry( devMode: devMode, Logger: logger, Compatibility: compatibility, - Termination: termination, } } diff --git a/plugin/plugin_registry_test.go b/plugin/plugin_registry_test.go index ef0ada0a..fcde9c44 100644 --- a/plugin/plugin_registry_test.go +++ b/plugin/plugin_registry_test.go @@ -33,7 +33,6 @@ func NewPluginRegistry(t *testing.T) *Registry { context.Background(), actRegistry, config.Loose, - config.Stop, logger, false, ) @@ -136,7 +135,6 @@ func BenchmarkHookRun(b *testing.B) { context.Background(), actRegistry, config.Loose, - config.Stop, logger, false, ) From 2b45ee70ad673fd00a47faef771366384957ccd9 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Thu, 29 Feb 2024 20:47:36 +0100 Subject: [PATCH 39/49] Fix bug in handling contradictory signals --- act/registry.go | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/act/registry.go b/act/registry.go index 6b25d479..51a2c7b7 100644 --- a/act/registry.go +++ b/act/registry.go @@ -2,6 +2,7 @@ package act import ( "context" + "slices" "time" sdkAct "github.com/gatewayd-io/gatewayd-plugin-sdk/act" @@ -90,21 +91,29 @@ func (r *Registry) Add(policy *sdkAct.Policy) { func (r *Registry) Apply(signals []sdkAct.Signal) []*sdkAct.Output { // If there are no signals, apply the default policy. if len(signals) == 0 { + r.logger.Debug().Msg("No signals provided, applying default signal") return r.Apply([]sdkAct.Signal{*r.DefaultSignal}) } - terminal := false + terminal := []string{} + nonTerminal := []string{} + for _, signal := range signals { + action, exists := r.Actions[signal.Name] + if exists && action.Sync && action.Terminal { + terminal = append(terminal, signal.Name) + } else if exists && action.Sync && !action.Terminal { + nonTerminal = append(nonTerminal, signal.Name) + } + } + outputs := []*sdkAct.Output{} for _, signal := range signals { - // Ignore contradictory actions (forward vs. terminate) if the signal is terminal. - // If the signal is terminal, all subsequent non-terminal signals are ignored. - // This is to prevent the user from shooting themselves in the foot. Also, it only + // Ignore contradictory actions (forward vs. terminate) if one of the signals is terminal. + // If the signal is terminal, all non-terminal signals are ignored. Also, it only // makes sense to have a terminal signal if the action is synchronous and terminal. - if action, exists := r.Actions[signal.Name]; exists && action.Sync && action.Terminal { - terminal = true - } else if exists && terminal && action.Sync && !action.Terminal { + if len(terminal) > 0 && slices.Contains(nonTerminal, signal.Name) { r.logger.Warn().Str("name", signal.Name).Msg( - "Contradictory action, ignoring signal") + "Terminal signal takes precedence, ignoring non-terminal signals") continue } From 4a39c8e84730368f9a5ee3325a73c2ecc46d9460 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Thu, 29 Feb 2024 23:52:17 +0100 Subject: [PATCH 40/49] Fix stack overflow when policy evaluation error occurs --- act/registry.go | 9 ++++++++- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/act/registry.go b/act/registry.go index 51a2c7b7..0887d7a5 100644 --- a/act/registry.go +++ b/act/registry.go @@ -2,6 +2,7 @@ package act import ( "context" + "errors" "slices" "time" @@ -107,6 +108,7 @@ func (r *Registry) Apply(signals []sdkAct.Signal) []*sdkAct.Output { } outputs := []*sdkAct.Output{} + evalErr := false for _, signal := range signals { // Ignore contradictory actions (forward vs. terminate) if one of the signals is terminal. // If the signal is terminal, all non-terminal signals are ignored. Also, it only @@ -120,12 +122,16 @@ func (r *Registry) Apply(signals []sdkAct.Signal) []*sdkAct.Output { output, err := r.apply(signal) if err != nil { r.logger.Error().Err(err).Str("name", signal.Name).Msg("Error applying signal") + if errors.Is(err, gerr.ErrEvalError) { + evalErr = true + } continue } + outputs = append(outputs, output) } - if len(outputs) == 0 { + if len(outputs) == 0 && !evalErr { return r.Apply([]sdkAct.Signal{*r.DefaultSignal}) } @@ -148,6 +154,7 @@ func (r *Registry) apply(signal sdkAct.Signal) (*sdkAct.Output, *gerr.GatewayDEr defer cancel() // Action dictates the sync mode, not the signal. + // TODO: Policy should be able to receive other parameters like server and client IPs, etc. verdict, err := policy.Eval( ctx, sdkAct.Input{ Name: signal.Name, diff --git a/go.mod b/go.mod index 16186473..268f5779 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/NYTimes/gziphandler v1.1.1 github.com/codingsince1985/checksum v1.3.0 github.com/envoyproxy/protoc-gen-validate v1.0.4 - github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.3 + github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.5 github.com/getsentry/sentry-go v0.27.0 github.com/go-co-op/gocron v1.37.0 github.com/google/go-github/v53 v53.2.0 diff --git a/go.sum b/go.sum index 7e3e459d..26ec896b 100644 --- a/go.sum +++ b/go.sum @@ -83,8 +83,8 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.3 h1:TzPoseln2War6SzqiJ/3HSceSB5vbJ9gCECz7Wy7pqE= -github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.3/go.mod h1:1XS2ufw+8VRTHAbDf18Y7rSPlOczeQ/baUWPqJrDkeE= +github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.5 h1:H1S4CKS4IfezxlvgBLtSJ/3s85wznxgxJEnwLys+kIM= +github.com/gatewayd-io/gatewayd-plugin-sdk v0.2.5/go.mod h1:1XS2ufw+8VRTHAbDf18Y7rSPlOczeQ/baUWPqJrDkeE= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= From bd2d65ba4ea2570cf37b7b6f1e34d3705b25115d Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Fri, 1 Mar 2024 00:01:27 +0100 Subject: [PATCH 41/49] Add more tests for policy registry Fix tests to reflect changes in the SDK --- act/registry_test.go | 239 +++++++++++++++++++++++++++++++++++++- plugin/plugin_registry.go | 2 +- plugin/utils_test.go | 2 +- 3 files changed, 238 insertions(+), 5 deletions(-) diff --git a/act/registry_test.go b/act/registry_test.go index f2d5487e..c3269a08 100644 --- a/act/registry_test.go +++ b/act/registry_test.go @@ -35,11 +35,43 @@ func Test_Add(t *testing.T) { config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) assert.NotNil(t, actRegistry) + assert.Len(t, actRegistry.Policies, len(BuiltinPolicies())) actRegistry.Add(&sdkAct.Policy{Name: "test-policy", Policy: "true"}) assert.NotNil(t, actRegistry.Policies["test-policy"]) assert.Equal(t, "test-policy", actRegistry.Policies["test-policy"].Name) assert.Equal(t, "true", actRegistry.Policies["test-policy"].Policy) assert.Nil(t, actRegistry.Policies["test-policy"].Metadata) + assert.Len(t, actRegistry.Policies, len(BuiltinPolicies())+1) +} + +// Test_Add_NilPolicy tests the Add function of the policy registry with a nil policy. +func Test_Add_NilPolicy(t *testing.T) { + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewRegistry( + BuiltinSignals(), map[string]*sdkAct.Policy{}, BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.NotNil(t, actRegistry) + + assert.Len(t, actRegistry.Policies, 0) + actRegistry.Add(nil) + assert.Len(t, actRegistry.Policies, 0) + assert.Contains(t, buf.String(), "Policy is nil, not adding") +} + +// Test_Add_ExistentPolicy tests the Add function of the policy registry with an existent policy. +func Test_Add_ExistentPolicy(t *testing.T) { + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewRegistry( + BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.NotNil(t, actRegistry) + + assert.Len(t, actRegistry.Policies, len(BuiltinPolicies())) + actRegistry.Add(BuiltinPolicies()["passthrough"]) + assert.Len(t, actRegistry.Policies, len(BuiltinPolicies())) + assert.Contains(t, buf.String(), "Policy already exists, overwriting") } // Test_Apply tests the Apply function of the policy registry. @@ -57,8 +89,179 @@ func Test_Apply(t *testing.T) { assert.Equal(t, "passthrough", outputs[0].MatchedPolicy) assert.Nil(t, outputs[0].Metadata) assert.True(t, outputs[0].Sync) - assert.True(t, outputs[0].Verdict) + assert.True(t, cast.ToBool(outputs[0].Verdict)) + assert.False(t, outputs[0].Terminal) +} + +// Test_Apply_NoSignals tests the Apply function of the policy registry with no signals. +// It should apply the default policy. +func Test_Apply_NoSignals(t *testing.T) { + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewRegistry( + BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.NotNil(t, actRegistry) + + outputs := actRegistry.Apply([]sdkAct.Signal{}) + assert.NotNil(t, outputs) + assert.Len(t, outputs, 1) + assert.Equal(t, "passthrough", outputs[0].MatchedPolicy) + assert.Nil(t, outputs[0].Metadata) + assert.True(t, outputs[0].Sync) + assert.True(t, cast.ToBool(outputs[0].Verdict)) assert.False(t, outputs[0].Terminal) + assert.Contains(t, buf.String(), "No signals provided, applying default signal") +} + +// Test_Apply_ContradictorySignals tests the Apply function of the policy registry +// with contradictory signals. The terminate signal should take precedence over +// the passthrough signal because it is a terminal action. The passthrough +// signal should be ignored. +func Test_Apply_ContradictorySignals(t *testing.T) { + // The following signals are contradictory because they have different actions. + // The terminate signal should take precedence over the passthrough signal. + // The order of the signals is NOT important. + signals := [][]sdkAct.Signal{ + { + *sdkAct.Terminate(), + *sdkAct.Passthrough(), + *sdkAct.Log("info", "test", map[string]any{"async": true}), + }, + { + *sdkAct.Passthrough(), + *sdkAct.Terminate(), + *sdkAct.Log("info", "test", map[string]any{"async": true}), + }, + } + + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewRegistry( + BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.NotNil(t, actRegistry) + + for _, s := range signals { + outputs := actRegistry.Apply(s) + assert.NotNil(t, outputs) + assert.Len(t, outputs, 2) + assert.Equal(t, "terminate", outputs[0].MatchedPolicy) + assert.Equal(t, outputs[0].Metadata, map[string]any{"terminate": true}) + assert.True(t, outputs[0].Sync) + assert.True(t, cast.ToBool(outputs[0].Verdict)) + assert.True(t, outputs[0].Terminal) + assert.Contains( + t, buf.String(), "Terminal signal takes precedence, ignoring non-terminal signals") + assert.Equal(t, "log", outputs[1].MatchedPolicy) + assert.Equal(t, + map[string]interface{}{ + "async": true, + "level": "info", + "log": true, + "message": "test", + }, + outputs[1].Metadata, + ) + assert.False(t, outputs[1].Sync) + assert.True(t, cast.ToBool(outputs[1].Verdict)) + assert.False(t, outputs[1].Terminal) + } +} + +// Test_Apply_ActionNotMatched tests the Apply function of the policy registry +// with a signal that does not match any action. The signal should be ignored. +// The default policy should be applied instead. +func Test_Apply_ActionNotMatched(t *testing.T) { + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewRegistry( + BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.NotNil(t, actRegistry) + + outputs := actRegistry.Apply([]sdkAct.Signal{ + {Name: "non-existent"}, + }) + assert.NotNil(t, outputs) + assert.Len(t, outputs, 1) + assert.Equal(t, "passthrough", outputs[0].MatchedPolicy) + assert.Nil(t, outputs[0].Metadata) + assert.True(t, outputs[0].Sync) + assert.True(t, cast.ToBool(outputs[0].Verdict)) + assert.False(t, outputs[0].Terminal) + assert.Contains(t, buf.String(), "{\"level\":\"error\",\"error\":\"no matching action\",\"name\":\"non-existent\",\"message\":\"Error applying signal\"}") //nolint:lll +} + +// Test_Apply_PolicyNotMatched tests the Apply function of the policy registry +// with a signal that does not match any policy. The signal should be ignored. +// The default policy should be applied instead. +func Test_Apply_PolicyNotMatched(t *testing.T) { + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewRegistry( + BuiltinSignals(), + map[string]*sdkAct.Policy{ + "passthrough": BuiltinPolicies()["passthrough"], + }, + BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.NotNil(t, actRegistry) + + outputs := actRegistry.Apply([]sdkAct.Signal{ + *sdkAct.Terminate(), + }) + assert.NotNil(t, outputs) + assert.Len(t, outputs, 1) + assert.Equal(t, "passthrough", outputs[0].MatchedPolicy) + assert.Nil(t, outputs[0].Metadata) + assert.True(t, outputs[0].Sync) + assert.True(t, cast.ToBool(outputs[0].Verdict)) + assert.False(t, outputs[0].Terminal) + assert.Contains(t, buf.String(), "{\"level\":\"error\",\"error\":\"no matching policy\",\"name\":\"terminate\",\"message\":\"Error applying signal\"}") //nolint:lll +} + +// Test_Apply_NonBoolPolicy tests the Apply function of the policy registry +// with a non-bool policy. +func Test_Apply_NonBoolPolicy(t *testing.T) { + badPolicies := []map[string]*sdkAct.Policy{ + { + "passthrough": sdkAct.MustNewPolicy( + "passthrough", + "2/0", + nil, + ), + }, + { + "passthrough": sdkAct.MustNewPolicy( + "passthrough", + "2+2", + nil, + ), + }, + } + + for _, policies := range badPolicies { + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewRegistry( + BuiltinSignals(), + policies, + BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.NotNil(t, actRegistry) + + outputs := actRegistry.Apply([]sdkAct.Signal{ + *sdkAct.Passthrough(), + }) + assert.NotNil(t, outputs) + assert.Len(t, outputs, 1) + assert.Equal(t, "passthrough", outputs[0].MatchedPolicy) + assert.Nil(t, outputs[0].Metadata) + assert.True(t, outputs[0].Sync) + assert.NotNil(t, outputs[0].Verdict) + assert.NotEmpty(t, outputs[0].Verdict) + } } // Test_Run tests the Run function of the policy registry with a non-terminal action. @@ -94,7 +297,7 @@ func Test_Run_Terminate(t *testing.T) { assert.Equal(t, "terminate", outputs[0].MatchedPolicy) assert.Equal(t, outputs[0].Metadata, map[string]interface{}{"terminate": true}) assert.True(t, outputs[0].Sync) - assert.True(t, outputs[0].Verdict) + assert.True(t, cast.ToBool(outputs[0].Verdict)) assert.True(t, outputs[0].Terminal) result, err := actRegistry.Run(outputs[0], WithResult(map[string]any{})) @@ -128,7 +331,7 @@ func Test_Run_Async(t *testing.T) { outputs[0].Metadata, ) assert.False(t, outputs[0].Sync) - assert.True(t, outputs[0].Verdict) + assert.True(t, cast.ToBool(outputs[0].Verdict)) assert.False(t, outputs[0].Terminal) result, err := actRegistry.Run(outputs[0], WithResult(map[string]any{})) @@ -142,3 +345,33 @@ func Test_Run_Async(t *testing.T) { // The following is the expected log output from the run function of the async action. assert.Contains(t, out.String(), "{\"level\":\"info\",\"async\":true,\"message\":\"test\"}") } + +// Test_Run_NilRegistry tests the Run function of the action with a nil output object. +func Test_Run_NilOutput(t *testing.T) { + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewRegistry( + BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.NotNil(t, actRegistry) + + result, err := actRegistry.Run(nil, WithLogger(logger)) + assert.Nil(t, result) + assert.Equal(t, err, gerr.ErrNilPointer) + assert.Contains(t, buf.String(), "Output is nil, run aborted") +} + +// Test_Run_ActionNotExist tests the Run function of the action with an empty output object. +func Test_Run_ActionNotExist(t *testing.T) { + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewRegistry( + BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.NotNil(t, actRegistry) + + result, err := actRegistry.Run(&sdkAct.Output{}, WithLogger(logger)) + assert.Nil(t, result) + assert.Equal(t, err, gerr.ErrActionNotExist) + assert.Contains(t, buf.String(), "Action does not exist, run aborted") +} diff --git a/plugin/plugin_registry.go b/plugin/plugin_registry.go index 1f73e1fc..3a54ce43 100644 --- a/plugin/plugin_registry.go +++ b/plugin/plugin_registry.go @@ -377,7 +377,7 @@ func (reg *Registry) Apply(hookName string, result *v1.Struct) ([]*sdkAct.Output // Check if any of the policies have a terminal action. var terminal bool for _, output := range outputs { - if output.Verdict && output.Terminal { + if output.Verdict != nil && output.Terminal { terminal = true break } diff --git a/plugin/utils_test.go b/plugin/utils_test.go index 7c6581fc..9bdd2761 100644 --- a/plugin/utils_test.go +++ b/plugin/utils_test.go @@ -102,7 +102,7 @@ func Test_applyPolicies(t *testing.T) { assert.Nil(t, output[0].Metadata) assert.True(t, output[0].Sync) assert.False(t, output[0].Terminal) - assert.True(t, output[0].Verdict) + assert.True(t, cast.ToBool(output[0].Verdict)) result, gerr := actRegistry.Run(output[0], act.WithLogger(logger)) assert.Nil(t, gerr) From 86e51048d6b02222bbf82212eecc1b30b24804a6 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Fri, 1 Mar 2024 00:21:52 +0100 Subject: [PATCH 42/49] Add coverage report to test target --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1e1fb437..bdcf9929 100644 --- a/Makefile +++ b/Makefile @@ -108,7 +108,7 @@ clean: @rm -rf dist test: - @go test -v ./... + @go test -v -cover -coverprofile=c.out ./... test-race: @go test -race -v ./... From 4e2698f2857e9f3c204f714bf525e353b62db3e0 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Fri, 1 Mar 2024 00:22:32 +0100 Subject: [PATCH 43/49] Rename policy registry to act registry Add a test for bad policies --- .gitignore | 1 + act/registry.go | 16 ++++++- act/registry_test.go | 86 +++++++++++++++++++++++----------- api/api_test.go | 6 +-- cmd/run.go | 17 ++++--- errors/errors.go | 13 ++--- network/proxy.go | 2 +- network/proxy_test.go | 24 +++++----- network/server_test.go | 14 +++--- plugin/plugin_registry.go | 10 ++-- plugin/plugin_registry_test.go | 4 +- plugin/utils_test.go | 2 +- 12 files changed, 123 insertions(+), 72 deletions(-) diff --git a/.gitignore b/.gitignore index 78b3074d..2a04f75e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out +go-carpet-coverage-out* # Dependency directories (remove the comment below to include it) # vendor/ diff --git a/act/registry.go b/act/registry.go index 0887d7a5..b9cdb324 100644 --- a/act/registry.go +++ b/act/registry.go @@ -32,8 +32,8 @@ type Registry struct { var _ IRegistry = (*Registry)(nil) -// NewRegistry creates a new registry with the specified default policy and timeout. -func NewRegistry( +// NewActRegistry creates a new act registry with the specified default policy and timeout. +func NewActRegistry( builtinSignals map[string]*sdkAct.Signal, builtinsPolicies map[string]*sdkAct.Policy, builtinActions map[string]*sdkAct.Action, @@ -42,14 +42,26 @@ func NewRegistry( logger zerolog.Logger, ) *Registry { for _, signal := range builtinSignals { + if signal == nil { + logger.Warn().Msg("Signal is nil, not adding") + return nil + } logger.Debug().Str("name", signal.Name).Msg("Registered builtin signal") } for _, policy := range builtinsPolicies { + if policy == nil { + logger.Warn().Msg("Policy is nil, not adding") + return nil + } logger.Debug().Str("name", policy.Name).Msg("Registered builtin policy") } for _, action := range builtinActions { + if action == nil { + logger.Warn().Msg("Action is nil, not adding") + return nil + } logger.Debug().Str("name", action.Name).Msg("Registered builtin action") } diff --git a/act/registry_test.go b/act/registry_test.go index c3269a08..ccff581c 100644 --- a/act/registry_test.go +++ b/act/registry_test.go @@ -17,7 +17,7 @@ import ( func Test_NewRegistry(t *testing.T) { logger := zerolog.Logger{} - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) assert.NotNil(t, actRegistry) @@ -28,9 +28,9 @@ func Test_NewRegistry(t *testing.T) { assert.Equal(t, config.DefaultPolicy, actRegistry.DefaultSignal.Name) } -// Test_Add tests the Add function of the policy registry. +// Test_Add tests the Add function of the act registry. func Test_Add(t *testing.T) { - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) assert.NotNil(t, actRegistry) @@ -44,11 +44,11 @@ func Test_Add(t *testing.T) { assert.Len(t, actRegistry.Policies, len(BuiltinPolicies())+1) } -// Test_Add_NilPolicy tests the Add function of the policy registry with a nil policy. +// Test_Add_NilPolicy tests the Add function of the act registry with a nil policy. func Test_Add_NilPolicy(t *testing.T) { buf := bytes.Buffer{} logger := zerolog.New(&buf) - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), map[string]*sdkAct.Policy{}, BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) assert.NotNil(t, actRegistry) @@ -59,11 +59,11 @@ func Test_Add_NilPolicy(t *testing.T) { assert.Contains(t, buf.String(), "Policy is nil, not adding") } -// Test_Add_ExistentPolicy tests the Add function of the policy registry with an existent policy. +// Test_Add_ExistentPolicy tests the Add function of the act registry with an existent policy. func Test_Add_ExistentPolicy(t *testing.T) { buf := bytes.Buffer{} logger := zerolog.New(&buf) - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) assert.NotNil(t, actRegistry) @@ -74,9 +74,9 @@ func Test_Add_ExistentPolicy(t *testing.T) { assert.Contains(t, buf.String(), "Policy already exists, overwriting") } -// Test_Apply tests the Apply function of the policy registry. +// Test_Apply tests the Apply function of the act registry. func Test_Apply(t *testing.T) { - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) assert.NotNil(t, actRegistry) @@ -93,12 +93,12 @@ func Test_Apply(t *testing.T) { assert.False(t, outputs[0].Terminal) } -// Test_Apply_NoSignals tests the Apply function of the policy registry with no signals. +// Test_Apply_NoSignals tests the Apply function of the act registry with no signals. // It should apply the default policy. func Test_Apply_NoSignals(t *testing.T) { buf := bytes.Buffer{} logger := zerolog.New(&buf) - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) assert.NotNil(t, actRegistry) @@ -114,7 +114,7 @@ func Test_Apply_NoSignals(t *testing.T) { assert.Contains(t, buf.String(), "No signals provided, applying default signal") } -// Test_Apply_ContradictorySignals tests the Apply function of the policy registry +// Test_Apply_ContradictorySignals tests the Apply function of the act registry // with contradictory signals. The terminate signal should take precedence over // the passthrough signal because it is a terminal action. The passthrough // signal should be ignored. @@ -137,7 +137,7 @@ func Test_Apply_ContradictorySignals(t *testing.T) { buf := bytes.Buffer{} logger := zerolog.New(&buf) - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) assert.NotNil(t, actRegistry) @@ -169,13 +169,13 @@ func Test_Apply_ContradictorySignals(t *testing.T) { } } -// Test_Apply_ActionNotMatched tests the Apply function of the policy registry +// Test_Apply_ActionNotMatched tests the Apply function of the act registry // with a signal that does not match any action. The signal should be ignored. // The default policy should be applied instead. func Test_Apply_ActionNotMatched(t *testing.T) { buf := bytes.Buffer{} logger := zerolog.New(&buf) - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) assert.NotNil(t, actRegistry) @@ -193,13 +193,13 @@ func Test_Apply_ActionNotMatched(t *testing.T) { assert.Contains(t, buf.String(), "{\"level\":\"error\",\"error\":\"no matching action\",\"name\":\"non-existent\",\"message\":\"Error applying signal\"}") //nolint:lll } -// Test_Apply_PolicyNotMatched tests the Apply function of the policy registry +// Test_Apply_PolicyNotMatched tests the Apply function of the act registry // with a signal that does not match any policy. The signal should be ignored. // The default policy should be applied instead. func Test_Apply_PolicyNotMatched(t *testing.T) { buf := bytes.Buffer{} logger := zerolog.New(&buf) - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), map[string]*sdkAct.Policy{ "passthrough": BuiltinPolicies()["passthrough"], @@ -221,7 +221,7 @@ func Test_Apply_PolicyNotMatched(t *testing.T) { assert.Contains(t, buf.String(), "{\"level\":\"error\",\"error\":\"no matching policy\",\"name\":\"terminate\",\"message\":\"Error applying signal\"}") //nolint:lll } -// Test_Apply_NonBoolPolicy tests the Apply function of the policy registry +// Test_Apply_NonBoolPolicy tests the Apply function of the act registry // with a non-bool policy. func Test_Apply_NonBoolPolicy(t *testing.T) { badPolicies := []map[string]*sdkAct.Policy{ @@ -244,7 +244,7 @@ func Test_Apply_NonBoolPolicy(t *testing.T) { for _, policies := range badPolicies { buf := bytes.Buffer{} logger := zerolog.New(&buf) - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), policies, BuiltinActions(), @@ -264,10 +264,42 @@ func Test_Apply_NonBoolPolicy(t *testing.T) { } } -// Test_Run tests the Run function of the policy registry with a non-terminal action. +// Test_Apply_BadPolicy tests the NewRegistry function with a bad policy, +// which should return a nil registry. +func Test_Apply_BadPolicy(t *testing.T) { + badPolicies := []map[string]*sdkAct.Policy{ + { + "passthrough": sdkAct.MustNewPolicy( + "passthrough", + "2/0 + 'test'", + nil, + ), + }, + { + "passthrough": sdkAct.MustNewPolicy( + "passthrough", + "2+2+true", + nil, + ), + }, + } + + for _, policies := range badPolicies { + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewActRegistry( + BuiltinSignals(), + policies, + BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.Nil(t, actRegistry) + } +} + +// Test_Run tests the Run function of the act registry with a non-terminal action. func Test_Run(t *testing.T) { logger := zerolog.Logger{} - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) assert.NotNil(t, actRegistry) @@ -282,10 +314,10 @@ func Test_Run(t *testing.T) { assert.True(t, cast.ToBool(result)) } -// Test_Run_Terminate tests the Run function of the policy registry with a terminal action. +// Test_Run_Terminate tests the Run function of the act registry with a terminal action. func Test_Run_Terminate(t *testing.T) { logger := zerolog.Logger{} - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) assert.NotNil(t, actRegistry) @@ -307,11 +339,11 @@ func Test_Run_Terminate(t *testing.T) { assert.NotEmpty(t, resultMap["response"]) } -// Test_Run_Async tests the Run function of the policy registry with an asynchronous action. +// Test_Run_Async tests the Run function of the act registry with an asynchronous action. func Test_Run_Async(t *testing.T) { out := bytes.Buffer{} logger := zerolog.New(&out) - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) assert.NotNil(t, actRegistry) @@ -350,7 +382,7 @@ func Test_Run_Async(t *testing.T) { func Test_Run_NilOutput(t *testing.T) { buf := bytes.Buffer{} logger := zerolog.New(&buf) - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) assert.NotNil(t, actRegistry) @@ -365,7 +397,7 @@ func Test_Run_NilOutput(t *testing.T) { func Test_Run_ActionNotExist(t *testing.T) { buf := bytes.Buffer{} logger := zerolog.New(&buf) - actRegistry := NewRegistry( + actRegistry := NewActRegistry( BuiltinSignals(), BuiltinPolicies(), BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) assert.NotNil(t, actRegistry) diff --git a/api/api_test.go b/api/api_test.go index 9d264a92..7beec0db 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -106,7 +106,7 @@ func TestGetPluginConfig(t *testing.T) { } func TestGetPlugins(t *testing.T) { - actRegistry := act.NewRegistry( + actRegistry := act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) pluginRegistry := plugin.NewRegistry( @@ -135,7 +135,7 @@ func TestGetPlugins(t *testing.T) { } func TestGetPluginsWithEmptyPluginRegistry(t *testing.T) { - actRegistry := act.NewRegistry( + actRegistry := act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) pluginRegistry := plugin.NewRegistry( @@ -243,7 +243,7 @@ func TestGetServers(t *testing.T) { config.DefaultPluginTimeout, ) - actRegistry := act.NewRegistry( + actRegistry := act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, zerolog.Logger{}) diff --git a/cmd/run.go b/cmd/run.go index d4452ca9..7ad42f48 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -57,7 +57,7 @@ var ( globalConfigFile string conf *config.Config pluginRegistry *plugin.Registry - policiesRegistry *act.Registry + actRegistry *act.Registry metricsServer *http.Server UsageReportURL = "localhost:59091" @@ -253,12 +253,17 @@ var runCmd = &cobra.Command{ "Running GatewayD in development mode (not recommended for production)") } - // Create a new policy registry given the built-in signals, policies, and actions. - policiesRegistry = act.NewRegistry( + // Create a new act registry given the built-in signals, policies, and actions. + actRegistry = act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), conf.Plugin.DefaultPolicy, conf.Plugin.PolicyTimeout, logger, ) + if actRegistry == nil { + logger.Error().Msg("Failed to create act registry") + os.Exit(gerr.FailedToCreateActRegistry) + } + // Load policies from the configuration file and add them to the registry. for _, plc := range conf.Plugin.Policies { if policy, err := sdkAct.NewPolicy( @@ -266,19 +271,19 @@ var runCmd = &cobra.Command{ ); err != nil || policy == nil { logger.Error().Err(err).Str("name", plc.Name).Msg("Failed to create policy") } else { - policiesRegistry.Add(policy) + actRegistry.Add(policy) } } logger.Info().Fields(map[string]interface{}{ - "policies": maps.Keys(policiesRegistry.Policies), + "policies": maps.Keys(actRegistry.Policies), }).Msg("Policies are loaded") // Create a new plugin registry. // The plugins are loaded and hooks registered before the configuration is loaded. pluginRegistry = plugin.NewRegistry( runCtx, - policiesRegistry, + actRegistry, config.If[config.CompatibilityPolicy]( config.Exists[string, config.CompatibilityPolicy]( config.CompatibilityPolicies, conf.Plugin.CompatibilityPolicy), diff --git a/errors/errors.go b/errors/errors.go index 84b631f0..c7cf7ae1 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -158,10 +158,11 @@ var ( ) const ( - FailedToLoadPluginConfig = 1 - FailedToLoadGlobalConfig = 2 - FailedToCreateClient = 3 - FailedToInitializePool = 4 - FailedToStartServer = 5 - FailedToStartTracer = 6 + FailedToLoadPluginConfig = 1 + FailedToLoadGlobalConfig = 2 + FailedToCreateClient = 3 + FailedToInitializePool = 4 + FailedToStartServer = 5 + FailedToStartTracer = 6 + FailedToCreateActRegistry = 7 ) diff --git a/network/proxy.go b/network/proxy.go index 3bf5f81b..0a3f500d 100644 --- a/network/proxy.go +++ b/network/proxy.go @@ -860,7 +860,7 @@ func (pr *Proxy) shouldTerminate(result map[string]interface{}) (bool, map[strin if slices.Contains(keys, sdkAct.Terminal) { var actionResult map[string]interface{} for _, output := range outputs { - actRes, err := pr.pluginRegistry.PolicyRegistry().Run( + actRes, err := pr.pluginRegistry.ActRegistry().Run( output, act.WithResult(result)) // If the action is async and we received a sentinel error, // don't log the error. diff --git a/network/proxy_test.go b/network/proxy_test.go index 7110e430..e340fae2 100644 --- a/network/proxy_test.go +++ b/network/proxy_test.go @@ -44,8 +44,8 @@ func TestNewProxy(t *testing.T) { err := newPool.Put(client.ID, client) assert.Nil(t, err) - // Create a new Act registry - actRegistry := act.NewRegistry( + // Create a new act registry + actRegistry := act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) @@ -90,8 +90,8 @@ func BenchmarkNewProxy(b *testing.B) { // Create a connection newPool newPool := pool.NewPool(context.Background(), config.EmptyPoolCapacity) - // Create a new Act registry - actRegistry := act.NewRegistry( + // Create a new act registry + actRegistry := act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) @@ -139,8 +139,8 @@ func BenchmarkProxyConnectDisconnect(b *testing.B) { } newPool.Put("client", NewClient(context.Background(), &clientConfig, logger, nil)) //nolint:errcheck - // Create a new Act registry - actRegistry := act.NewRegistry( + // Create a new act registry + actRegistry := act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) @@ -194,8 +194,8 @@ func BenchmarkProxyPassThrough(b *testing.B) { } newPool.Put("client", NewClient(context.Background(), &clientConfig, logger, nil)) //nolint:errcheck - // Create a new Act registry - actRegistry := act.NewRegistry( + // Create a new act registry + actRegistry := act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) @@ -254,8 +254,8 @@ func BenchmarkProxyIsHealthyAndIsExhausted(b *testing.B) { client := NewClient(context.Background(), &clientConfig, logger, nil) newPool.Put("client", client) //nolint:errcheck - // Create a new Act registry - actRegistry := act.NewRegistry( + // Create a new act registry + actRegistry := act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) @@ -312,8 +312,8 @@ func BenchmarkProxyAvailableAndBusyConnections(b *testing.B) { client := NewClient(context.Background(), &clientConfig, logger, nil) newPool.Put("client", client) //nolint:errcheck - // Create a new Act registry - actRegistry := act.NewRegistry( + // Create a new act registry + actRegistry := act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) diff --git a/network/server_test.go b/network/server_test.go index 7ca01905..95658778 100644 --- a/network/server_test.go +++ b/network/server_test.go @@ -39,7 +39,7 @@ func TestRunServer(t *testing.T) { FileName: "server_test.log", }) - actRegistry := act.NewRegistry( + actRegistry := act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) pluginRegistry := plugin.NewRegistry( @@ -55,12 +55,12 @@ func TestRunServer(t *testing.T) { pluginRegistry.AddHook(v1.HookName_HOOK_NAME_ON_TRAFFIC_FROM_SERVER, 1, onOutgoingTraffic) pluginRegistry.AddHook(v1.HookName_HOOK_NAME_ON_TRAFFIC_TO_CLIENT, 1, onOutgoingTraffic) - assert.NotNil(t, pluginRegistry.PolicyRegistry()) - assert.NotNil(t, pluginRegistry.PolicyRegistry().Signals) - assert.NotNil(t, pluginRegistry.PolicyRegistry().Policies) - assert.NotNil(t, pluginRegistry.PolicyRegistry().Actions) - assert.Equal(t, config.DefaultPolicy, pluginRegistry.PolicyRegistry().DefaultPolicy.Name) - assert.Equal(t, config.DefaultPolicy, pluginRegistry.PolicyRegistry().DefaultSignal.Name) + assert.NotNil(t, pluginRegistry.ActRegistry()) + assert.NotNil(t, pluginRegistry.ActRegistry().Signals) + assert.NotNil(t, pluginRegistry.ActRegistry().Policies) + assert.NotNil(t, pluginRegistry.ActRegistry().Actions) + assert.Equal(t, config.DefaultPolicy, pluginRegistry.ActRegistry().DefaultPolicy.Name) + assert.Equal(t, config.DefaultPolicy, pluginRegistry.ActRegistry().DefaultSignal.Name) clientConfig := config.Client{ Network: "tcp", diff --git a/plugin/plugin_registry.go b/plugin/plugin_registry.go index 3a54ce43..7272f010 100644 --- a/plugin/plugin_registry.go +++ b/plugin/plugin_registry.go @@ -50,7 +50,7 @@ type IRegistry interface { LoadPlugins(ctx context.Context, plugins []config.Plugin, startTimeout time.Duration) RegisterHooks(ctx context.Context, pluginID sdkPlugin.Identifier) Apply(hookName string, result *v1.Struct) ([]*sdkAct.Output, bool) - PolicyRegistry() *act.Registry + ActRegistry() *act.Registry // Hook management IHook @@ -365,7 +365,7 @@ func (reg *Registry) Apply(hookName string, result *v1.Struct) ([]*sdkAct.Output // Apply policies to the signals. // The outputs contains the verdicts of the policies and their metadata. // And using this list, the caller can take further actions. - outputs := applyPolicies(hookName, signals, reg.Logger, reg.PolicyRegistry()) + outputs := applyPolicies(hookName, signals, reg.Logger, reg.ActRegistry()) // If no policies are found, return a default output. // Note: this should never happen, as the default policy is always loaded. @@ -729,9 +729,9 @@ func (reg *Registry) RegisterHooks(ctx context.Context, pluginID sdkPlugin.Ident } } -// PolicyRegistry returns the policy registry. -func (reg *Registry) PolicyRegistry() *act.Registry { - _, span := otel.Tracer(config.TracerName).Start(reg.ctx, "PolicyRegistry") +// ActRegistry returns the act registry. +func (reg *Registry) ActRegistry() *act.Registry { + _, span := otel.Tracer(config.TracerName).Start(reg.ctx, "ActRegistry") defer span.End() return reg.policiesRegistry } diff --git a/plugin/plugin_registry_test.go b/plugin/plugin_registry_test.go index fcde9c44..ff8b911b 100644 --- a/plugin/plugin_registry_test.go +++ b/plugin/plugin_registry_test.go @@ -26,7 +26,7 @@ func NewPluginRegistry(t *testing.T) *Registry { NoColor: true, } logger := logging.NewLogger(context.Background(), cfg) - actRegistry := act.NewRegistry( + actRegistry := act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) reg := NewRegistry( @@ -128,7 +128,7 @@ func BenchmarkHookRun(b *testing.B) { NoColor: true, } logger := logging.NewLogger(context.Background(), cfg) - actRegistry := act.NewRegistry( + actRegistry := act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger) reg := NewRegistry( diff --git a/plugin/utils_test.go b/plugin/utils_test.go index 9bdd2761..e123c8ad 100644 --- a/plugin/utils_test.go +++ b/plugin/utils_test.go @@ -90,7 +90,7 @@ func Test_getSignals_empty(t *testing.T) { // It also tests the Run function of the registered passthrough (built-in) action. func Test_applyPolicies(t *testing.T) { logger := zerolog.Logger{} - actRegistry := act.NewRegistry( + actRegistry := act.NewActRegistry( act.BuiltinSignals(), act.BuiltinPolicies(), act.BuiltinActions(), config.DefaultPolicy, config.DefaultPolicyTimeout, logger, ) From bbda501082999beb04056ded242bef2a04592fed Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Fri, 1 Mar 2024 17:10:58 +0100 Subject: [PATCH 44/49] Add comments and slightly refactor action functions --- act/builtins.go | 91 ++++++++++++++++++++++++++----------------------- act/registry.go | 9 +++-- 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/act/builtins.go b/act/builtins.go index 41dca12a..65c8fadb 100644 --- a/act/builtins.go +++ b/act/builtins.go @@ -65,78 +65,85 @@ func BuiltinActions() map[string]*sdkAct.Action { } } +// Passthrough is a built-in action that always returns true and no error. func Passthrough(map[string]any, ...sdkAct.Parameter) (any, error) { return true, nil } +// Terminate is a built-in action that terminates the connection if the +// terminate signal is true and the policy is set to "stop". The action +// can optionally receive a result parameter. func Terminate(_ map[string]any, params ...sdkAct.Parameter) (any, error) { - if len(params) == 0 || params[0].Key != "logger" { + if len(params) == 0 || params[0].Key != LoggerKey { + // No logger parameter or the first parameter is not a logger. return nil, gerr.ErrLoggerRequired } logger, ok := params[0].Value.(zerolog.Logger) if !ok { + // The first parameter is not a logger. return nil, gerr.ErrLoggerRequired } - if len(params) >= TerminateDefaultFieldCount { - if params[1].Key != "result" { - logger.Debug().Msg( - "terminate action can optionally receive a result parameter") - return true, nil - } - - result, ok := params[1].Value.(map[string]any) - if !ok { - logger.Debug().Msg("terminate action can receive a result parameter") - return true, nil - } + if len(params) < TerminateDefaultFieldCount || params[1].Key != ResultKey { + logger.Debug().Msg( + "terminate action can optionally receive a result parameter") + return true, nil + } - // If the result from the plugin does not contain a response, - // yet it is a terminal action (hence running this action), - // add an error response to the result and terminate the connection. - if _, exists := result["response"]; !exists { - logger.Trace().Fields(result).Msg( - "Terminating without response, returning an error response") - result["response"] = (&pgproto3.Terminate{}).Encode( - postgres.ErrorResponse( - "Request terminated", - "ERROR", - "42000", - "Policy terminated the request", - ), - ) - } + result, ok := params[1].Value.(map[string]any) + if !ok { + logger.Debug().Msg("terminate action received a non-map result parameter") + return true, nil + } - return result, nil + // If the result from the plugin does not contain a response, + // yet it is a terminal action (hence running this action), + // add an error response to the result and terminate the connection. + if _, exists := result["response"]; !exists { + logger.Trace().Fields(result).Msg( + "Terminating without response, returning an error response") + result["response"] = (&pgproto3.Terminate{}).Encode( + postgres.ErrorResponse( + "Request terminated", + "ERROR", + "42000", + "Policy terminated the request", + ), + ) } - return true, nil + return result, nil } +// Log is a built-in action that logs the data received from the plugin. func Log(data map[string]any, params ...sdkAct.Parameter) (any, error) { + if len(params) == 0 || params[0].Key != LoggerKey { + // No logger parameter or the first parameter is not a logger. + return nil, gerr.ErrLoggerRequired + } + + logger, ok := params[0].Value.(zerolog.Logger) + if !ok { + // The first parameter is not a logger. + return nil, gerr.ErrLoggerRequired + } + fields := map[string]any{} - // Only log the fields that are not level, message, or log. if len(data) > LogDefaultFieldCount { for k, v := range data { + // Skip these necessary fields, as they are already used by the logger. + // level: The log level. + // message: The log message. + // log: The log signal. if k == "level" || k == "message" || k == "log" { continue } + // Add the rest of the fields to the logger as extra fields. fields[k] = v } } - if len(params) == 0 || params[0].Key != "logger" { - // No logger parameter or the first parameter is not a logger. - return false, nil - } - - logger, ok := params[0].Value.(zerolog.Logger) - if !ok { - // The first parameter is not a logger. - return false, nil - } - logger.WithLevel( logging.GetZeroLogLevel(cast.ToString(data["level"])), ).Fields(fields).Msg(cast.ToString(data["message"])) diff --git a/act/registry.go b/act/registry.go index b9cdb324..c185996e 100644 --- a/act/registry.go +++ b/act/registry.go @@ -11,6 +11,11 @@ import ( "github.com/rs/zerolog" ) +const ( + LoggerKey = "__logger__" + ResultKey = "__result__" +) + type IRegistry interface { Add(policy *sdkAct.Policy) Apply(signals []sdkAct.Signal) []*sdkAct.Output @@ -248,7 +253,7 @@ func (r *Registry) Run( // This is automatically prepended to the parameters when running an action. func WithLogger(logger zerolog.Logger) sdkAct.Parameter { return sdkAct.Parameter{ - Key: "logger", + Key: LoggerKey, Value: logger, } } @@ -257,7 +262,7 @@ func WithLogger(logger zerolog.Logger) sdkAct.Parameter { // to be used by the action. func WithResult(result map[string]any) sdkAct.Parameter { return sdkAct.Parameter{ - Key: "result", + Key: ResultKey, Value: result, } } From a5126a094792b96edb048df25fc251a4cec480c0 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Fri, 1 Mar 2024 17:17:34 +0100 Subject: [PATCH 45/49] Refactor and rename variables and add comments --- act/builtins.go | 18 ++++++++++++++---- act/registry.go | 5 ----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/act/builtins.go b/act/builtins.go index 65c8fadb..24a90189 100644 --- a/act/builtins.go +++ b/act/builtins.go @@ -11,10 +11,18 @@ import ( ) const ( - LogDefaultFieldCount = 3 - TerminateDefaultFieldCount = 2 + // TerminateDefaultParamCount is the default parameter count for the terminate action. + TerminateDefaultParamCount = 2 + + // LogDefaultKeyCount is the default key count in the metadata for the log action. + LogDefaultKeyCount = 3 + + // These are the keys used to pass the logger and the result to the built-in actions. + LoggerKey = "__logger__" + ResultKey = "__result__" ) +// BuiltinSignals returns a map of built-in signals. func BuiltinSignals() map[string]*sdkAct.Signal { return map[string]*sdkAct.Signal{ "passthrough": sdkAct.Passthrough(), @@ -23,6 +31,7 @@ func BuiltinSignals() map[string]*sdkAct.Signal { } } +// BuiltinPolicies returns a map of built-in policies. func BuiltinPolicies() map[string]*sdkAct.Policy { return map[string]*sdkAct.Policy{ "passthrough": sdkAct.MustNewPolicy("passthrough", "true", nil), @@ -39,6 +48,7 @@ func BuiltinPolicies() map[string]*sdkAct.Policy { } } +// BuiltinActions returns a map of built-in actions. func BuiltinActions() map[string]*sdkAct.Action { return map[string]*sdkAct.Action{ "passthrough": { @@ -85,7 +95,7 @@ func Terminate(_ map[string]any, params ...sdkAct.Parameter) (any, error) { return nil, gerr.ErrLoggerRequired } - if len(params) < TerminateDefaultFieldCount || params[1].Key != ResultKey { + if len(params) < TerminateDefaultParamCount || params[1].Key != ResultKey { logger.Debug().Msg( "terminate action can optionally receive a result parameter") return true, nil @@ -130,7 +140,7 @@ func Log(data map[string]any, params ...sdkAct.Parameter) (any, error) { } fields := map[string]any{} - if len(data) > LogDefaultFieldCount { + if len(data) > LogDefaultKeyCount { for k, v := range data { // Skip these necessary fields, as they are already used by the logger. // level: The log level. diff --git a/act/registry.go b/act/registry.go index c185996e..3a4857c8 100644 --- a/act/registry.go +++ b/act/registry.go @@ -11,11 +11,6 @@ import ( "github.com/rs/zerolog" ) -const ( - LoggerKey = "__logger__" - ResultKey = "__result__" -) - type IRegistry interface { Add(policy *sdkAct.Policy) Apply(signals []sdkAct.Signal) []*sdkAct.Output From a2a13e71bf4f69b3c945c326668110ff0c754601 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Fri, 1 Mar 2024 17:23:07 +0100 Subject: [PATCH 46/49] Add more tests for nils --- act/registry.go | 8 ++++++- act/registry_test.go | 57 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/act/registry.go b/act/registry.go index 3a4857c8..69b08ca9 100644 --- a/act/registry.go +++ b/act/registry.go @@ -32,7 +32,8 @@ type Registry struct { var _ IRegistry = (*Registry)(nil) -// NewActRegistry creates a new act registry with the specified default policy and timeout. +// NewActRegistry creates a new act registry with the specified default policy and timeout +// and the builtin signals, policies, and actions. func NewActRegistry( builtinSignals map[string]*sdkAct.Signal, builtinsPolicies map[string]*sdkAct.Policy, @@ -41,6 +42,11 @@ func NewActRegistry( policyTimeout time.Duration, logger zerolog.Logger, ) *Registry { + if builtinSignals == nil || builtinsPolicies == nil || builtinActions == nil { + logger.Warn().Msg("Builtin signals, policies, or actions are nil, not adding") + return nil + } + for _, signal := range builtinSignals { if signal == nil { logger.Warn().Msg("Signal is nil, not adding") diff --git a/act/registry_test.go b/act/registry_test.go index ccff581c..e3e54893 100644 --- a/act/registry_test.go +++ b/act/registry_test.go @@ -28,6 +28,63 @@ func Test_NewRegistry(t *testing.T) { assert.Equal(t, config.DefaultPolicy, actRegistry.DefaultSignal.Name) } +// Test_NewRegistry_NilSignals tests the NewRegistry function with nil signals, +// actions, and policies. It should return a nil registry. +func Test_NewRegistry_NilBuiltins(t *testing.T) { + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewActRegistry( + nil, nil, nil, config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.Nil(t, actRegistry) + assert.Contains(t, buf.String(), "Builtin signals, policies, or actions are nil, not adding") +} + +// Test_NewRegistry_NilPolicy tests the NewRegistry function with a nil signal. +// It should return a nil registry. +func Test_NewRegistry_NilSignal(t *testing.T) { + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewActRegistry( + map[string]*sdkAct.Signal{ + "bad": nil, + }, + BuiltinPolicies(), BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.Nil(t, actRegistry) + assert.Contains(t, buf.String(), "Signal is nil, not adding") +} + +// Test_NewRegistry_NilPolicy tests the NewRegistry function with a nil policy. +// It should return a nil registry. +func Test_NewRegistry_NilPolicy(t *testing.T) { + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewActRegistry( + BuiltinSignals(), + map[string]*sdkAct.Policy{ + "bad": nil, + }, + BuiltinActions(), + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.Nil(t, actRegistry) + assert.Contains(t, buf.String(), "Policy is nil, not adding") +} + +// Test_NewRegistry_NilAction tests the NewRegistry function with a nil action. +// It should return a nil registry. +func Test_NewRegistry_NilAction(t *testing.T) { + buf := bytes.Buffer{} + logger := zerolog.New(&buf) + actRegistry := NewActRegistry( + BuiltinSignals(), BuiltinPolicies(), + map[string]*sdkAct.Action{ + "bad": nil, + }, + config.DefaultPolicy, config.DefaultPolicyTimeout, logger) + assert.Nil(t, actRegistry) + assert.Contains(t, buf.String(), "Action is nil, not adding") +} + // Test_Add tests the Add function of the act registry. func Test_Add(t *testing.T) { actRegistry := NewActRegistry( From 710a2da75f32c1b7382dfc8efe10d6a862b18a0a Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Fri, 1 Mar 2024 17:33:41 +0100 Subject: [PATCH 47/49] Add comments --- act/registry.go | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/act/registry.go b/act/registry.go index 69b08ca9..6dea7a59 100644 --- a/act/registry.go +++ b/act/registry.go @@ -7,6 +7,7 @@ import ( "time" sdkAct "github.com/gatewayd-io/gatewayd-plugin-sdk/act" + "github.com/gatewayd-io/gatewayd/config" gerr "github.com/gatewayd-io/gatewayd/errors" "github.com/rs/zerolog" ) @@ -73,9 +74,9 @@ func NewActRegistry( // The default policy must exist, otherwise use passthrough. if _, exists := builtinsPolicies[defaultPolicy]; !exists || defaultPolicy == "" { - logger.Warn().Str("name", defaultPolicy).Msg( - "The specified default policy does not exist, using passthrough") - defaultPolicy = "passthrough" + logger.Warn().Str("name", defaultPolicy).Msgf( + "The specified default policy does not exist, using %s", config.DefaultPolicy) + defaultPolicy = config.DefaultPolicy } logger.Debug().Str("name", defaultPolicy).Msg("Using default policy") @@ -114,6 +115,7 @@ func (r *Registry) Apply(signals []sdkAct.Signal) []*sdkAct.Output { return r.Apply([]sdkAct.Signal{*r.DefaultSignal}) } + // Separate terminal and non-terminal signals to find contradictions. terminal := []string{} nonTerminal := []string{} for _, signal := range signals { @@ -137,9 +139,13 @@ func (r *Registry) Apply(signals []sdkAct.Signal) []*sdkAct.Output { continue } + // Apply the signal and append the output to the list of outputs. output, err := r.apply(signal) if err != nil { r.logger.Error().Err(err).Str("name", signal.Name).Msg("Error applying signal") + // If there is an error evaluating the policy, continue to the next signal. + // This also prevents stack overflows from infinite loops of the external + // if condition below. if errors.Is(err, gerr.ErrEvalError) { evalErr = true } @@ -168,17 +174,19 @@ func (r *Registry) apply(signal sdkAct.Signal) (*sdkAct.Output, *gerr.GatewayDEr return nil, gerr.ErrPolicyNotMatched } + // Create a context with a timeout for policy evaluation. ctx, cancel := context.WithTimeout(context.Background(), r.policyTimeout) defer cancel() - // Action dictates the sync mode, not the signal. + // Evaluate the policy. // TODO: Policy should be able to receive other parameters like server and client IPs, etc. verdict, err := policy.Eval( ctx, sdkAct.Input{ Name: signal.Name, Policy: policy.Metadata, Signal: signal.Metadata, - Sync: action.Sync, + // Action dictates the sync mode, not the signal. + Sync: action.Sync, }, ) if err != nil { @@ -194,10 +202,16 @@ func (r *Registry) apply(signal sdkAct.Signal) (*sdkAct.Output, *gerr.GatewayDEr }, nil } -// Run runs the output and returns the result. +// Run runs the function associated with the output.MatchedPolicy and +// returns its result. If the action is synchronous, the result is returned +// immediately. If the action is asynchronous, the result is nil and the +// error is ErrAsyncAction, which is a sentinel error to indicate that the +// action is running asynchronously. func (r *Registry) Run( output *sdkAct.Output, params ...sdkAct.Parameter, ) (any, *gerr.GatewayDError) { + // In certain cases, the output may be nil, for example, if the policy + // evaluation fails. In this case, the run is aborted. if output == nil { // This should never happen, since the output is always set by the registry // to be the default policy if no signals are provided. @@ -215,11 +229,13 @@ func (r *Registry) Run( // Prepend the logger to the parameters. params = append([]sdkAct.Parameter{WithLogger(r.logger)}, params...) + // If the action is synchronous, run it and return the result immediately. if action.Sync { r.logger.Debug().Fields(map[string]interface{}{ "execution_mode": "sync", "action": action.Name, }).Msgf("Running action") + output, err := action.Run(output.Metadata, params...) if err != nil { r.logger.Error().Err(err).Str("action", action.Name).Msg("Error running action") From c4109b55ad6ae910ee4a31fac46aea6108b6cfb3 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Fri, 1 Mar 2024 17:51:00 +0100 Subject: [PATCH 48/49] Fix linter issues --- act/builtins.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/act/builtins.go b/act/builtins.go index 24a90189..f9cf474d 100644 --- a/act/builtins.go +++ b/act/builtins.go @@ -89,8 +89,8 @@ func Terminate(_ map[string]any, params ...sdkAct.Parameter) (any, error) { return nil, gerr.ErrLoggerRequired } - logger, ok := params[0].Value.(zerolog.Logger) - if !ok { + logger, isValid := params[0].Value.(zerolog.Logger) + if !isValid { // The first parameter is not a logger. return nil, gerr.ErrLoggerRequired } @@ -101,8 +101,8 @@ func Terminate(_ map[string]any, params ...sdkAct.Parameter) (any, error) { return true, nil } - result, ok := params[1].Value.(map[string]any) - if !ok { + result, isValid := params[1].Value.(map[string]any) + if !isValid { logger.Debug().Msg("terminate action received a non-map result parameter") return true, nil } @@ -141,16 +141,16 @@ func Log(data map[string]any, params ...sdkAct.Parameter) (any, error) { fields := map[string]any{} if len(data) > LogDefaultKeyCount { - for k, v := range data { + for key, value := range data { // Skip these necessary fields, as they are already used by the logger. // level: The log level. // message: The log message. // log: The log signal. - if k == "level" || k == "message" || k == "log" { + if key == "level" || key == "message" || key == "log" { continue } // Add the rest of the fields to the logger as extra fields. - fields[k] = v + fields[key] = value } } From 930b3ecf9bde9a3836f4048f84f3efbfd557b72c Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Fri, 1 Mar 2024 17:57:48 +0100 Subject: [PATCH 49/49] Rename policiesRegistry to actRegistry --- plugin/plugin_registry.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/plugin/plugin_registry.go b/plugin/plugin_registry.go index 7272f010..da1247eb 100644 --- a/plugin/plugin_registry.go +++ b/plugin/plugin_registry.go @@ -57,11 +57,11 @@ type IRegistry interface { } type Registry struct { - plugins pool.IPool - policiesRegistry *act.Registry - hooks map[v1.HookName]map[sdkPlugin.Priority]sdkPlugin.Method - ctx context.Context //nolint:containedctx - devMode bool + plugins pool.IPool + actRegistry *act.Registry + hooks map[v1.HookName]map[sdkPlugin.Priority]sdkPlugin.Method + ctx context.Context //nolint:containedctx + devMode bool Logger zerolog.Logger Compatibility config.CompatibilityPolicy @@ -73,7 +73,7 @@ var _ IRegistry = (*Registry)(nil) // NewRegistry creates a new plugin registry. func NewRegistry( ctx context.Context, - policiesRegistry *act.Registry, + actRegistry *act.Registry, compatibility config.CompatibilityPolicy, logger zerolog.Logger, devMode bool, @@ -82,13 +82,13 @@ func NewRegistry( defer span.End() return &Registry{ - plugins: pool.NewPool(regCtx, config.EmptyPoolCapacity), - policiesRegistry: policiesRegistry, - hooks: map[v1.HookName]map[sdkPlugin.Priority]sdkPlugin.Method{}, - ctx: regCtx, - devMode: devMode, - Logger: logger, - Compatibility: compatibility, + plugins: pool.NewPool(regCtx, config.EmptyPoolCapacity), + actRegistry: actRegistry, + hooks: map[v1.HookName]map[sdkPlugin.Priority]sdkPlugin.Method{}, + ctx: regCtx, + devMode: devMode, + Logger: logger, + Compatibility: compatibility, } } @@ -733,5 +733,5 @@ func (reg *Registry) RegisterHooks(ctx context.Context, pluginID sdkPlugin.Ident func (reg *Registry) ActRegistry() *act.Registry { _, span := otel.Tracer(config.TracerName).Start(reg.ctx, "ActRegistry") defer span.End() - return reg.policiesRegistry + return reg.actRegistry }