Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Act system #451

Merged
merged 50 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
ba68601
Update dependencies
mostafa Feb 24, 2024
527f7cf
Add Act registry
mostafa Feb 24, 2024
bbd97de
Fix issue after updating dependency (prometheus_client for Go)
mostafa Feb 24, 2024
dc7816f
Implement Act system in the plugin registry
mostafa Feb 24, 2024
fcbf380
Add config options for policies
mostafa Feb 24, 2024
6617bf1
Refactor proxy to use the new Act system
mostafa Feb 24, 2024
28a369a
Initialize Act system on run
mostafa Feb 24, 2024
dae7d6c
Allow expr
mostafa Feb 24, 2024
10c6aea
Update tests to reflect changes implemented as part of the Act system
mostafa Feb 24, 2024
e3c3b53
Update actions
mostafa Feb 24, 2024
42766a7
Move Signal helper functions to SDK
mostafa Feb 25, 2024
e2143cf
Update SDK
mostafa Feb 25, 2024
20322c0
Use optional params for action run function
mostafa Feb 25, 2024
ccb361b
Upgrade to Go v1.22
mostafa Feb 25, 2024
cf9bfa0
Pin golangci-lint version and use go install
mostafa Feb 25, 2024
d0f834b
Update workflows and Docker image to use Go v0.22
mostafa Feb 25, 2024
12609d2
Use pointer to struct to access fields
mostafa Feb 25, 2024
dced52e
Marshal/unmarshal to JSON to deal with time.Duration field
mostafa Feb 25, 2024
e564ace
Use the latest main branch to fix issues before release
mostafa Feb 25, 2024
217a735
Fix linter errors and improve code
mostafa Feb 25, 2024
c973282
Error sentinel is safe to be bypassed
mostafa Feb 26, 2024
6dc84d7
Run default signal, action and policy
mostafa Feb 26, 2024
122e12a
Actions now receive the result map from the traffic hooks (onTrafficF…
mostafa Feb 26, 2024
d6fa8fd
Lower log level and add clarifying comment
mostafa Feb 27, 2024
6ee9b82
Terminate connection with an error response if none is provided by th…
mostafa Feb 27, 2024
7537d38
Update signature of act.NewRegistry to remove global variables
mostafa Feb 27, 2024
a36b4fc
Fix linter issues
mostafa Feb 27, 2024
a328900
Ignore contradictory signals
mostafa Feb 27, 2024
e08fbe0
Use the latest (tagged) version of prometheus client for Go
mostafa Feb 28, 2024
e51c89d
Remove unused code
mostafa Feb 28, 2024
6d02b36
Add tests for Act utils functions
mostafa Feb 28, 2024
33ea274
Add tests for policy registry
mostafa Feb 28, 2024
9e6ccf6
Add cast to allow list of tests
mostafa Feb 28, 2024
670bda4
Remove comparison of pointers
mostafa Feb 28, 2024
f70efac
Add test for act/registry.go
mostafa Feb 28, 2024
0629368
Rename variable for clarification
mostafa Feb 29, 2024
fbf1ca8
Add policies and policyTimeout config params to sample config file
mostafa Feb 29, 2024
00db220
Remove termination policy (#458)
mostafa Feb 29, 2024
2b45ee7
Fix bug in handling contradictory signals
mostafa Feb 29, 2024
4a39c8e
Fix stack overflow when policy evaluation error occurs
mostafa Feb 29, 2024
bd2d65b
Add more tests for policy registry
mostafa Feb 29, 2024
86e5104
Add coverage report to test target
mostafa Feb 29, 2024
4e2698f
Rename policy registry to act registry
mostafa Feb 29, 2024
bbda501
Add comments and slightly refactor action functions
mostafa Mar 1, 2024
a5126a0
Refactor and rename variables and add comments
mostafa Mar 1, 2024
a2a13e7
Add more tests for nils
mostafa Mar 1, 2024
710a2da
Add comments
mostafa Mar 1, 2024
c4109b5
Fix linter issues
mostafa Mar 1, 2024
930b3ec
Rename policiesRegistry to actRegistry
mostafa Mar 1, 2024
f65832d
Merge branch 'main' into act-system
mostafa Mar 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go 1.21
uses: actions/setup-go@v3
- 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
Expand Down
19 changes: 10 additions & 9 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,21 @@ 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"
go-version: "1.22"

- name: Lint code issues 🚨
uses: golangci/golangci-lint-action@v3
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 ./...
Expand Down Expand Up @@ -89,17 +91,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"
go-version: "1.22"

- name: Checkout test plugin 🛎️
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: gatewayd-io/plugin-template-go
path: plugin-template-go
Expand All @@ -113,7 +115,6 @@ jobs:
export SHA256SUM=$(sha256sum ptg | awk '{print $1}')
cat <<EOF > gatewayd_plugins.yaml
compatibilityPolicy: "strict"
terminationPolicy: "stop"
metricsMergerPeriod: 1s
healthCheckPeriod: 1s
reloadOnCrash: true
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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/
Expand Down
3 changes: 3 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ linters-settings:
- "gopkg.in/yaml.v3"
- "github.com/zenizh/go-capturer"
- "gopkg.in/natefinch/lumberjack.v2"
- "github.com/expr-lang/expr"
- "github.com/jackc/pgx/v5/pgproto3"
test:
files:
- $test
Expand All @@ -84,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
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 ./...
Expand Down
162 changes: 162 additions & 0 deletions act/builtins.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
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 (
// 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(),
"terminate": sdkAct.Terminate(),
"log": {Name: "log"},
}
}

// 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),
"terminate": sdkAct.MustNewPolicy(
"terminate",
`Signal.terminate == true && Policy.terminate == "stop"`,
map[string]any{"terminate": "stop"},
),
"log": sdkAct.MustNewPolicy(
"log",
`Signal.log == true && Policy.log == "enabled"`,
map[string]any{"log": "enabled"},
),
}
}

// BuiltinActions returns a map of built-in actions.
func BuiltinActions() map[string]*sdkAct.Action {
return map[string]*sdkAct.Action{
"passthrough": {
Name: "passthrough",
Metadata: nil,
Sync: true,
Terminal: false,
Run: Passthrough,
},
"terminate": {
Name: "terminate",
Metadata: nil,
Sync: true,
Terminal: true,
Run: Terminate,
},
"log": {
Name: "log",
Metadata: nil,
Sync: false,
Terminal: false,
Run: Log,
},
}
}

// 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 != LoggerKey {
// No logger parameter or the first parameter is not a logger.
return nil, gerr.ErrLoggerRequired
}

logger, isValid := params[0].Value.(zerolog.Logger)
if !isValid {
// The first parameter is not a logger.
return nil, gerr.ErrLoggerRequired
}

if len(params) < TerminateDefaultParamCount || params[1].Key != ResultKey {
logger.Debug().Msg(
"terminate action can optionally receive a result parameter")
return true, nil
}

result, isValid := params[1].Value.(map[string]any)
if !isValid {
logger.Debug().Msg("terminate action received a non-map 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
}

// 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{}
if len(data) > LogDefaultKeyCount {
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 key == "level" || key == "message" || key == "log" {
continue
}
// Add the rest of the fields to the logger as extra fields.
fields[key] = value
}
}

logger.WithLevel(
logging.GetZeroLogLevel(cast.ToString(data["level"])),
).Fields(fields).Msg(cast.ToString(data["message"]))

return true, nil
}
Loading