Merge branch 'master' into lapi-detailed-metrics
This commit is contained in:
commit
3169343526
42 changed files with 2322 additions and 1472 deletions
6
.github/governance.yml
vendored
6
.github/governance.yml
vendored
|
@ -42,7 +42,7 @@ issue:
|
||||||
3. Check [Releases](https://github.com/crowdsecurity/crowdsec/releases/latest) to make sure your agent is on the latest version.
|
3. Check [Releases](https://github.com/crowdsecurity/crowdsec/releases/latest) to make sure your agent is on the latest version.
|
||||||
|
|
||||||
- prefix: kind
|
- prefix: kind
|
||||||
list: ['feature', 'bug', 'packaging', 'enhancement']
|
list: ['feature', 'bug', 'packaging', 'enhancement', 'refactoring']
|
||||||
multiple: false
|
multiple: false
|
||||||
author_association:
|
author_association:
|
||||||
author: true
|
author: true
|
||||||
|
@ -54,6 +54,7 @@ issue:
|
||||||
@$AUTHOR: There are no 'kind' label on this issue. You need a 'kind' label to start the triage process.
|
@$AUTHOR: There are no 'kind' label on this issue. You need a 'kind' label to start the triage process.
|
||||||
* `/kind feature`
|
* `/kind feature`
|
||||||
* `/kind enhancement`
|
* `/kind enhancement`
|
||||||
|
* `/kind refactoring`
|
||||||
* `/kind bug`
|
* `/kind bug`
|
||||||
* `/kind packaging`
|
* `/kind packaging`
|
||||||
|
|
||||||
|
@ -65,12 +66,13 @@ pull_request:
|
||||||
labels:
|
labels:
|
||||||
- prefix: kind
|
- prefix: kind
|
||||||
multiple: false
|
multiple: false
|
||||||
list: [ 'feature', 'enhancement', 'fix', 'chore', 'dependencies']
|
list: [ 'feature', 'enhancement', 'fix', 'chore', 'dependencies', 'refactoring']
|
||||||
needs:
|
needs:
|
||||||
comment: |
|
comment: |
|
||||||
@$AUTHOR: There are no 'kind' label on this PR. You need a 'kind' label to generate the release automatically.
|
@$AUTHOR: There are no 'kind' label on this PR. You need a 'kind' label to generate the release automatically.
|
||||||
* `/kind feature`
|
* `/kind feature`
|
||||||
* `/kind enhancement`
|
* `/kind enhancement`
|
||||||
|
* `/kind refactoring`
|
||||||
* `/kind fix`
|
* `/kind fix`
|
||||||
* `/kind chore`
|
* `/kind chore`
|
||||||
* `/kind dependencies`
|
* `/kind dependencies`
|
||||||
|
|
2
.github/workflows/bats-hub.yml
vendored
2
.github/workflows/bats-hub.yml
vendored
|
@ -33,7 +33,7 @@ jobs:
|
||||||
- name: "Set up Go"
|
- name: "Set up Go"
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "1.21.8"
|
go-version: "1.21.9"
|
||||||
|
|
||||||
- name: "Install bats dependencies"
|
- name: "Install bats dependencies"
|
||||||
env:
|
env:
|
||||||
|
|
2
.github/workflows/bats-mysql.yml
vendored
2
.github/workflows/bats-mysql.yml
vendored
|
@ -36,7 +36,7 @@ jobs:
|
||||||
- name: "Set up Go"
|
- name: "Set up Go"
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "1.21.8"
|
go-version: "1.21.9"
|
||||||
|
|
||||||
- name: "Install bats dependencies"
|
- name: "Install bats dependencies"
|
||||||
env:
|
env:
|
||||||
|
|
2
.github/workflows/bats-postgres.yml
vendored
2
.github/workflows/bats-postgres.yml
vendored
|
@ -45,7 +45,7 @@ jobs:
|
||||||
- name: "Set up Go"
|
- name: "Set up Go"
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "1.21.8"
|
go-version: "1.21.9"
|
||||||
|
|
||||||
- name: "Install bats dependencies"
|
- name: "Install bats dependencies"
|
||||||
env:
|
env:
|
||||||
|
|
2
.github/workflows/bats-sqlite-coverage.yml
vendored
2
.github/workflows/bats-sqlite-coverage.yml
vendored
|
@ -28,7 +28,7 @@ jobs:
|
||||||
- name: "Set up Go"
|
- name: "Set up Go"
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "1.21.8"
|
go-version: "1.21.9"
|
||||||
|
|
||||||
- name: "Install bats dependencies"
|
- name: "Install bats dependencies"
|
||||||
env:
|
env:
|
||||||
|
|
2
.github/workflows/ci-windows-build-msi.yml
vendored
2
.github/workflows/ci-windows-build-msi.yml
vendored
|
@ -35,7 +35,7 @@ jobs:
|
||||||
- name: "Set up Go"
|
- name: "Set up Go"
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "1.21.8"
|
go-version: "1.21.9"
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: make windows_installer BUILD_RE2_WASM=1
|
run: make windows_installer BUILD_RE2_WASM=1
|
||||||
|
|
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
|
@ -52,7 +52,7 @@ jobs:
|
||||||
- name: "Set up Go"
|
- name: "Set up Go"
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "1.21.8"
|
go-version: "1.21.9"
|
||||||
cache-dependency-path: "**/go.sum"
|
cache-dependency-path: "**/go.sum"
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
|
14
.github/workflows/docker-tests.yml
vendored
14
.github/workflows/docker-tests.yml
vendored
|
@ -59,15 +59,15 @@ jobs:
|
||||||
cd docker/test
|
cd docker/test
|
||||||
python -m pip install --upgrade pipenv wheel
|
python -m pip install --upgrade pipenv wheel
|
||||||
|
|
||||||
- name: "Cache virtualenvs"
|
#- name: "Cache virtualenvs"
|
||||||
id: cache-pipenv
|
# id: cache-pipenv
|
||||||
uses: actions/cache@v4
|
# uses: actions/cache@v4
|
||||||
with:
|
# with:
|
||||||
path: ~/.local/share/virtualenvs
|
# path: ~/.local/share/virtualenvs
|
||||||
key: ${{ runner.os }}-pipenv-${{ hashFiles('**/Pipfile.lock') }}
|
# key: ${{ runner.os }}-pipenv-${{ hashFiles('**/Pipfile.lock') }}
|
||||||
|
|
||||||
- name: "Install dependencies"
|
- name: "Install dependencies"
|
||||||
if: steps.cache-pipenv.outputs.cache-hit != 'true'
|
#if: steps.cache-pipenv.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
cd docker/test
|
cd docker/test
|
||||||
pipenv install --deploy
|
pipenv install --deploy
|
||||||
|
|
4
.github/workflows/go-tests-windows.yml
vendored
4
.github/workflows/go-tests-windows.yml
vendored
|
@ -34,7 +34,7 @@ jobs:
|
||||||
- name: "Set up Go"
|
- name: "Set up Go"
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "1.21.8"
|
go-version: "1.21.9"
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
|
@ -56,7 +56,7 @@ jobs:
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v4
|
uses: golangci/golangci-lint-action@v4
|
||||||
with:
|
with:
|
||||||
version: v1.56
|
version: v1.57
|
||||||
args: --issues-exit-code=1 --timeout 10m
|
args: --issues-exit-code=1 --timeout 10m
|
||||||
only-new-issues: false
|
only-new-issues: false
|
||||||
# the cache is already managed above, enabling it here
|
# the cache is already managed above, enabling it here
|
||||||
|
|
4
.github/workflows/go-tests.yml
vendored
4
.github/workflows/go-tests.yml
vendored
|
@ -126,7 +126,7 @@ jobs:
|
||||||
- name: "Set up Go"
|
- name: "Set up Go"
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "1.21.8"
|
go-version: "1.21.9"
|
||||||
|
|
||||||
- name: Create localstack streams
|
- name: Create localstack streams
|
||||||
run: |
|
run: |
|
||||||
|
@ -157,7 +157,7 @@ jobs:
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v4
|
uses: golangci/golangci-lint-action@v4
|
||||||
with:
|
with:
|
||||||
version: v1.56
|
version: v1.57
|
||||||
args: --issues-exit-code=1 --timeout 10m
|
args: --issues-exit-code=1 --timeout 10m
|
||||||
only-new-issues: false
|
only-new-issues: false
|
||||||
# the cache is already managed above, enabling it here
|
# the cache is already managed above, enabling it here
|
||||||
|
|
|
@ -25,7 +25,7 @@ jobs:
|
||||||
- name: "Set up Go"
|
- name: "Set up Go"
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "1.21.8"
|
go-version: "1.21.9"
|
||||||
|
|
||||||
- name: Build the binaries
|
- name: Build the binaries
|
||||||
run: |
|
run: |
|
||||||
|
|
101
.golangci.yml
101
.golangci.yml
|
@ -1,12 +1,5 @@
|
||||||
# https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml
|
# https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml
|
||||||
|
|
||||||
run:
|
|
||||||
skip-dirs:
|
|
||||||
- pkg/time/rate
|
|
||||||
skip-files:
|
|
||||||
- pkg/yamlpatch/merge.go
|
|
||||||
- pkg/yamlpatch/merge_test.go
|
|
||||||
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
cyclop:
|
cyclop:
|
||||||
# lower this after refactoring
|
# lower this after refactoring
|
||||||
|
@ -19,6 +12,10 @@ linters-settings:
|
||||||
- prefix(github.com/crowdsecurity)
|
- prefix(github.com/crowdsecurity)
|
||||||
- prefix(github.com/crowdsecurity/crowdsec)
|
- prefix(github.com/crowdsecurity/crowdsec)
|
||||||
|
|
||||||
|
gomoddirectives:
|
||||||
|
replace-allow-list:
|
||||||
|
- golang.org/x/time/rate
|
||||||
|
|
||||||
gocognit:
|
gocognit:
|
||||||
# lower this after refactoring
|
# lower this after refactoring
|
||||||
min-complexity: 145
|
min-complexity: 145
|
||||||
|
@ -40,7 +37,6 @@ linters-settings:
|
||||||
statements: 122
|
statements: 122
|
||||||
|
|
||||||
govet:
|
govet:
|
||||||
check-shadowing: true
|
|
||||||
enable:
|
enable:
|
||||||
- atomicalign
|
- atomicalign
|
||||||
- deepequalerrors
|
- deepequalerrors
|
||||||
|
@ -151,37 +147,40 @@ linters:
|
||||||
#
|
#
|
||||||
# DEPRECATED by golangi-lint
|
# DEPRECATED by golangi-lint
|
||||||
#
|
#
|
||||||
- deadcode # The owner seems to have abandoned the linter. Replaced by unused.
|
- deadcode
|
||||||
- exhaustivestruct # The owner seems to have abandoned the linter. Replaced by exhaustruct.
|
- exhaustivestruct
|
||||||
- golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
|
- golint
|
||||||
- ifshort # Checks that your code uses short syntax for if-statements whenever possible
|
- ifshort
|
||||||
- interfacer # Linter that suggests narrower interface types
|
- interfacer
|
||||||
- maligned # Tool to detect Go structs that would take less memory if their fields were sorted
|
- maligned
|
||||||
- nosnakecase # nosnakecase is a linter that detects snake case of variable naming and function name.
|
- nosnakecase
|
||||||
- scopelint # Scopelint checks for unpinned variables in go programs
|
- scopelint
|
||||||
- structcheck # The owner seems to have abandoned the linter. Replaced by unused.
|
- structcheck
|
||||||
- varcheck # The owner seems to have abandoned the linter. Replaced by unused.
|
- varcheck
|
||||||
|
|
||||||
#
|
#
|
||||||
# Enabled
|
# Enabled
|
||||||
#
|
#
|
||||||
|
|
||||||
# - asasalint # check for pass []any as any in variadic func(...any)
|
# - asasalint # check for pass []any as any in variadic func(...any)
|
||||||
# - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers
|
# - asciicheck # checks that all code identifiers does not have non-ASCII symbols in the name
|
||||||
# - bidichk # Checks for dangerous unicode character sequences
|
# - bidichk # Checks for dangerous unicode character sequences
|
||||||
# - bodyclose # checks whether HTTP response body is closed successfully
|
# - bodyclose # checks whether HTTP response body is closed successfully
|
||||||
|
# - copyloopvar # copyloopvar is a linter detects places where loop variables are copied
|
||||||
# - cyclop # checks function and package cyclomatic complexity
|
# - cyclop # checks function and package cyclomatic complexity
|
||||||
# - decorder # check declaration order and count of types, constants, variables and functions
|
# - decorder # check declaration order and count of types, constants, variables and functions
|
||||||
# - depguard # Go linter that checks if package imports are in a list of acceptable packages
|
# - depguard # Go linter that checks if package imports are in a list of acceptable packages
|
||||||
# - dupword # checks for duplicate words in the source code
|
# - dupword # checks for duplicate words in the source code
|
||||||
# - durationcheck # check for two durations multiplied together
|
# - durationcheck # check for two durations multiplied together
|
||||||
# - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
|
# - errcheck # errcheck is a program for checking for unchecked errors in Go code. These unchecked errors can be critical bugs in some cases
|
||||||
# - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13.
|
# - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13.
|
||||||
# - execinquery # execinquery is a linter about query string checker in Query function which reads your Go src files and warning it finds
|
# - execinquery # execinquery is a linter about query string checker in Query function which reads your Go src files and warning it finds
|
||||||
# - exportloopref # checks for pointers to enclosing loop variables
|
# - exportloopref # checks for pointers to enclosing loop variables
|
||||||
# - funlen # Tool for detection of long functions
|
# - funlen # Tool for detection of long functions
|
||||||
# - ginkgolinter # enforces standards of using ginkgo and gomega
|
# - ginkgolinter # enforces standards of using ginkgo and gomega
|
||||||
|
# - gocheckcompilerdirectives # Checks that go compiler directive comments (//go:) are valid.
|
||||||
# - gochecknoinits # Checks that no init functions are present in Go code
|
# - gochecknoinits # Checks that no init functions are present in Go code
|
||||||
|
# - gochecksumtype # Run exhaustiveness checks on Go "sum types"
|
||||||
# - gocognit # Computes and checks the cognitive complexity of functions
|
# - gocognit # Computes and checks the cognitive complexity of functions
|
||||||
# - gocritic # Provides diagnostics that check for bugs, performance and style issues.
|
# - gocritic # Provides diagnostics that check for bugs, performance and style issues.
|
||||||
# - gocyclo # Computes and checks the cyclomatic complexity of functions
|
# - gocyclo # Computes and checks the cyclomatic complexity of functions
|
||||||
|
@ -189,48 +188,56 @@ linters:
|
||||||
# - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod.
|
# - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod.
|
||||||
# - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations.
|
# - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations.
|
||||||
# - goprintffuncname # Checks that printf-like functions are named with `f` at the end
|
# - goprintffuncname # Checks that printf-like functions are named with `f` at the end
|
||||||
# - gosimple # (megacheck): Linter for Go source code that specializes in simplifying a code
|
# - gosimple # (megacheck): Linter for Go source code that specializes in simplifying code
|
||||||
# - govet # (vet, vetshadow): Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
|
# - gosmopolitan # Report certain i18n/l10n anti-patterns in your Go codebase
|
||||||
# - grouper # An analyzer to analyze expression groups.
|
# - govet # (vet, vetshadow): Vet examines Go source code and reports suspicious constructs. It is roughly the same as 'go vet' and uses its passes.
|
||||||
|
# - grouper # Analyze expression groups.
|
||||||
# - importas # Enforces consistent import aliases
|
# - importas # Enforces consistent import aliases
|
||||||
# - ineffassign # Detects when assignments to existing variables are not used
|
# - ineffassign # Detects when assignments to existing variables are not used
|
||||||
# - interfacebloat # A linter that checks the number of methods inside an interface.
|
# - interfacebloat # A linter that checks the number of methods inside an interface.
|
||||||
|
# - intrange # intrange is a linter to find places where for loops could make use of an integer range.
|
||||||
# - lll # Reports long lines
|
# - lll # Reports long lines
|
||||||
|
# - loggercheck # (logrlint): Checks key value pairs for common logger libraries (kitlog,klog,logr,zap).
|
||||||
# - logrlint # Check logr arguments.
|
# - logrlint # Check logr arguments.
|
||||||
# - maintidx # maintidx measures the maintainability index of each function.
|
# - maintidx # maintidx measures the maintainability index of each function.
|
||||||
# - makezero # Finds slice declarations with non-zero initial length
|
# - makezero # Finds slice declarations with non-zero initial length
|
||||||
# - misspell # Finds commonly misspelled English words in comments
|
# - mirror # reports wrong mirror patterns of bytes/strings usage
|
||||||
# - nakedret # Finds naked returns in functions greater than a specified function length
|
# - misspell # Finds commonly misspelled English words
|
||||||
|
# - nakedret # Checks that functions with naked returns are not longer than a maximum size (can be zero).
|
||||||
# - nestif # Reports deeply nested if statements
|
# - nestif # Reports deeply nested if statements
|
||||||
# - nilerr # Finds the code that returns nil even if it checks that the error is not nil.
|
# - nilerr # Finds the code that returns nil even if it checks that the error is not nil.
|
||||||
# - nolintlint # Reports ill-formed or insufficient nolint directives
|
# - nolintlint # Reports ill-formed or insufficient nolint directives
|
||||||
# - nonamedreturns # Reports all named returns
|
# - nonamedreturns # Reports all named returns
|
||||||
# - nosprintfhostport # Checks for misuse of Sprintf to construct a host with port in a URL.
|
# - nosprintfhostport # Checks for misuse of Sprintf to construct a host with port in a URL.
|
||||||
|
# - perfsprint # Checks that fmt.Sprintf can be replaced with a faster alternative.
|
||||||
# - predeclared # find code that shadows one of Go's predeclared identifiers
|
# - predeclared # find code that shadows one of Go's predeclared identifiers
|
||||||
# - reassign # Checks that package variables are not reassigned
|
# - reassign # Checks that package variables are not reassigned
|
||||||
# - rowserrcheck # checks whether Err of rows is checked successfully
|
# - rowserrcheck # checks whether Rows.Err of rows is checked successfully
|
||||||
# - sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed.
|
# - sloglint # ensure consistent code style when using log/slog
|
||||||
# - staticcheck # (megacheck): Staticcheck is a go vet on steroids, applying a ton of static analysis checks
|
# - spancheck # Checks for mistakes with OpenTelemetry/Census spans.
|
||||||
# - testableexamples # linter checks if examples are testable (have an expected output)
|
# - sqlclosecheck # Checks that sql.Rows, sql.Stmt, sqlx.NamedStmt, pgx.Query are closed.
|
||||||
|
# - staticcheck # (megacheck): It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary. The author of staticcheck doesn't support or approve the use of staticcheck as a library inside golangci-lint.
|
||||||
# - tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17
|
# - tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17
|
||||||
|
# - testableexamples # linter checks if examples are testable (have an expected output)
|
||||||
|
# - testifylint # Checks usage of github.com/stretchr/testify.
|
||||||
# - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes
|
# - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes
|
||||||
# - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code
|
|
||||||
# - unconvert # Remove unnecessary type conversions
|
# - unconvert # Remove unnecessary type conversions
|
||||||
# - unused # (megacheck): Checks Go code for unused constants, variables, functions and types
|
# - unused # (megacheck): Checks Go code for unused constants, variables, functions and types
|
||||||
# - usestdlibvars # A linter that detect the possibility to use variables/constants from the Go standard library.
|
# - usestdlibvars # A linter that detect the possibility to use variables/constants from the Go standard library.
|
||||||
# - wastedassign # wastedassign finds wasted assignment statements.
|
# - wastedassign # Finds wasted assignment statements
|
||||||
|
# - zerologlint # Detects the wrong usage of `zerolog` that a user forgets to dispatch with `Send` or `Msg`
|
||||||
|
|
||||||
#
|
#
|
||||||
# Recommended? (easy)
|
# Recommended? (easy)
|
||||||
#
|
#
|
||||||
|
|
||||||
- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
|
- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
|
||||||
- errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occations, where the check for the returned error can be omitted.
|
- errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and reports occations, where the check for the returned error can be omitted.
|
||||||
- exhaustive # check exhaustiveness of enum switch statements
|
- exhaustive # check exhaustiveness of enum switch statements
|
||||||
- gci # Gci control golang package import order and make it always deterministic.
|
- gci # Gci control golang package import order and make it always deterministic.
|
||||||
- godot # Check if comments end in a period
|
- godot # Check if comments end in a period
|
||||||
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
|
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
|
||||||
- goimports # In addition to fixing imports, goimports also formats your code in the same style as gofmt.
|
- goimports # Check import statements are formatted according to the 'goimport' command. Reformat imports in autofix mode.
|
||||||
- gosec # (gas): Inspects source code for security problems
|
- gosec # (gas): Inspects source code for security problems
|
||||||
- inamedparam # reports interfaces with unnamed method parameters
|
- inamedparam # reports interfaces with unnamed method parameters
|
||||||
- musttag # enforce field tags in (un)marshaled structs
|
- musttag # enforce field tags in (un)marshaled structs
|
||||||
|
@ -238,7 +245,7 @@ linters:
|
||||||
- protogetter # Reports direct reads from proto message fields when getters should be used
|
- protogetter # Reports direct reads from proto message fields when getters should be used
|
||||||
- revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint.
|
- revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint.
|
||||||
- tagalign # check that struct tags are well aligned
|
- tagalign # check that struct tags are well aligned
|
||||||
- thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers
|
- thelper # thelper detects tests helpers which is not start with t.Helper() method.
|
||||||
- wrapcheck # Checks that errors returned from external packages are wrapped
|
- wrapcheck # Checks that errors returned from external packages are wrapped
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -246,12 +253,12 @@ linters:
|
||||||
#
|
#
|
||||||
|
|
||||||
- containedctx # containedctx is a linter that detects struct contained context.Context field
|
- containedctx # containedctx is a linter that detects struct contained context.Context field
|
||||||
- contextcheck # check the function whether use a non-inherited context
|
- contextcheck # check whether the function uses a non-inherited context
|
||||||
- errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`.
|
- errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`.
|
||||||
- gomnd # An analyzer to detect magic numbers.
|
- gomnd # An analyzer to detect magic numbers.
|
||||||
- ireturn # Accept Interfaces, Return Concrete Types
|
- ireturn # Accept Interfaces, Return Concrete Types
|
||||||
- nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value.
|
- nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value.
|
||||||
- noctx # noctx finds sending http request without context.Context
|
- noctx # Finds sending http request without context.Context
|
||||||
- unparam # Reports unused function parameters
|
- unparam # Reports unused function parameters
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -260,8 +267,8 @@ linters:
|
||||||
|
|
||||||
- gofumpt # Gofumpt checks whether code was gofumpt-ed.
|
- gofumpt # Gofumpt checks whether code was gofumpt-ed.
|
||||||
- nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity
|
- nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity
|
||||||
- whitespace # Tool for detection of leading and trailing whitespace
|
- whitespace # Whitespace is a linter that checks for unnecessary newlines at the start and end of functions, if, for, etc.
|
||||||
- wsl # Whitespace Linter - Forces you to use empty lines!
|
- wsl # add or remove empty lines
|
||||||
|
|
||||||
#
|
#
|
||||||
# Well intended, but not ready for this
|
# Well intended, but not ready for this
|
||||||
|
@ -269,8 +276,8 @@ linters:
|
||||||
- dupl # Tool for code clone detection
|
- dupl # Tool for code clone detection
|
||||||
- forcetypeassert # finds forced type assertions
|
- forcetypeassert # finds forced type assertions
|
||||||
- godox # Tool for detection of FIXME, TODO and other comment keywords
|
- godox # Tool for detection of FIXME, TODO and other comment keywords
|
||||||
- goerr113 # Golang linter to check the errors handling expressions
|
- goerr113 # Go linter to check the errors handling expressions
|
||||||
- paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test
|
- paralleltest # Detects missing usage of t.Parallel() method in your Go test
|
||||||
- testpackage # linter that makes you use a separate _test package
|
- testpackage # linter that makes you use a separate _test package
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -278,7 +285,7 @@ linters:
|
||||||
#
|
#
|
||||||
- exhaustruct # Checks if all structure fields are initialized
|
- exhaustruct # Checks if all structure fields are initialized
|
||||||
- forbidigo # Forbids identifiers
|
- forbidigo # Forbids identifiers
|
||||||
- gochecknoglobals # check that no global variables exist
|
- gochecknoglobals # Check that no global variables exist.
|
||||||
- goconst # Finds repeated strings that could be replaced by a constant
|
- goconst # Finds repeated strings that could be replaced by a constant
|
||||||
- stylecheck # Stylecheck is a replacement for golint
|
- stylecheck # Stylecheck is a replacement for golint
|
||||||
- tagliatelle # Checks the struct tags.
|
- tagliatelle # Checks the struct tags.
|
||||||
|
@ -295,15 +302,21 @@ issues:
|
||||||
# “Look, that’s why there’s rules, understand? So that you think before you
|
# “Look, that’s why there’s rules, understand? So that you think before you
|
||||||
# break ‘em.” ― Terry Pratchett
|
# break ‘em.” ― Terry Pratchett
|
||||||
|
|
||||||
|
exclude-dirs:
|
||||||
|
- pkg/time/rate
|
||||||
|
|
||||||
|
exclude-files:
|
||||||
|
- pkg/yamlpatch/merge.go
|
||||||
|
- pkg/yamlpatch/merge_test.go
|
||||||
|
|
||||||
|
exclude-generated-strict: true
|
||||||
|
|
||||||
max-issues-per-linter: 0
|
max-issues-per-linter: 0
|
||||||
max-same-issues: 0
|
max-same-issues: 0
|
||||||
exclude-rules:
|
exclude-rules:
|
||||||
|
|
||||||
# Won't fix:
|
# Won't fix:
|
||||||
|
|
||||||
- path: go.mod
|
|
||||||
text: "replacement are not allowed: golang.org/x/time/rate"
|
|
||||||
|
|
||||||
# `err` is often shadowed, we may continue to do it
|
# `err` is often shadowed, we may continue to do it
|
||||||
- linters:
|
- linters:
|
||||||
- govet
|
- govet
|
||||||
|
|
15
Dockerfile
15
Dockerfile
|
@ -1,5 +1,5 @@
|
||||||
# vim: set ft=dockerfile:
|
# vim: set ft=dockerfile:
|
||||||
FROM golang:1.21.8-alpine3.18 AS build
|
FROM golang:1.21.9-alpine3.18 AS build
|
||||||
|
|
||||||
ARG BUILD_VERSION
|
ARG BUILD_VERSION
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ RUN apk add --no-cache git g++ gcc libc-dev make bash gettext binutils-gold core
|
||||||
cd re2-${RE2_VERSION} && \
|
cd re2-${RE2_VERSION} && \
|
||||||
make install && \
|
make install && \
|
||||||
echo "githubciXXXXXXXXXXXXXXXXXXXXXXXX" > /etc/machine-id && \
|
echo "githubciXXXXXXXXXXXXXXXXXXXXXXXX" > /etc/machine-id && \
|
||||||
go install github.com/mikefarah/yq/v4@v4.40.4
|
go install github.com/mikefarah/yq/v4@v4.43.1
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
@ -43,11 +43,12 @@ COPY --from=build /go/bin/yq /usr/local/bin/crowdsec /usr/local/bin/cscli /usr/l
|
||||||
COPY --from=build /etc/crowdsec /staging/etc/crowdsec
|
COPY --from=build /etc/crowdsec /staging/etc/crowdsec
|
||||||
COPY --from=build /go/src/crowdsec/docker/docker_start.sh /
|
COPY --from=build /go/src/crowdsec/docker/docker_start.sh /
|
||||||
COPY --from=build /go/src/crowdsec/docker/config.yaml /staging/etc/crowdsec/config.yaml
|
COPY --from=build /go/src/crowdsec/docker/config.yaml /staging/etc/crowdsec/config.yaml
|
||||||
|
COPY --from=build /var/lib/crowdsec /staging/var/lib/crowdsec
|
||||||
RUN yq -n '.url="http://0.0.0.0:8080"' | install -m 0600 /dev/stdin /staging/etc/crowdsec/local_api_credentials.yaml
|
RUN yq -n '.url="http://0.0.0.0:8080"' | install -m 0600 /dev/stdin /staging/etc/crowdsec/local_api_credentials.yaml
|
||||||
|
|
||||||
ENTRYPOINT /bin/bash /docker_start.sh
|
ENTRYPOINT /bin/bash /docker_start.sh
|
||||||
|
|
||||||
FROM slim as plugins
|
FROM slim as full
|
||||||
|
|
||||||
# Due to the wizard using cp -n, we have to copy the config files directly from the source as -n does not exist in busybox cp
|
# Due to the wizard using cp -n, we have to copy the config files directly from the source as -n does not exist in busybox cp
|
||||||
# The files are here for reference, as users will need to mount a new version to be actually able to use notifications
|
# The files are here for reference, as users will need to mount a new version to be actually able to use notifications
|
||||||
|
@ -60,11 +61,3 @@ COPY --from=build \
|
||||||
/staging/etc/crowdsec/notifications/
|
/staging/etc/crowdsec/notifications/
|
||||||
|
|
||||||
COPY --from=build /usr/local/lib/crowdsec/plugins /usr/local/lib/crowdsec/plugins
|
COPY --from=build /usr/local/lib/crowdsec/plugins /usr/local/lib/crowdsec/plugins
|
||||||
|
|
||||||
FROM slim as geoip
|
|
||||||
|
|
||||||
COPY --from=build /var/lib/crowdsec /staging/var/lib/crowdsec
|
|
||||||
|
|
||||||
FROM plugins as full
|
|
||||||
|
|
||||||
COPY --from=build /var/lib/crowdsec /staging/var/lib/crowdsec
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# vim: set ft=dockerfile:
|
# vim: set ft=dockerfile:
|
||||||
FROM golang:1.21.8-bookworm AS build
|
FROM golang:1.21.9-bookworm AS build
|
||||||
|
|
||||||
ARG BUILD_VERSION
|
ARG BUILD_VERSION
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ RUN apt-get update && \
|
||||||
make && \
|
make && \
|
||||||
make install && \
|
make install && \
|
||||||
echo "githubciXXXXXXXXXXXXXXXXXXXXXXXX" > /etc/machine-id && \
|
echo "githubciXXXXXXXXXXXXXXXXXXXXXXXX" > /etc/machine-id && \
|
||||||
go install github.com/mikefarah/yq/v4@v4.40.4
|
go install github.com/mikefarah/yq/v4@v4.43.1
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
|
|
@ -15,19 +15,13 @@ pool:
|
||||||
stages:
|
stages:
|
||||||
- stage: Build
|
- stage: Build
|
||||||
jobs:
|
jobs:
|
||||||
- job:
|
- job: Build
|
||||||
displayName: "Build"
|
displayName: "Build"
|
||||||
steps:
|
steps:
|
||||||
- task: DotNetCoreCLI@2
|
|
||||||
displayName: "Install SignClient"
|
|
||||||
inputs:
|
|
||||||
command: 'custom'
|
|
||||||
custom: 'tool'
|
|
||||||
arguments: 'install --global SignClient --version 1.3.155'
|
|
||||||
- task: GoTool@0
|
- task: GoTool@0
|
||||||
displayName: "Install Go"
|
displayName: "Install Go"
|
||||||
inputs:
|
inputs:
|
||||||
version: '1.21.8'
|
version: '1.21.9'
|
||||||
|
|
||||||
- pwsh: |
|
- pwsh: |
|
||||||
choco install -y make
|
choco install -y make
|
||||||
|
@ -39,24 +33,14 @@ stages:
|
||||||
#we are not calling make windows_installer because we want to sign the binaries before they are added to the MSI
|
#we are not calling make windows_installer because we want to sign the binaries before they are added to the MSI
|
||||||
script: |
|
script: |
|
||||||
make build BUILD_RE2_WASM=1
|
make build BUILD_RE2_WASM=1
|
||||||
- task: AzureKeyVault@2
|
|
||||||
inputs:
|
|
||||||
azureSubscription: 'Azure subscription 1(8a93ab40-7e99-445e-ad47-0f6a3e2ef546)'
|
|
||||||
KeyVaultName: 'CodeSigningSecrets'
|
|
||||||
SecretsFilter: 'CodeSigningUser,CodeSigningPassword'
|
|
||||||
RunAsPreJob: false
|
|
||||||
|
|
||||||
- task: DownloadSecureFile@1
|
|
||||||
inputs:
|
|
||||||
secureFile: appsettings.json
|
|
||||||
|
|
||||||
- pwsh: |
|
|
||||||
SignClient.exe Sign --name "crowdsec-binaries" `
|
|
||||||
--input "**/*.exe" --config (Join-Path -Path $(Agent.TempDirectory) -ChildPath "appsettings.json") `
|
|
||||||
--user $(CodeSigningUser) --secret '$(CodeSigningPassword)'
|
|
||||||
displayName: "Sign Crowdsec binaries + plugins"
|
|
||||||
- pwsh: |
|
- pwsh: |
|
||||||
$build_version=$env:BUILD_SOURCEBRANCHNAME
|
$build_version=$env:BUILD_SOURCEBRANCHNAME
|
||||||
|
#Override the version if it's set in the pipeline
|
||||||
|
if ( ${env:USERBUILDVERSION} -ne "")
|
||||||
|
{
|
||||||
|
$build_version = ${env:USERBUILDVERSION}
|
||||||
|
}
|
||||||
if ($build_version.StartsWith("v"))
|
if ($build_version.StartsWith("v"))
|
||||||
{
|
{
|
||||||
$build_version = $build_version.Substring(1)
|
$build_version = $build_version.Substring(1)
|
||||||
|
@ -69,35 +53,112 @@ stages:
|
||||||
displayName: GetCrowdsecVersion
|
displayName: GetCrowdsecVersion
|
||||||
name: GetCrowdsecVersion
|
name: GetCrowdsecVersion
|
||||||
- pwsh: |
|
- pwsh: |
|
||||||
.\make_installer.ps1 -version '$(GetCrowdsecVersion.BuildVersion)'
|
Get-ChildItem -Path .\cmd -Directory | ForEach-Object {
|
||||||
|
$dirName = $_.Name
|
||||||
|
Get-ChildItem -Path .\cmd\$dirName -File -Filter '*.exe' | ForEach-Object {
|
||||||
|
$fileName = $_.Name
|
||||||
|
$destDir = Join-Path $(Build.ArtifactStagingDirectory) cmd\$dirName
|
||||||
|
New-Item -ItemType Directory -Path $destDir -Force
|
||||||
|
Copy-Item -Path .\cmd\$dirName\$fileName -Destination $destDir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
displayName: "Copy binaries to staging directory"
|
||||||
|
- task: PublishPipelineArtifact@1
|
||||||
|
inputs:
|
||||||
|
targetPath: '$(Build.ArtifactStagingDirectory)'
|
||||||
|
artifact: 'unsigned_binaries'
|
||||||
|
displayName: "Upload binaries artifact"
|
||||||
|
|
||||||
|
- stage: Sign
|
||||||
|
dependsOn: Build
|
||||||
|
variables:
|
||||||
|
- group: 'FOSS Build Variables'
|
||||||
|
- name: BuildVersion
|
||||||
|
value: $[ stageDependencies.Build.Build.outputs['GetCrowdsecVersion.BuildVersion'] ]
|
||||||
|
condition: succeeded()
|
||||||
|
jobs:
|
||||||
|
- job: Sign
|
||||||
|
displayName: "Sign"
|
||||||
|
steps:
|
||||||
|
- download: current
|
||||||
|
artifact: unsigned_binaries
|
||||||
|
displayName: "Download binaries artifact"
|
||||||
|
- task: CopyFiles@2
|
||||||
|
inputs:
|
||||||
|
SourceFolder: '$(Pipeline.Workspace)/unsigned_binaries'
|
||||||
|
TargetFolder: '$(Build.SourcesDirectory)'
|
||||||
|
displayName: "Copy binaries to workspace"
|
||||||
|
- task: DotNetCoreCLI@2
|
||||||
|
displayName: "Install SignTool tool"
|
||||||
|
inputs:
|
||||||
|
command: 'custom'
|
||||||
|
custom: 'tool'
|
||||||
|
arguments: install --global sign --version 0.9.0-beta.23127.3
|
||||||
|
- task: AzureKeyVault@2
|
||||||
|
displayName: "Get signing parameters"
|
||||||
|
inputs:
|
||||||
|
azureSubscription: "Azure subscription"
|
||||||
|
KeyVaultName: "$(KeyVaultName)"
|
||||||
|
SecretsFilter: "TenantId,ClientId,ClientSecret,Certificate,KeyVaultUrl"
|
||||||
|
- pwsh: |
|
||||||
|
sign code azure-key-vault `
|
||||||
|
"**/*.exe" `
|
||||||
|
--base-directory "$(Build.SourcesDirectory)/cmd/" `
|
||||||
|
--publisher-name "CrowdSec" `
|
||||||
|
--description "CrowdSec" `
|
||||||
|
--description-url "https://github.com/crowdsecurity/crowdsec" `
|
||||||
|
--azure-key-vault-tenant-id "$(TenantId)" `
|
||||||
|
--azure-key-vault-client-id "$(ClientId)" `
|
||||||
|
--azure-key-vault-client-secret "$(ClientSecret)" `
|
||||||
|
--azure-key-vault-certificate "$(Certificate)" `
|
||||||
|
--azure-key-vault-url "$(KeyVaultUrl)"
|
||||||
|
displayName: "Sign crowdsec binaries"
|
||||||
|
- pwsh: |
|
||||||
|
.\make_installer.ps1 -version '$(BuildVersion)'
|
||||||
displayName: "Build Crowdsec MSI"
|
displayName: "Build Crowdsec MSI"
|
||||||
name: BuildMSI
|
name: BuildMSI
|
||||||
|
|
||||||
- pwsh: |
|
- pwsh: |
|
||||||
.\make_chocolatey.ps1 -version '$(GetCrowdsecVersion.BuildVersion)'
|
.\make_chocolatey.ps1 -version '$(BuildVersion)'
|
||||||
displayName: "Build Chocolatey nupkg"
|
displayName: "Build Chocolatey nupkg"
|
||||||
|
|
||||||
- pwsh: |
|
- pwsh: |
|
||||||
SignClient.exe Sign --name "crowdsec-msi" `
|
sign code azure-key-vault `
|
||||||
--input "*.msi" --config (Join-Path -Path $(Agent.TempDirectory) -ChildPath "appsettings.json") `
|
"*.msi" `
|
||||||
--user $(CodeSigningUser) --secret '$(CodeSigningPassword)'
|
--base-directory "$(Build.SourcesDirectory)" `
|
||||||
displayName: "Sign Crowdsec MSI"
|
--publisher-name "CrowdSec" `
|
||||||
|
--description "CrowdSec" `
|
||||||
- task: PublishBuildArtifacts@1
|
--description-url "https://github.com/crowdsecurity/crowdsec" `
|
||||||
|
--azure-key-vault-tenant-id "$(TenantId)" `
|
||||||
|
--azure-key-vault-client-id "$(ClientId)" `
|
||||||
|
--azure-key-vault-client-secret "$(ClientSecret)" `
|
||||||
|
--azure-key-vault-certificate "$(Certificate)" `
|
||||||
|
--azure-key-vault-url "$(KeyVaultUrl)"
|
||||||
|
displayName: "Sign MSI package"
|
||||||
|
- pwsh: |
|
||||||
|
sign code azure-key-vault `
|
||||||
|
"*.nupkg" `
|
||||||
|
--base-directory "$(Build.SourcesDirectory)" `
|
||||||
|
--publisher-name "CrowdSec" `
|
||||||
|
--description "CrowdSec" `
|
||||||
|
--description-url "https://github.com/crowdsecurity/crowdsec" `
|
||||||
|
--azure-key-vault-tenant-id "$(TenantId)" `
|
||||||
|
--azure-key-vault-client-id "$(ClientId)" `
|
||||||
|
--azure-key-vault-client-secret "$(ClientSecret)" `
|
||||||
|
--azure-key-vault-certificate "$(Certificate)" `
|
||||||
|
--azure-key-vault-url "$(KeyVaultUrl)"
|
||||||
|
displayName: "Sign nuget package"
|
||||||
|
- task: PublishPipelineArtifact@1
|
||||||
inputs:
|
inputs:
|
||||||
PathtoPublish: '$(Build.Repository.LocalPath)\\crowdsec_$(GetCrowdsecVersion.BuildVersion).msi'
|
targetPath: '$(Build.SourcesDirectory)/crowdsec_$(BuildVersion).msi'
|
||||||
ArtifactName: 'crowdsec.msi'
|
artifact: 'signed_msi_package'
|
||||||
publishLocation: 'Container'
|
displayName: "Upload signed MSI artifact"
|
||||||
displayName: "Upload MSI artifact"
|
- task: PublishPipelineArtifact@1
|
||||||
|
|
||||||
- task: PublishBuildArtifacts@1
|
|
||||||
inputs:
|
inputs:
|
||||||
PathtoPublish: '$(Build.Repository.LocalPath)\\windows\\Chocolatey\\crowdsec\\crowdsec.$(GetCrowdsecVersion.BuildVersion).nupkg'
|
targetPath: '$(Build.SourcesDirectory)/crowdsec.$(BuildVersion).nupkg'
|
||||||
ArtifactName: 'crowdsec.nupkg'
|
artifact: 'signed_nuget_package'
|
||||||
publishLocation: 'Container'
|
displayName: "Upload signed nuget artifact"
|
||||||
displayName: "Upload nupkg artifact"
|
|
||||||
- stage: Publish
|
- stage: Publish
|
||||||
dependsOn: Build
|
dependsOn: Sign
|
||||||
jobs:
|
jobs:
|
||||||
- deployment: "Publish"
|
- deployment: "Publish"
|
||||||
displayName: "Publish to GitHub"
|
displayName: "Publish to GitHub"
|
||||||
|
@ -119,8 +180,7 @@ stages:
|
||||||
assetUploadMode: 'replace'
|
assetUploadMode: 'replace'
|
||||||
addChangeLog: false
|
addChangeLog: false
|
||||||
isPreRelease: true #we force prerelease because the pipeline is invoked on tag creation, which happens when we do a prerelease
|
isPreRelease: true #we force prerelease because the pipeline is invoked on tag creation, which happens when we do a prerelease
|
||||||
#the .. is an ugly hack, but I can't find the var that gives D:\a\1 ...
|
|
||||||
assets: |
|
assets: |
|
||||||
$(Build.ArtifactStagingDirectory)\..\crowdsec.msi/*.msi
|
$(Pipeline.Workspace)/signed_msi_package/*.msi
|
||||||
$(Build.ArtifactStagingDirectory)\..\crowdsec.nupkg/*.nupkg
|
$(Pipeline.Workspace)/signed_nuget_package/*.nupkg
|
||||||
condition: ne(variables['GetLatestPrelease.LatestPreRelease'], '')
|
condition: ne(variables['GetLatestPrelease.LatestPreRelease'], '')
|
||||||
|
|
|
@ -177,9 +177,9 @@ func (cli *cliAlerts) displayOneAlert(alert *models.Alert, withDetail bool) erro
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type cliAlerts struct{
|
type cliAlerts struct {
|
||||||
client *apiclient.ApiClient
|
client *apiclient.ApiClient
|
||||||
cfg configGetter
|
cfg configGetter
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCLIAlerts(getconfig configGetter) *cliAlerts {
|
func NewCLIAlerts(getconfig configGetter) *cliAlerts {
|
||||||
|
@ -253,8 +253,10 @@ func (cli *cliAlerts) NewListCmd() *cobra.Command {
|
||||||
Example: `cscli alerts list
|
Example: `cscli alerts list
|
||||||
cscli alerts list --ip 1.2.3.4
|
cscli alerts list --ip 1.2.3.4
|
||||||
cscli alerts list --range 1.2.3.0/24
|
cscli alerts list --range 1.2.3.0/24
|
||||||
|
cscli alerts list --origin lists
|
||||||
cscli alerts list -s crowdsecurity/ssh-bf
|
cscli alerts list -s crowdsecurity/ssh-bf
|
||||||
cscli alerts list --type ban`,
|
cscli alerts list --type ban`,
|
||||||
|
Long: `List alerts with optional filters`,
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||||
if err := manageCliDecisionAlerts(alertListFilter.IPEquals, alertListFilter.RangeEquals,
|
if err := manageCliDecisionAlerts(alertListFilter.IPEquals, alertListFilter.RangeEquals,
|
||||||
|
@ -358,7 +360,7 @@ func (cli *cliAlerts) NewDeleteCmd() *cobra.Command {
|
||||||
var (
|
var (
|
||||||
ActiveDecision *bool
|
ActiveDecision *bool
|
||||||
AlertDeleteAll bool
|
AlertDeleteAll bool
|
||||||
delAlertByID string
|
delAlertByID string
|
||||||
)
|
)
|
||||||
|
|
||||||
var alertDeleteFilter = apiclient.AlertsDeleteOpts{
|
var alertDeleteFilter = apiclient.AlertsDeleteOpts{
|
||||||
|
@ -449,7 +451,7 @@ cscli alerts delete -s crowdsecurity/ssh-bf"`,
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
flags.SortFlags = false
|
flags.SortFlags = false
|
||||||
flags.StringVar(alertDeleteFilter.ScopeEquals, "scope", "", "the scope (ie. ip,range)")
|
flags.StringVar(alertDeleteFilter.ScopeEquals, "scope", "", "the scope (ie. ip,range)")
|
||||||
|
@ -520,7 +522,7 @@ func (cli *cliAlerts) NewInspectCmd() *cobra.Command {
|
||||||
func (cli *cliAlerts) NewFlushCmd() *cobra.Command {
|
func (cli *cliAlerts) NewFlushCmd() *cobra.Command {
|
||||||
var (
|
var (
|
||||||
maxItems int
|
maxItems int
|
||||||
maxAge string
|
maxAge string
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
|
|
@ -195,7 +195,7 @@ func (cli *cliDecisions) newListCmd() *cobra.Command {
|
||||||
Example: `cscli decisions list -i 1.2.3.4
|
Example: `cscli decisions list -i 1.2.3.4
|
||||||
cscli decisions list -r 1.2.3.0/24
|
cscli decisions list -r 1.2.3.0/24
|
||||||
cscli decisions list -s crowdsecurity/ssh-bf
|
cscli decisions list -s crowdsecurity/ssh-bf
|
||||||
cscli decisions list -t ban
|
cscli decisions list --origin lists --scenario list_name
|
||||||
`,
|
`,
|
||||||
Args: cobra.ExactArgs(0),
|
Args: cobra.ExactArgs(0),
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
|
@ -436,6 +436,7 @@ func (cli *cliDecisions) newDeleteCmd() *cobra.Command {
|
||||||
cscli decisions delete -i 1.2.3.4
|
cscli decisions delete -i 1.2.3.4
|
||||||
cscli decisions delete --id 42
|
cscli decisions delete --id 42
|
||||||
cscli decisions delete --type captcha
|
cscli decisions delete --type captcha
|
||||||
|
cscli decisions delete --origin lists --scenario list_name
|
||||||
`,
|
`,
|
||||||
/*TBD : refaire le Long/Example*/
|
/*TBD : refaire le Long/Example*/
|
||||||
PreRunE: func(cmd *cobra.Command, _ []string) error {
|
PreRunE: func(cmd *cobra.Command, _ []string) error {
|
||||||
|
|
|
@ -272,9 +272,7 @@ func (ms metricStore) Format(out io.Writer, sections []string, formatType string
|
||||||
|
|
||||||
// if no sections are specified, we want all of them
|
// if no sections are specified, we want all of them
|
||||||
if len(sections) == 0 {
|
if len(sections) == 0 {
|
||||||
for section := range ms {
|
sections = maptools.SortedKeys(ms)
|
||||||
sections = append(sections, section)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, section := range sections {
|
for _, section := range sections {
|
||||||
|
@ -283,7 +281,7 @@ func (ms metricStore) Format(out io.Writer, sections []string, formatType string
|
||||||
|
|
||||||
switch formatType {
|
switch formatType {
|
||||||
case "human":
|
case "human":
|
||||||
for section := range want {
|
for _, section := range maptools.SortedKeys(want) {
|
||||||
want[section].Table(out, noUnit, showEmpty)
|
want[section].Table(out, noUnit, showEmpty)
|
||||||
}
|
}
|
||||||
case "json":
|
case "json":
|
||||||
|
@ -376,7 +374,7 @@ cscli metrics list`,
|
||||||
}
|
}
|
||||||
|
|
||||||
// expandAlias returns a list of sections. The input can be a list of sections or alias.
|
// expandAlias returns a list of sections. The input can be a list of sections or alias.
|
||||||
func (cli *cliMetrics) expandSectionGroups(args []string) []string {
|
func (cli *cliMetrics) expandAlias(args []string) []string {
|
||||||
ret := []string{}
|
ret := []string{}
|
||||||
|
|
||||||
for _, section := range args {
|
for _, section := range args {
|
||||||
|
@ -422,7 +420,7 @@ cscli metrics show acquisition parsers scenarios stash -o json`,
|
||||||
// Positional args are optional
|
// Positional args are optional
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
RunE: func(_ *cobra.Command, args []string) error {
|
RunE: func(_ *cobra.Command, args []string) error {
|
||||||
args = cli.expandSectionGroups(args)
|
args = cli.expandAlias(args)
|
||||||
return cli.show(args, url, noUnit)
|
return cli.show(args, url, noUnit)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ CROWDSEC_TEST_VERSION="dev"
|
||||||
# All of the following flavors will be tested when using the "flavor" fixture
|
# All of the following flavors will be tested when using the "flavor" fixture
|
||||||
CROWDSEC_TEST_FLAVORS="full"
|
CROWDSEC_TEST_FLAVORS="full"
|
||||||
# CROWDSEC_TEST_FLAVORS="full,slim,debian"
|
# CROWDSEC_TEST_FLAVORS="full,slim,debian"
|
||||||
# CROWDSEC_TEST_FLAVORS="full,slim,debian,geoip,plugins-debian-slim,debian-geoip,debian-plugins"
|
# CROWDSEC_TEST_FLAVORS="full,slim,debian,debian-slim"
|
||||||
|
|
||||||
# network to use
|
# network to use
|
||||||
CROWDSEC_TEST_NETWORK="net-test"
|
CROWDSEC_TEST_NETWORK="net-test"
|
||||||
|
|
|
@ -42,7 +42,7 @@ def test_flavor_content(crowdsec, flavor):
|
||||||
x = cs.cont.exec_run(
|
x = cs.cont.exec_run(
|
||||||
'ls -1 /usr/local/lib/crowdsec/plugins/')
|
'ls -1 /usr/local/lib/crowdsec/plugins/')
|
||||||
stdout = x.output.decode()
|
stdout = x.output.decode()
|
||||||
if 'slim' in flavor or 'geoip' in flavor:
|
if 'slim' in flavor:
|
||||||
# the exact return code and full message depend
|
# the exact return code and full message depend
|
||||||
# on the 'ls' implementation (busybox vs coreutils)
|
# on the 'ls' implementation (busybox vs coreutils)
|
||||||
assert x.exit_code != 0
|
assert x.exit_code != 0
|
||||||
|
|
22
go.mod
22
go.mod
|
@ -24,6 +24,7 @@ require (
|
||||||
github.com/buger/jsonparser v1.1.1
|
github.com/buger/jsonparser v1.1.1
|
||||||
github.com/c-robinson/iplib v1.0.3
|
github.com/c-robinson/iplib v1.0.3
|
||||||
github.com/cespare/xxhash/v2 v2.2.0
|
github.com/cespare/xxhash/v2 v2.2.0
|
||||||
|
github.com/corazawaf/libinjection-go v0.1.2
|
||||||
github.com/crowdsecurity/coraza/v3 v3.0.0-20240108124027-a62b8d8e5607
|
github.com/crowdsecurity/coraza/v3 v3.0.0-20240108124027-a62b8d8e5607
|
||||||
github.com/crowdsecurity/dlog v0.0.0-20170105205344-4fb5f8204f26
|
github.com/crowdsecurity/dlog v0.0.0-20170105205344-4fb5f8204f26
|
||||||
github.com/crowdsecurity/go-cs-lib v0.0.6
|
github.com/crowdsecurity/go-cs-lib v0.0.6
|
||||||
|
@ -31,7 +32,7 @@ require (
|
||||||
github.com/crowdsecurity/machineid v1.0.2
|
github.com/crowdsecurity/machineid v1.0.2
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/dghubble/sling v1.3.0
|
github.com/dghubble/sling v1.3.0
|
||||||
github.com/docker/docker v24.0.7+incompatible
|
github.com/docker/docker v24.0.9+incompatible
|
||||||
github.com/docker/go-connections v0.4.0
|
github.com/docker/go-connections v0.4.0
|
||||||
github.com/fatih/color v1.15.0
|
github.com/fatih/color v1.15.0
|
||||||
github.com/fsnotify/fsnotify v1.6.0
|
github.com/fsnotify/fsnotify v1.6.0
|
||||||
|
@ -55,7 +56,7 @@ require (
|
||||||
github.com/hashicorp/go-version v1.2.1
|
github.com/hashicorp/go-version v1.2.1
|
||||||
github.com/hexops/gotextdiff v1.0.3
|
github.com/hexops/gotextdiff v1.0.3
|
||||||
github.com/ivanpirog/coloredcobra v1.0.1
|
github.com/ivanpirog/coloredcobra v1.0.1
|
||||||
github.com/jackc/pgx/v4 v4.14.1
|
github.com/jackc/pgx/v4 v4.18.2
|
||||||
github.com/jarcoal/httpmock v1.1.0
|
github.com/jarcoal/httpmock v1.1.0
|
||||||
github.com/jszwec/csvutil v1.5.1
|
github.com/jszwec/csvutil v1.5.1
|
||||||
github.com/lithammer/dedent v1.1.0
|
github.com/lithammer/dedent v1.1.0
|
||||||
|
@ -81,9 +82,9 @@ require (
|
||||||
github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26
|
github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26
|
||||||
github.com/wasilibs/go-re2 v1.3.0
|
github.com/wasilibs/go-re2 v1.3.0
|
||||||
github.com/xhit/go-simple-mail/v2 v2.16.0
|
github.com/xhit/go-simple-mail/v2 v2.16.0
|
||||||
golang.org/x/crypto v0.17.0
|
golang.org/x/crypto v0.22.0
|
||||||
golang.org/x/mod v0.11.0
|
golang.org/x/mod v0.11.0
|
||||||
golang.org/x/sys v0.15.0
|
golang.org/x/sys v0.19.0
|
||||||
golang.org/x/text v0.14.0
|
golang.org/x/text v0.14.0
|
||||||
google.golang.org/grpc v1.56.3
|
google.golang.org/grpc v1.56.3
|
||||||
google.golang.org/protobuf v1.33.0
|
google.golang.org/protobuf v1.33.0
|
||||||
|
@ -104,7 +105,6 @@ require (
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bytedance/sonic v1.9.1 // indirect
|
github.com/bytedance/sonic v1.9.1 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
github.com/corazawaf/libinjection-go v0.1.2 // indirect
|
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||||
github.com/creack/pty v1.1.18 // indirect
|
github.com/creack/pty v1.1.18 // indirect
|
||||||
|
@ -137,12 +137,12 @@ require (
|
||||||
github.com/imdario/mergo v0.3.12 // indirect
|
github.com/imdario/mergo v0.3.12 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||||
github.com/jackc/pgconn v1.10.1 // indirect
|
github.com/jackc/pgconn v1.14.3 // indirect
|
||||||
github.com/jackc/pgio v1.0.0 // indirect
|
github.com/jackc/pgio v1.0.0 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgproto3/v2 v2.2.0 // indirect
|
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
github.com/jackc/pgtype v1.9.1 // indirect
|
github.com/jackc/pgtype v1.14.0 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
@ -198,9 +198,9 @@ require (
|
||||||
github.com/zclconf/go-cty v1.8.0 // indirect
|
github.com/zclconf/go-cty v1.8.0 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.9.4 // indirect
|
go.mongodb.org/mongo-driver v1.9.4 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/net v0.19.0 // indirect
|
golang.org/x/net v0.24.0 // indirect
|
||||||
golang.org/x/sync v0.6.0 // indirect
|
golang.org/x/sync v0.6.0 // indirect
|
||||||
golang.org/x/term v0.15.0 // indirect
|
golang.org/x/term v0.19.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
golang.org/x/tools v0.8.1-0.20230428195545-5283a0178901 // indirect
|
golang.org/x/tools v0.8.1-0.20230428195545-5283a0178901 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
|
|
40
go.sum
40
go.sum
|
@ -116,8 +116,8 @@ github.com/dghubble/sling v1.3.0 h1:pZHjCJq4zJvc6qVQ5wN1jo5oNZlNE0+8T/h0XeXBUKU=
|
||||||
github.com/dghubble/sling v1.3.0/go.mod h1:XXShWaBWKzNLhu2OxikSNFrlsvowtz4kyRuXUG7oQKY=
|
github.com/dghubble/sling v1.3.0/go.mod h1:XXShWaBWKzNLhu2OxikSNFrlsvowtz4kyRuXUG7oQKY=
|
||||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
|
github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0=
|
||||||
github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
|
@ -368,8 +368,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU
|
||||||
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
||||||
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
|
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
|
||||||
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
||||||
github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8=
|
github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
|
||||||
github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
|
||||||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
||||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||||
|
@ -385,26 +385,26 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW
|
||||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||||
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||||
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||||
github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns=
|
github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
|
||||||
github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
|
|
||||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||||
|
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/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
||||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
||||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
||||||
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
||||||
github.com/jackc/pgtype v1.9.1 h1:MJc2s0MFS8C3ok1wQTdQxWuXQcB6+HwAm5x1CzW7mf0=
|
github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw=
|
||||||
github.com/jackc/pgtype v1.9.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
||||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
||||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
||||||
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
|
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
|
||||||
github.com/jackc/pgx/v4 v4.14.1 h1:71oo1KAGI6mXhLiTMn6iDFcp3e7+zon/capWjl2OEFU=
|
github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU=
|
||||||
github.com/jackc/pgx/v4 v4.14.1/go.mod h1:RgDuE4Z34o7XE92RpLsvFiOEfrAUT0Xt2KxvX73W06M=
|
github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
|
||||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
|
||||||
github.com/jarcoal/httpmock v1.1.0 h1:F47ChZj1Y2zFsCXxNkBPwNNKnAyOATcdQibk0qEdVCE=
|
github.com/jarcoal/httpmock v1.1.0 h1:F47ChZj1Y2zFsCXxNkBPwNNKnAyOATcdQibk0qEdVCE=
|
||||||
github.com/jarcoal/httpmock v1.1.0/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
github.com/jarcoal/httpmock v1.1.0/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
||||||
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
|
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
|
||||||
|
@ -757,8 +757,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
@ -791,8 +791,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -841,8 +841,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
@ -850,8 +850,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
|
|
@ -15,4 +15,6 @@ if ($version.Contains("-"))
|
||||||
Set-Location .\windows\Chocolatey\crowdsec
|
Set-Location .\windows\Chocolatey\crowdsec
|
||||||
Copy-Item ..\..\..\crowdsec_$version.msi tools\crowdsec.msi
|
Copy-Item ..\..\..\crowdsec_$version.msi tools\crowdsec.msi
|
||||||
|
|
||||||
choco pack --version $version
|
choco pack --version $version
|
||||||
|
|
||||||
|
Copy-Item crowdsec.$version.nupkg ..\..\..\
|
|
@ -1,7 +1,7 @@
|
||||||
param (
|
param (
|
||||||
$version
|
$version
|
||||||
)
|
)
|
||||||
$env:Path += ";C:\Program Files (x86)\WiX Toolset v3.11\bin"
|
$env:Path += ";C:\Program Files (x86)\WiX Toolset v3.14\bin"
|
||||||
if ($version.StartsWith("v"))
|
if ($version.StartsWith("v"))
|
||||||
{
|
{
|
||||||
$version = $version.Substring(1)
|
$version = $version.Substring(1)
|
||||||
|
|
714
pkg/acquisition/modules/appsec/appsec_hooks_test.go
Normal file
714
pkg/acquisition/modules/appsec/appsec_hooks_test.go
Normal file
|
@ -0,0 +1,714 @@
|
||||||
|
package appsecacquisition
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/appsec"
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/appsec/appsec_rule"
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAppsecOnMatchHooks(t *testing.T) {
|
||||||
|
tests := []appsecRuleTest{
|
||||||
|
{
|
||||||
|
name: "no rule : check return code",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.Equal(t, 403, responses[0].BouncerHTTPResponseCode)
|
||||||
|
require.Equal(t, 403, responses[0].UserHTTPResponseCode)
|
||||||
|
require.Equal(t, appsec.BanRemediation, responses[0].Action)
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_match: change return code",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on_match: []appsec.Hook{
|
||||||
|
{Filter: "IsInBand == true", Apply: []string{"SetReturnCode(413)"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.Equal(t, 403, responses[0].BouncerHTTPResponseCode)
|
||||||
|
require.Equal(t, 413, responses[0].UserHTTPResponseCode)
|
||||||
|
require.Equal(t, appsec.BanRemediation, responses[0].Action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_match: change action to a non standard one (log)",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on_match: []appsec.Hook{
|
||||||
|
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('log')"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.Equal(t, "log", responses[0].Action)
|
||||||
|
require.Equal(t, 403, responses[0].BouncerHTTPResponseCode)
|
||||||
|
require.Equal(t, 403, responses[0].UserHTTPResponseCode)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_match: change action to another standard one (allow)",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on_match: []appsec.Hook{
|
||||||
|
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('allow')"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.Equal(t, appsec.AllowRemediation, responses[0].Action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_match: change action to another standard one (ban)",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on_match: []appsec.Hook{
|
||||||
|
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('ban')"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
//note: SetAction normalizes deny, ban and block to ban
|
||||||
|
require.Equal(t, appsec.BanRemediation, responses[0].Action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_match: change action to another standard one (captcha)",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on_match: []appsec.Hook{
|
||||||
|
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('captcha')"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
//note: SetAction normalizes deny, ban and block to ban
|
||||||
|
require.Equal(t, appsec.CaptchaRemediation, responses[0].Action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_match: change action to a non standard one",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on_match: []appsec.Hook{
|
||||||
|
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('foobar')"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.Equal(t, "foobar", responses[0].Action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_match: cancel alert",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on_match: []appsec.Hook{
|
||||||
|
{Filter: "IsInBand == true && LogInfo('XX -> %s', evt.Appsec.MatchedRules.GetName())", Apply: []string{"CancelAlert()"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 1)
|
||||||
|
require.Equal(t, types.LOG, events[0].Type)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.Equal(t, appsec.BanRemediation, responses[0].Action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_match: cancel event",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on_match: []appsec.Hook{
|
||||||
|
{Filter: "IsInBand == true", Apply: []string{"CancelEvent()"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 1)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.Equal(t, appsec.BanRemediation, responses[0].Action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
loadAppSecEngine(test, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppsecPreEvalHooks(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []appsecRuleTest{
|
||||||
|
{
|
||||||
|
name: "Basic on_load hook to disable inband rule",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pre_eval: []appsec.Hook{
|
||||||
|
{Filter: "1 == 1", Apply: []string{"RemoveInBandRuleByName('rule1')"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Empty(t, events)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.False(t, responses[0].InBandInterrupt)
|
||||||
|
require.False(t, responses[0].OutOfBandInterrupt)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Basic on_load fails to disable rule",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pre_eval: []appsec.Hook{
|
||||||
|
{Filter: "1 ==2", Apply: []string{"RemoveInBandRuleByName('rule1')"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.True(t, events[1].Appsec.HasInBandMatches)
|
||||||
|
require.Len(t, events[1].Appsec.MatchedRules, 1)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.True(t, responses[0].InBandInterrupt)
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_load : disable inband by tag",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rulez",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pre_eval: []appsec.Hook{
|
||||||
|
{Apply: []string{"RemoveInBandRuleByTag('crowdsec-rulez')"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Empty(t, events)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.False(t, responses[0].InBandInterrupt)
|
||||||
|
require.False(t, responses[0].OutOfBandInterrupt)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_load : disable inband by ID",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rulez",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pre_eval: []appsec.Hook{
|
||||||
|
{Apply: []string{"RemoveInBandRuleByID(1516470898)"}}, //rule ID is generated at runtime. If you change rule, it will break the test (:
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Empty(t, events)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.False(t, responses[0].InBandInterrupt)
|
||||||
|
require.False(t, responses[0].OutOfBandInterrupt)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_load : disable inband by name",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rulez",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pre_eval: []appsec.Hook{
|
||||||
|
{Apply: []string{"RemoveInBandRuleByName('rulez')"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Empty(t, events)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.False(t, responses[0].InBandInterrupt)
|
||||||
|
require.False(t, responses[0].OutOfBandInterrupt)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_load : outofband default behavior",
|
||||||
|
expected_load_ok: true,
|
||||||
|
outofband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rulez",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 1)
|
||||||
|
require.Equal(t, types.LOG, events[0].Type)
|
||||||
|
require.True(t, events[0].Appsec.HasOutBandMatches)
|
||||||
|
require.False(t, events[0].Appsec.HasInBandMatches)
|
||||||
|
require.Len(t, events[0].Appsec.MatchedRules, 1)
|
||||||
|
require.Equal(t, "rulez", events[0].Appsec.MatchedRules[0]["msg"])
|
||||||
|
//maybe surprising, but response won't mention OOB event, as it's sent as soon as the inband phase is over.
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.False(t, responses[0].InBandInterrupt)
|
||||||
|
require.False(t, responses[0].OutOfBandInterrupt)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_load : set remediation by tag",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rulez",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pre_eval: []appsec.Hook{
|
||||||
|
{Apply: []string{"SetRemediationByTag('crowdsec-rulez', 'foobar')"}}, //rule ID is generated at runtime. If you change rule, it will break the test (:
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.Equal(t, "foobar", responses[0].Action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_load : set remediation by name",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rulez",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pre_eval: []appsec.Hook{
|
||||||
|
{Apply: []string{"SetRemediationByName('rulez', 'foobar')"}}, //rule ID is generated at runtime. If you change rule, it will break the test (:
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.Equal(t, "foobar", responses[0].Action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "on_load : set remediation by ID",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rulez",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pre_eval: []appsec.Hook{
|
||||||
|
{Apply: []string{"SetRemediationByID(1516470898, 'foobar')"}}, //rule ID is generated at runtime. If you change rule, it will break the test (:
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.Equal(t, "foobar", responses[0].Action)
|
||||||
|
require.Equal(t, "foobar", appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
loadAppSecEngine(test, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppsecRemediationConfigHooks(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []appsecRuleTest{
|
||||||
|
{
|
||||||
|
name: "Basic matching rule",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.BanRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, statusCode)
|
||||||
|
require.Equal(t, appsec.BanRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SetRemediation",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
on_match: []appsec.Hook{{Apply: []string{"SetRemediation('captcha')"}}}, //rule ID is generated at runtime. If you change rule, it will break the test (:
|
||||||
|
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.CaptchaRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, statusCode)
|
||||||
|
require.Equal(t, appsec.CaptchaRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SetRemediation",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
on_match: []appsec.Hook{{Apply: []string{"SetReturnCode(418)"}}}, //rule ID is generated at runtime. If you change rule, it will break the test (:
|
||||||
|
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.BanRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, statusCode)
|
||||||
|
require.Equal(t, appsec.BanRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusTeapot, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
loadAppSecEngine(test, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestOnMatchRemediationHooks(t *testing.T) {
|
||||||
|
tests := []appsecRuleTest{
|
||||||
|
{
|
||||||
|
name: "set remediation to allow with on_match hook",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
on_match: []appsec.Hook{
|
||||||
|
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('allow')"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.AllowRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusOK, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "set remediation to captcha + custom user code with on_match hook",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
DefaultRemediation: appsec.AllowRemediation,
|
||||||
|
on_match: []appsec.Hook{
|
||||||
|
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('captcha')", "SetReturnCode(418)"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
spew.Dump(responses)
|
||||||
|
spew.Dump(appsecResponse)
|
||||||
|
|
||||||
|
log.Errorf("http status : %d", statusCode)
|
||||||
|
require.Equal(t, appsec.CaptchaRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusTeapot, appsecResponse.HTTPStatus)
|
||||||
|
require.Equal(t, http.StatusForbidden, statusCode)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
loadAppSecEngine(test, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
74
pkg/acquisition/modules/appsec/appsec_lnx_test.go
Normal file
74
pkg/acquisition/modules/appsec/appsec_lnx_test.go
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package appsecacquisition
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/appsec"
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/appsec/appsec_rule"
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAppsecRuleTransformsOthers(t *testing.T) {
|
||||||
|
|
||||||
|
log.SetLevel(log.TraceLevel)
|
||||||
|
tests := []appsecRuleTest{
|
||||||
|
{
|
||||||
|
name: "normalizepath",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "b/c"},
|
||||||
|
Transform: []string{"normalizepath"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/?foo=a/../b/c",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "normalizepath #2",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "b/c/"},
|
||||||
|
Transform: []string{"normalizepath"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/?foo=a/../b/c/////././././",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
loadAppSecEngine(test, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
320
pkg/acquisition/modules/appsec/appsec_remediation_test.go
Normal file
320
pkg/acquisition/modules/appsec/appsec_remediation_test.go
Normal file
|
@ -0,0 +1,320 @@
|
||||||
|
package appsecacquisition
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/appsec"
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/appsec/appsec_rule"
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAppsecDefaultPassRemediation(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []appsecRuleTest{
|
||||||
|
{
|
||||||
|
name: "Basic non-matching rule",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/",
|
||||||
|
Args: url.Values{"foo": []string{"tutu"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.AllowRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusOK, statusCode)
|
||||||
|
require.Equal(t, appsec.AllowRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusOK, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DefaultPassAction: pass",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/",
|
||||||
|
Args: url.Values{"foo": []string{"tutu"}},
|
||||||
|
},
|
||||||
|
DefaultPassAction: "allow",
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.AllowRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusOK, statusCode)
|
||||||
|
require.Equal(t, appsec.AllowRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusOK, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DefaultPassAction: captcha",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/",
|
||||||
|
Args: url.Values{"foo": []string{"tutu"}},
|
||||||
|
},
|
||||||
|
DefaultPassAction: "captcha",
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.CaptchaRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusOK, statusCode) //@tko: body is captcha, but as it's 200, captcha won't be showed to user
|
||||||
|
require.Equal(t, appsec.CaptchaRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusOK, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DefaultPassHTTPCode: 200",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/",
|
||||||
|
Args: url.Values{"foo": []string{"tutu"}},
|
||||||
|
},
|
||||||
|
UserPassedHTTPCode: 200,
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.AllowRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusOK, statusCode)
|
||||||
|
require.Equal(t, appsec.AllowRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusOK, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DefaultPassHTTPCode: 200",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/",
|
||||||
|
Args: url.Values{"foo": []string{"tutu"}},
|
||||||
|
},
|
||||||
|
UserPassedHTTPCode: 418,
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.AllowRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusOK, statusCode)
|
||||||
|
require.Equal(t, appsec.AllowRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusTeapot, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
loadAppSecEngine(test, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppsecDefaultRemediation(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []appsecRuleTest{
|
||||||
|
{
|
||||||
|
name: "Basic matching rule",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.BanRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, statusCode)
|
||||||
|
require.Equal(t, appsec.BanRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "default remediation to ban (default)",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
DefaultRemediation: "ban",
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.BanRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, statusCode)
|
||||||
|
require.Equal(t, appsec.BanRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "default remediation to allow",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
DefaultRemediation: "allow",
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.AllowRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusOK, statusCode)
|
||||||
|
require.Equal(t, appsec.AllowRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusOK, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "default remediation to captcha",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
DefaultRemediation: "captcha",
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.CaptchaRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, statusCode)
|
||||||
|
require.Equal(t, appsec.CaptchaRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom user HTTP code",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
UserBlockedHTTPCode: 418,
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.BanRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, statusCode)
|
||||||
|
require.Equal(t, appsec.BanRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusTeapot, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom remediation + HTTP code",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
UserBlockedHTTPCode: 418,
|
||||||
|
DefaultRemediation: "foobar",
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, "foobar", responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, statusCode)
|
||||||
|
require.Equal(t, "foobar", appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusTeapot, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
loadAppSecEngine(test, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
733
pkg/acquisition/modules/appsec/appsec_rules_test.go
Normal file
733
pkg/acquisition/modules/appsec/appsec_rules_test.go
Normal file
|
@ -0,0 +1,733 @@
|
||||||
|
package appsecacquisition
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/appsec"
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/appsec/appsec_rule"
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAppsecRuleMatches(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []appsecRuleTest{
|
||||||
|
{
|
||||||
|
name: "Basic matching rule",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.True(t, events[1].Appsec.HasInBandMatches)
|
||||||
|
require.Len(t, events[1].Appsec.MatchedRules, 1)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.True(t, responses[0].InBandInterrupt)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Basic non-matching rule",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"tutu"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Empty(t, events)
|
||||||
|
require.Len(t, responses, 1)
|
||||||
|
require.False(t, responses[0].InBandInterrupt)
|
||||||
|
require.False(t, responses[0].OutOfBandInterrupt)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "default remediation to allow",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
DefaultRemediation: "allow",
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.AllowRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusOK, statusCode)
|
||||||
|
require.Equal(t, appsec.AllowRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusOK, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "default remediation to captcha",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
DefaultRemediation: "captcha",
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.CaptchaRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, statusCode)
|
||||||
|
require.Equal(t, appsec.CaptchaRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no default remediation / custom user HTTP code",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"toto"}},
|
||||||
|
},
|
||||||
|
UserBlockedHTTPCode: 418,
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Equal(t, appsec.BanRemediation, responses[0].Action)
|
||||||
|
require.Equal(t, http.StatusForbidden, statusCode)
|
||||||
|
require.Equal(t, appsec.BanRemediation, appsecResponse.Action)
|
||||||
|
require.Equal(t, http.StatusTeapot, appsecResponse.HTTPStatus)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no match but try to set remediation to captcha with on_match hook",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on_match: []appsec.Hook{
|
||||||
|
{Filter: "IsInBand == true", Apply: []string{"SetRemediation('captcha')"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"bla"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Empty(t, events)
|
||||||
|
require.Equal(t, http.StatusOK, statusCode)
|
||||||
|
require.Equal(t, appsec.AllowRemediation, appsecResponse.Action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no match but try to set user HTTP code with on_match hook",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on_match: []appsec.Hook{
|
||||||
|
{Filter: "IsInBand == true", Apply: []string{"SetReturnCode(418)"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"bla"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Empty(t, events)
|
||||||
|
require.Equal(t, http.StatusOK, statusCode)
|
||||||
|
require.Equal(t, appsec.AllowRemediation, appsecResponse.Action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no match but try to set remediation with pre_eval hook",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule42",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "regex", Value: "^toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pre_eval: []appsec.Hook{
|
||||||
|
{Filter: "IsInBand == true", Apply: []string{"SetRemediationByName('rule42', 'captcha')"}},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/urllll",
|
||||||
|
Args: url.Values{"foo": []string{"bla"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Empty(t, events)
|
||||||
|
require.Equal(t, http.StatusOK, statusCode)
|
||||||
|
require.Equal(t, appsec.AllowRemediation, appsecResponse.Action)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
loadAppSecEngine(test, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppsecRuleTransforms(t *testing.T) {
|
||||||
|
|
||||||
|
log.SetLevel(log.TraceLevel)
|
||||||
|
tests := []appsecRuleTest{
|
||||||
|
{
|
||||||
|
name: "Basic matching rule",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"URI"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "/toto"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/toto",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "lowercase",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"URI"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "/toto"},
|
||||||
|
Transform: []string{"lowercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/TOTO",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "uppercase",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"URI"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "/TOTO"},
|
||||||
|
Transform: []string{"uppercase"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/toto",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "b64decode",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "toto"},
|
||||||
|
Transform: []string{"b64decode"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/?foo=dG90bw",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "b64decode with extra padding",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "toto"},
|
||||||
|
Transform: []string{"b64decode"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/?foo=dG90bw===",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "length",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "gte", Value: "3"},
|
||||||
|
Transform: []string{"length"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/?foo=toto",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "urldecode",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "BB/A"},
|
||||||
|
Transform: []string{"urldecode"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/?foo=%42%42%2F%41",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "trim",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Variables: []string{"foo"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "BB/A"},
|
||||||
|
Transform: []string{"urldecode", "trim"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/?foo=%20%20%42%42%2F%41%20%20",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
loadAppSecEngine(test, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppsecRuleZones(t *testing.T) {
|
||||||
|
|
||||||
|
log.SetLevel(log.TraceLevel)
|
||||||
|
tests := []appsecRuleTest{
|
||||||
|
{
|
||||||
|
name: "rule: ARGS",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "toto"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "rule2",
|
||||||
|
Zones: []string{"ARGS"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "foobar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/foobar?something=toto&foobar=smth",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rule: ARGS_NAMES",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"ARGS_NAMES"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "toto"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "rule2",
|
||||||
|
Zones: []string{"ARGS_NAMES"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "foobar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/foobar?something=toto&foobar=smth",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule2", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rule: BODY_ARGS",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"BODY_ARGS"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "toto"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "rule2",
|
||||||
|
Zones: []string{"BODY_ARGS"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "foobar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/",
|
||||||
|
Body: []byte("smth=toto&foobar=other"),
|
||||||
|
Headers: http.Header{"Content-Type": []string{"application/x-www-form-urlencoded"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rule: BODY_ARGS_NAMES",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"BODY_ARGS_NAMES"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "toto"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "rule2",
|
||||||
|
Zones: []string{"BODY_ARGS_NAMES"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "foobar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/",
|
||||||
|
Body: []byte("smth=toto&foobar=other"),
|
||||||
|
Headers: http.Header{"Content-Type": []string{"application/x-www-form-urlencoded"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule2", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rule: HEADERS",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"HEADERS"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "toto"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "rule2",
|
||||||
|
Zones: []string{"HEADERS"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "foobar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/",
|
||||||
|
Headers: http.Header{"foobar": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rule: HEADERS_NAMES",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"HEADERS_NAMES"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "toto"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "rule2",
|
||||||
|
Zones: []string{"HEADERS_NAMES"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "foobar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/",
|
||||||
|
Headers: http.Header{"foobar": []string{"toto"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule2", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rule: METHOD",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"METHOD"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "GET"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rule: PROTOCOL",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"PROTOCOL"},
|
||||||
|
Match: appsec_rule.Match{Type: "contains", Value: "3.1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/",
|
||||||
|
Proto: "HTTP/3.1",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rule: URI",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"URI"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "/foobar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/foobar",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rule: URI_FULL",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"URI_FULL"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "/foobar?a=b"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/foobar?a=b",
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rule: RAW_BODY",
|
||||||
|
expected_load_ok: true,
|
||||||
|
inband_rules: []appsec_rule.CustomRule{
|
||||||
|
{
|
||||||
|
Name: "rule1",
|
||||||
|
Zones: []string{"RAW_BODY"},
|
||||||
|
Match: appsec_rule.Match{Type: "equals", Value: "foobar=42421"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input_request: appsec.ParsedRequest{
|
||||||
|
RemoteAddr: "1.2.3.4",
|
||||||
|
Method: "GET",
|
||||||
|
URI: "/",
|
||||||
|
Body: []byte("foobar=42421"),
|
||||||
|
Headers: http.Header{"Content-Type": []string{"application/x-www-form-urlencoded"}},
|
||||||
|
},
|
||||||
|
output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
require.Len(t, events, 2)
|
||||||
|
require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
loadAppSecEngine(test, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
46
pkg/acquisition/modules/appsec/appsec_win_test.go
Normal file
46
pkg/acquisition/modules/appsec/appsec_win_test.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package appsecacquisition
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAppsecRuleTransformsWindows(t *testing.T) {
|
||||||
|
|
||||||
|
log.SetLevel(log.TraceLevel)
|
||||||
|
tests := []appsecRuleTest{
|
||||||
|
// {
|
||||||
|
// name: "normalizepath",
|
||||||
|
// expected_load_ok: true,
|
||||||
|
// inband_rules: []appsec_rule.CustomRule{
|
||||||
|
// {
|
||||||
|
// Name: "rule1",
|
||||||
|
// Zones: []string{"ARGS"},
|
||||||
|
// Variables: []string{"foo"},
|
||||||
|
// Match: appsec_rule.Match{Type: "equals", Value: "b/c"},
|
||||||
|
// Transform: []string{"normalizepath"},
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// input_request: appsec.ParsedRequest{
|
||||||
|
// RemoteAddr: "1.2.3.4",
|
||||||
|
// Method: "GET",
|
||||||
|
// URI: "/?foo=a/../b/c",
|
||||||
|
// },
|
||||||
|
// output_asserts: func(events []types.Event, responses []appsec.AppsecTempResponse, appsecResponse appsec.BodyResponse, statusCode int) {
|
||||||
|
// require.Len(t, events, 2)
|
||||||
|
// require.Equal(t, types.APPSEC, events[0].Type)
|
||||||
|
// require.Equal(t, types.LOG, events[1].Type)
|
||||||
|
// require.Equal(t, "rule1", events[1].Appsec.MatchedRules[0]["msg"])
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
loadAppSecEngine(test, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,8 @@ var zonesMap map[string]string = map[string]string{
|
||||||
"HEADERS": "REQUEST_HEADERS",
|
"HEADERS": "REQUEST_HEADERS",
|
||||||
"METHOD": "REQUEST_METHOD",
|
"METHOD": "REQUEST_METHOD",
|
||||||
"PROTOCOL": "REQUEST_PROTOCOL",
|
"PROTOCOL": "REQUEST_PROTOCOL",
|
||||||
"URI": "REQUEST_URI",
|
"URI": "REQUEST_FILENAME",
|
||||||
|
"URI_FULL": "REQUEST_URI",
|
||||||
"RAW_BODY": "REQUEST_BODY",
|
"RAW_BODY": "REQUEST_BODY",
|
||||||
"FILENAMES": "FILES",
|
"FILENAMES": "FILES",
|
||||||
}
|
}
|
||||||
|
@ -28,8 +29,14 @@ var transformMap map[string]string = map[string]string{
|
||||||
"lowercase": "t:lowercase",
|
"lowercase": "t:lowercase",
|
||||||
"uppercase": "t:uppercase",
|
"uppercase": "t:uppercase",
|
||||||
"b64decode": "t:base64Decode",
|
"b64decode": "t:base64Decode",
|
||||||
"hexdecode": "t:hexDecode",
|
//"hexdecode": "t:hexDecode", -> not supported by coraza
|
||||||
"length": "t:length",
|
"length": "t:length",
|
||||||
|
"urldecode": "t:urlDecode",
|
||||||
|
"trim": "t:trim",
|
||||||
|
"normalize_path": "t:normalizePath",
|
||||||
|
"normalizepath": "t:normalizePath",
|
||||||
|
"htmlentitydecode": "t:htmlEntityDecode",
|
||||||
|
"html_entity_decode": "t:htmlEntityDecode",
|
||||||
}
|
}
|
||||||
|
|
||||||
var matchMap map[string]string = map[string]string{
|
var matchMap map[string]string = map[string]string{
|
||||||
|
|
|
@ -365,11 +365,11 @@ func NewParsedRequestFromRequest(r *http.Request, logger *logrus.Entry) (ParsedR
|
||||||
UUID: uuid.New().String(),
|
UUID: uuid.New().String(),
|
||||||
ClientHost: clientHost,
|
ClientHost: clientHost,
|
||||||
ClientIP: clientIP,
|
ClientIP: clientIP,
|
||||||
URI: parsedURL.Path,
|
URI: clientURI,
|
||||||
Method: clientMethod,
|
Method: clientMethod,
|
||||||
Host: r.Host,
|
Host: clientHost,
|
||||||
Headers: r.Header,
|
Headers: r.Header,
|
||||||
URL: r.URL,
|
URL: parsedURL,
|
||||||
Proto: r.Proto,
|
Proto: r.Proto,
|
||||||
Body: body,
|
Body: body,
|
||||||
Args: ParseQuery(parsedURL.RawQuery),
|
Args: ParseQuery(parsedURL.RawQuery),
|
||||||
|
|
|
@ -13,6 +13,7 @@ type ConfigurationPaths struct {
|
||||||
HubDir string `yaml:"hub_dir,omitempty"`
|
HubDir string `yaml:"hub_dir,omitempty"`
|
||||||
PluginDir string `yaml:"plugin_dir,omitempty"`
|
PluginDir string `yaml:"plugin_dir,omitempty"`
|
||||||
NotificationDir string `yaml:"notification_dir,omitempty"`
|
NotificationDir string `yaml:"notification_dir,omitempty"`
|
||||||
|
PatternDir string `yaml:"pattern_dir,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) loadConfigurationPaths() error {
|
func (c *Config) loadConfigurationPaths() error {
|
||||||
|
@ -33,6 +34,10 @@ func (c *Config) loadConfigurationPaths() error {
|
||||||
c.ConfigPaths.HubIndexFile = filepath.Clean(c.ConfigPaths.HubDir + "/.index.json")
|
c.ConfigPaths.HubIndexFile = filepath.Clean(c.ConfigPaths.HubDir + "/.index.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.ConfigPaths.PatternDir == "" {
|
||||||
|
c.ConfigPaths.PatternDir = filepath.Join(c.ConfigPaths.ConfigDir, "patterns/")
|
||||||
|
}
|
||||||
|
|
||||||
var configPathsCleanup = []*string{
|
var configPathsCleanup = []*string{
|
||||||
&c.ConfigPaths.HubDir,
|
&c.ConfigPaths.HubDir,
|
||||||
&c.ConfigPaths.HubIndexFile,
|
&c.ConfigPaths.HubIndexFile,
|
||||||
|
@ -41,6 +46,7 @@ func (c *Config) loadConfigurationPaths() error {
|
||||||
&c.ConfigPaths.SimulationFilePath,
|
&c.ConfigPaths.SimulationFilePath,
|
||||||
&c.ConfigPaths.PluginDir,
|
&c.ConfigPaths.PluginDir,
|
||||||
&c.ConfigPaths.NotificationDir,
|
&c.ConfigPaths.NotificationDir,
|
||||||
|
&c.ConfigPaths.PatternDir,
|
||||||
}
|
}
|
||||||
for _, k := range configPathsCleanup {
|
for _, k := range configPathsCleanup {
|
||||||
if *k == "" {
|
if *k == "" {
|
||||||
|
|
|
@ -7,10 +7,24 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/crowdsecurity/go-cs-lib/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// hubTransport wraps a Transport to set a custom User-Agent.
|
||||||
|
type hubTransport struct {
|
||||||
|
http.RoundTripper
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *hubTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
req.Header.Set("User-Agent", "crowdsec/"+version.String())
|
||||||
|
return t.RoundTripper.RoundTrip(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// hubClient is the HTTP client used to communicate with the CrowdSec Hub.
|
||||||
var hubClient = &http.Client{
|
var hubClient = &http.Client{
|
||||||
Timeout: 120 * time.Second,
|
Timeout: 120 * time.Second,
|
||||||
|
Transport: &hubTransport{http.DefaultTransport},
|
||||||
}
|
}
|
||||||
|
|
||||||
// safePath returns a joined path and ensures that it does not escape the base directory.
|
// safePath returns a joined path and ensures that it does not escape the base directory.
|
||||||
|
|
|
@ -4,9 +4,11 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -32,6 +34,9 @@ func downloadFile(url string, destPath string) error {
|
||||||
return fmt.Errorf("bad http code %d for %s", resp.StatusCode, url)
|
return fmt.Errorf("bad http code %d for %s", resp.StatusCode, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Download to a temporary location to avoid corrupting files
|
||||||
|
// that are currently in use or memory mapped.
|
||||||
|
|
||||||
tmpFile, err := os.CreateTemp(filepath.Dir(destPath), filepath.Base(destPath)+".*.tmp")
|
tmpFile, err := os.CreateTemp(filepath.Dir(destPath), filepath.Base(destPath)+".*.tmp")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -57,6 +62,23 @@ func downloadFile(url string, destPath string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a check on stdout is used while scripting to know if the hub has been upgraded
|
||||||
|
// and a configuration reload is required
|
||||||
|
// TODO: use a better way to communicate this
|
||||||
|
fmt.Printf("updated %s\n", filepath.Base(destPath))
|
||||||
|
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// On Windows, rename will fail if the destination file already exists
|
||||||
|
// so we remove it first.
|
||||||
|
err = os.Remove(destPath)
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, fs.ErrNotExist):
|
||||||
|
break
|
||||||
|
case err != nil:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err = os.Rename(tmpFileName, destPath); err != nil {
|
if err = os.Rename(tmpFileName, destPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +1,56 @@
|
||||||
package cwhub
|
package cwhub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jarcoal/httpmock"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/crowdsecurity/go-cs-lib/cstest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDownloadFile(t *testing.T) {
|
func TestDownloadFile(t *testing.T) {
|
||||||
examplePath := "./example.txt"
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
defer os.Remove(examplePath)
|
switch r.URL.Path {
|
||||||
|
case "/xx":
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = io.WriteString(w, "example content oneoneone")
|
||||||
|
default:
|
||||||
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
_, _ = io.WriteString(w, "not found")
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
httpmock.Activate()
|
dest := filepath.Join(t.TempDir(), "example.txt")
|
||||||
defer httpmock.DeactivateAndReset()
|
defer os.Remove(dest)
|
||||||
|
|
||||||
// OK
|
err := downloadFile(ts.URL+"/xx", dest)
|
||||||
httpmock.RegisterResponder(
|
|
||||||
"GET",
|
|
||||||
"https://example.com/xx",
|
|
||||||
httpmock.NewStringResponder(200, "example content oneoneone"),
|
|
||||||
)
|
|
||||||
|
|
||||||
httpmock.RegisterResponder(
|
|
||||||
"GET",
|
|
||||||
"https://example.com/x",
|
|
||||||
httpmock.NewStringResponder(404, "not found"),
|
|
||||||
)
|
|
||||||
|
|
||||||
err := downloadFile("https://example.com/xx", examplePath)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
content, err := os.ReadFile(examplePath)
|
content, err := os.ReadFile(dest)
|
||||||
assert.Equal(t, "example content oneoneone", string(content))
|
assert.Equal(t, "example content oneoneone", string(content))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// bad uri
|
// bad uri
|
||||||
err = downloadFile("https://zz.com", examplePath)
|
err = downloadFile("https://zz.com", dest)
|
||||||
require.Error(t, err)
|
cstest.RequireErrorContains(t, err, "lookup zz.com")
|
||||||
|
cstest.RequireErrorContains(t, err, "no such host")
|
||||||
|
|
||||||
// 404
|
// 404
|
||||||
err = downloadFile("https://example.com/x", examplePath)
|
err = downloadFile(ts.URL+"/x", dest)
|
||||||
require.Error(t, err)
|
cstest.RequireErrorContains(t, err, "bad http code 404")
|
||||||
|
|
||||||
// bad target
|
// bad target
|
||||||
err = downloadFile("https://example.com/xx", "")
|
err = downloadFile(ts.URL+"/xx", "")
|
||||||
require.Error(t, err)
|
cstest.RequireErrorContains(t, err, cstest.PathNotFoundMessage)
|
||||||
|
|
||||||
|
// destination directory does not exist
|
||||||
|
err = downloadFile(ts.URL+"/xx", filepath.Join(t.TempDir(), "missing/example.txt"))
|
||||||
|
cstest.RequireErrorContains(t, err, cstest.PathNotFoundMessage)
|
||||||
}
|
}
|
||||||
|
|
|
@ -441,6 +441,20 @@ var exprFuncs = []exprCustomFunc{
|
||||||
new(func(float64, float64) bool),
|
new(func(float64, float64) bool),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "LibInjectionIsSQLI",
|
||||||
|
function: LibInjectionIsSQLI,
|
||||||
|
signature: []interface{}{
|
||||||
|
new(func(string) bool),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "LibInjectionIsXSS",
|
||||||
|
function: LibInjectionIsXSS,
|
||||||
|
signature: []interface{}{
|
||||||
|
new(func(string) bool),
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
//go 1.20 "CutPrefix": strings.CutPrefix,
|
//go 1.20 "CutPrefix": strings.CutPrefix,
|
||||||
|
|
17
pkg/exprhelpers/libinjection.go
Normal file
17
pkg/exprhelpers/libinjection.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package exprhelpers
|
||||||
|
|
||||||
|
import "github.com/corazawaf/libinjection-go"
|
||||||
|
|
||||||
|
func LibInjectionIsSQLI(params ...any) (any, error) {
|
||||||
|
str := params[0].(string)
|
||||||
|
|
||||||
|
ret, _ := libinjection.IsSQLi(str)
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func LibInjectionIsXSS(params ...any) (any, error) {
|
||||||
|
str := params[0].(string)
|
||||||
|
|
||||||
|
ret := libinjection.IsXSS(str)
|
||||||
|
return ret, nil
|
||||||
|
}
|
60
pkg/exprhelpers/libinjection_test.go
Normal file
60
pkg/exprhelpers/libinjection_test.go
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package exprhelpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLibinjectionHelpers(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
function func(params ...any) (any, error)
|
||||||
|
params []any
|
||||||
|
expectResult any
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "LibInjectionIsSQLI",
|
||||||
|
function: LibInjectionIsSQLI,
|
||||||
|
params: []any{"?__f__73=73&&__f__75=75&delivery=1&max=24.9&min=15.9&n=12&o=2&p=(select(0)from(select(sleep(15)))v)/*'%2B(select(0)from(select(sleep(15)))v)%2B'\x22%2B(select(0)from(select(sleep(15)))v)%2B\x22*/&rating=4"},
|
||||||
|
expectResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "LibInjectionIsSQLI - no match",
|
||||||
|
function: LibInjectionIsSQLI,
|
||||||
|
params: []any{"?bla=42&foo=bar"},
|
||||||
|
expectResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "LibInjectionIsSQLI - no match 2",
|
||||||
|
function: LibInjectionIsSQLI,
|
||||||
|
params: []any{"https://foo.com/asdkfj?bla=42&foo=bar"},
|
||||||
|
expectResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "LibInjectionIsXSS",
|
||||||
|
function: LibInjectionIsXSS,
|
||||||
|
params: []any{"<script>alert('XSS')</script>"},
|
||||||
|
expectResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "LibInjectionIsXSS - no match",
|
||||||
|
function: LibInjectionIsXSS,
|
||||||
|
params: []any{"?bla=42&foo=bar"},
|
||||||
|
expectResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "LibInjectionIsXSS - no match 2",
|
||||||
|
function: LibInjectionIsXSS,
|
||||||
|
params: []any{"https://foo.com/asdkfj?bla=42&foo[]=bar&foo"},
|
||||||
|
expectResult: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
result, _ := test.function(test.params...)
|
||||||
|
assert.Equal(t, test.expectResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,10 +26,10 @@ produces:
|
||||||
paths:
|
paths:
|
||||||
/decisions/stream:
|
/decisions/stream:
|
||||||
get:
|
get:
|
||||||
description: Returns a list of new/expired decisions. Intended for bouncers that need to "stream" decisions
|
description: Returns a list of new/expired decisions. Intended for remediation component that need to "stream" decisions
|
||||||
summary: getDecisionsStream
|
summary: getDecisionsStream
|
||||||
tags:
|
tags:
|
||||||
- bouncers
|
- Remediation component
|
||||||
operationId: getDecisionsStream
|
operationId: getDecisionsStream
|
||||||
deprecated: false
|
deprecated: false
|
||||||
produces:
|
produces:
|
||||||
|
@ -39,7 +39,7 @@ paths:
|
||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
description: 'If true, means that the bouncers is starting and a full list must be provided'
|
description: 'If true, means that the remediation component is starting and a full list must be provided'
|
||||||
- name: scopes
|
- name: scopes
|
||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
|
@ -73,10 +73,10 @@ paths:
|
||||||
security:
|
security:
|
||||||
- APIKeyAuthorizer: []
|
- APIKeyAuthorizer: []
|
||||||
head:
|
head:
|
||||||
description: Returns a list of new/expired decisions. Intended for bouncers that need to "stream" decisions
|
description: Returns a list of new/expired decisions. Intended for remediation component that need to "stream" decisions
|
||||||
summary: GetDecisionsStream
|
summary: GetDecisionsStream
|
||||||
tags:
|
tags:
|
||||||
- bouncers
|
- Remediation component
|
||||||
operationId: headDecisionsStream
|
operationId: headDecisionsStream
|
||||||
deprecated: false
|
deprecated: false
|
||||||
produces:
|
produces:
|
||||||
|
@ -100,7 +100,7 @@ paths:
|
||||||
description: Returns information about existing decisions
|
description: Returns information about existing decisions
|
||||||
summary: getDecisions
|
summary: getDecisions
|
||||||
tags:
|
tags:
|
||||||
- bouncers
|
- Remediation component
|
||||||
operationId: getDecisions
|
operationId: getDecisions
|
||||||
deprecated: false
|
deprecated: false
|
||||||
produces:
|
produces:
|
||||||
|
@ -164,7 +164,7 @@ paths:
|
||||||
description: Returns information about existing decisions
|
description: Returns information about existing decisions
|
||||||
summary: GetDecisions
|
summary: GetDecisions
|
||||||
tags:
|
tags:
|
||||||
- bouncers
|
- Remediation component
|
||||||
operationId: headDecisions
|
operationId: headDecisions
|
||||||
deprecated: false
|
deprecated: false
|
||||||
produces:
|
produces:
|
||||||
|
@ -1206,7 +1206,7 @@ definitions:
|
||||||
title: "success response"
|
title: "success response"
|
||||||
description: "success response return by the API"
|
description: "success response return by the API"
|
||||||
tags:
|
tags:
|
||||||
- name: bouncers
|
- name: Remediation component
|
||||||
description: 'Operations about decisions : bans, captcha, rate-limit etc.'
|
description: 'Operations about decisions : bans, captcha, rate-limit etc.'
|
||||||
- name: watchers
|
- name: watchers
|
||||||
description: 'Operations about watchers : cscli & crowdsec'
|
description: 'Operations about watchers : cscli & crowdsec'
|
||||||
|
|
|
@ -98,7 +98,7 @@ func NewParsers(hub *cwhub.Hub) *Parsers {
|
||||||
func LoadParsers(cConfig *csconfig.Config, parsers *Parsers) (*Parsers, error) {
|
func LoadParsers(cConfig *csconfig.Config, parsers *Parsers) (*Parsers, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
patternsDir := filepath.Join(cConfig.ConfigPaths.ConfigDir, "patterns/")
|
patternsDir := cConfig.ConfigPaths.PatternDir
|
||||||
log.Infof("Loading grok library %s", patternsDir)
|
log.Infof("Loading grok library %s", patternsDir)
|
||||||
/* load base regexps for two grok parsers */
|
/* load base regexps for two grok parsers */
|
||||||
parsers.Ctx, err = Init(map[string]interface{}{"patterns": patternsDir,
|
parsers.Ctx, err = Init(map[string]interface{}{"patterns": patternsDir,
|
||||||
|
|
10
test/bats.mk
10
test/bats.mk
|
@ -66,11 +66,11 @@ bats-check-requirements: ## Check dependencies for functional tests
|
||||||
@$(TEST_DIR)/bin/check-requirements
|
@$(TEST_DIR)/bin/check-requirements
|
||||||
|
|
||||||
bats-update-tools: ## Install/update tools required for functional tests
|
bats-update-tools: ## Install/update tools required for functional tests
|
||||||
# yq v4.40.4
|
# yq v4.43.1
|
||||||
GOBIN=$(TEST_DIR)/tools go install github.com/mikefarah/yq/v4@1c3d55106075bd37df197b4bc03cb4a413fdb903
|
GOBIN=$(TEST_DIR)/tools go install github.com/mikefarah/yq/v4@c35ec752e38ea0c096d3c44e13cfc0797ac394d8
|
||||||
# cfssl v1.6.4
|
# cfssl v1.6.5
|
||||||
GOBIN=$(TEST_DIR)/tools go install github.com/cloudflare/cfssl/cmd/cfssl@b4d0d877cac528f63db39dfb62d5c96cd3a32a0b
|
GOBIN=$(TEST_DIR)/tools go install github.com/cloudflare/cfssl/cmd/cfssl@96259aa29c9cc9b2f4e04bad7d4bc152e5405dda
|
||||||
GOBIN=$(TEST_DIR)/tools go install github.com/cloudflare/cfssl/cmd/cfssljson@b4d0d877cac528f63db39dfb62d5c96cd3a32a0b
|
GOBIN=$(TEST_DIR)/tools go install github.com/cloudflare/cfssl/cmd/cfssljson@96259aa29c9cc9b2f4e04bad7d4bc152e5405dda
|
||||||
|
|
||||||
# Build and installs crowdsec in a local directory. Rebuilds if already exists.
|
# Build and installs crowdsec in a local directory. Rebuilds if already exists.
|
||||||
bats-build: bats-environment ## Build binaries for functional tests
|
bats-build: bats-environment ## Build binaries for functional tests
|
||||||
|
|
Loading…
Reference in a new issue