Skip to content

Commit

Permalink
Merge branch 'main' into regex_default_mods
Browse files Browse the repository at this point in the history
  • Loading branch information
M4tteoP authored Nov 18, 2024
2 parents 1c7633a + 3bc5ef6 commit 3c50384
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 75 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Initialize CodeQL
uses: github/codeql-action/init@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3
uses: github/codeql-action/init@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3
with:
languages: go

- name: Autobuild
uses: github/codeql-action/autobuild@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3
uses: github/codeql-action/autobuild@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3
uses: github/codeql-action/analyze@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3
10 changes: 5 additions & 5 deletions .github/workflows/regression.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
tags: ${{ steps.generate.outputs.tags }}
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Generate tag combinations
id: generate
Expand Down Expand Up @@ -48,28 +48,28 @@ jobs:
export BUILD_TAGS=${{ matrix.build-flag }}
go run mage.go coverage
- name: "Codecov: General"
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # v5
if: ${{ matrix.go-version == '1.22.x' }}
with:
files: build/coverage.txt
flags: default,${{ matrix.build-flag }}
token: ${{ secrets.CODECOV_TOKEN }}
- name: "Codecov: Examples"
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # v5
if: ${{ matrix.go-version == '1.22.x' }}
with:
files: build/coverage-examples.txt
flags: examples+${{ matrix.build-flag }}
token: ${{ secrets.CODECOV_TOKEN }}
- name: "Codecov: FTW"
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # v5
if: ${{ matrix.go-version == '1.22.x' }}
with:
files: build/coverage-ftw.txt
flags: ftw,${{ matrix.build-flag }}
token: ${{ secrets.CODECOV_TOKEN }}
- name: "Codecov: Tinygo"
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # v5
# only if coverage-tinygo.txt exists
if: ${{ matrix.go-version == '1.22.x' && hashFiles('build/coverage-tinygo.txt') != '' }}
with:
Expand Down
26 changes: 18 additions & 8 deletions internal/collections/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,15 @@ func (c *Map) Get(key string) []string {
if !c.isCaseSensitive {
key = strings.ToLower(key)
}
var values []string
for _, a := range c.data[key] {
values = append(values, a.value)
values := c.data[key]
if len(values) == 0 {
return nil
}
result := make([]string, len(values))
for i, v := range values {
result[i] = v.value
}
return values
return result
}

// FindRegex returns all map elements whose key matches the regular expression.
Expand Down Expand Up @@ -120,16 +124,22 @@ func (c *Map) Add(key string, value string) {
c.data[key] = append(c.data[key], aVal)
}

// Set sets the value of a key with the array of strings passed. If the key already exists, it will be overwritten.
// Sets the value of a key with the array of strings passed. If the key already exists, it will be overwritten.
func (c *Map) Set(key string, values []string) {
originalKey := key
if !c.isCaseSensitive {
key = strings.ToLower(key)
}
c.data[key] = make([]keyValue, 0, len(values))
for _, v := range values {
c.data[key] = append(c.data[key], keyValue{key: originalKey, value: v})
dataSlice, exists := c.data[key]
if !exists || cap(dataSlice) < len(values) {
dataSlice = make([]keyValue, len(values))
} else {
dataSlice = dataSlice[:len(values)] // Reuse existing slice with the same length
}
for i, v := range values {
dataSlice[i] = keyValue{key: originalKey, value: v}
}
c.data[key] = dataSlice
}

// SetIndex sets the value of a key at the specified index. If the key already exists, it will be overwritten.
Expand Down
22 changes: 22 additions & 0 deletions internal/collections/map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,25 @@ func TestNewCaseSensitiveKeyMap(t *testing.T) {
}

}

func BenchmarkTxSetGet(b *testing.B) {
keys := make(map[int]string, b.N)
for i := 0; i < b.N; i++ {
keys[i] = fmt.Sprintf("key%d", i)
}
c := NewCaseSensitiveKeyMap(variables.RequestHeaders)

b.Run("Set", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
c.Set(keys[i], []string{"value2"})
}
})
b.Run("Get", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
c.Get(keys[i])
}
})
b.ReportAllocs()
}
8 changes: 4 additions & 4 deletions internal/collections/named.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ func (c *NamedCollection) Len() int {

// Data is an internal method used for serializing to JSON
func (c *NamedCollection) Data() map[string][]string {
result := map[string][]string{}
result := make(map[string][]string, len(c.data))
for k, v := range c.data {
result[k] = make([]string, 0, len(v))
for _, a := range v {
result[k] = append(result[k], a.value)
result[k] = make([]string, len(v))
for i, a := range v {
result[k][i] = a.value
}
}
return result
Expand Down
12 changes: 6 additions & 6 deletions internal/corazarules/rule_match.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,27 +33,27 @@ type MatchData struct {

var _ types.MatchData = (*MatchData)(nil)

func (m *MatchData) Variable() variables.RuleVariable {
func (m MatchData) Variable() variables.RuleVariable {
return m.Variable_
}

func (m *MatchData) Key() string {
func (m MatchData) Key() string {
return m.Key_
}

func (m *MatchData) Value() string {
func (m MatchData) Value() string {
return m.Value_
}

func (m *MatchData) Message() string {
func (m MatchData) Message() string {
return m.Message_
}

func (m *MatchData) Data() string {
func (m MatchData) Data() string {
return m.Data_
}

func (m *MatchData) ChainLevel() int {
func (m MatchData) ChainLevel() int {
return m.ChainLevel_
}

Expand Down
82 changes: 45 additions & 37 deletions internal/corazawaf/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,17 @@ func (r *Rule) doEvaluate(logger debuglog.Logger, phase types.RulePhase, tx *Tra
}
vLog.Debug().Msg("Expanding arguments for rule")

args := make([]string, 1)
var errs []error
var argsLen int
for i, arg := range values {
args, errs := r.transformArg(arg, i, cache)
if r.MultiMatch {
args, errs = r.transformMultiMatchArg(arg)
argsLen = len(args)
} else {
args[0], errs = r.transformArg(arg, i, cache)
argsLen = 1
}
if len(errs) > 0 {
vWarnLog := vLog.Warn()
if vWarnLog.IsEnabled() {
Expand All @@ -255,7 +264,7 @@ func (r *Rule) doEvaluate(logger debuglog.Logger, phase types.RulePhase, tx *Tra
}

// args represents the transformed variables
for _, carg := range args {
for _, carg := range args[:argsLen] {
evalLog := vLog.
Debug().
Str("operator_function", r.operator.Function).
Expand Down Expand Up @@ -381,42 +390,41 @@ func (r *Rule) doEvaluate(logger debuglog.Logger, phase types.RulePhase, tx *Tra
return matchedValues
}

func (r *Rule) transformArg(arg types.MatchData, argIdx int, cache map[transformationKey]*transformationValue) ([]string, []error) {
if r.MultiMatch {
// TODOs:
// - We don't need to run every transformation. We could try for each until found
// - Cache is not used for multimatch
return r.executeTransformationsMultimatch(arg.Value())
} else {
switch {
case len(r.transformations) == 0:
return []string{arg.Value()}, nil
case arg.Variable().Name() == "TX":
// no cache for TX
arg, errs := r.executeTransformations(arg.Value())
return []string{arg}, errs
default:
// NOTE: See comment on transformationKey struct to understand this hacky code
argKey := arg.Key()
argKeyPtr := unsafe.StringData(argKey)
key := transformationKey{
argKey: argKeyPtr,
argIndex: argIdx,
argVariable: arg.Variable(),
transformationsID: r.transformationsID,
}
if cached, ok := cache[key]; ok {
return cached.args, cached.errs
} else {
ars, es := r.executeTransformations(arg.Value())
args := []string{ars}
errs := es
cache[key] = &transformationValue{
args: args,
errs: es,
}
return args, errs
func (r *Rule) transformMultiMatchArg(arg types.MatchData) ([]string, []error) {
// TODOs:
// - We don't need to run every transformation. We could try for each until found
// - Cache is not used for multimatch
return r.executeTransformationsMultimatch(arg.Value())
}

func (r *Rule) transformArg(arg types.MatchData, argIdx int, cache map[transformationKey]*transformationValue) (string, []error) {
switch {
case len(r.transformations) == 0:
return arg.Value(), nil
case arg.Variable().Name() == "TX":
// no cache for TX
arg, errs := r.executeTransformations(arg.Value())
return arg, errs
default:
// NOTE: See comment on transformationKey struct to understand this hacky code
argKey := arg.Key()
argKeyPtr := unsafe.StringData(argKey)
key := transformationKey{
argKey: argKeyPtr,
argIndex: argIdx,
argVariable: arg.Variable(),
transformationsID: r.transformationsID,
}
if cached, ok := cache[key]; ok {
return cached.arg, cached.errs
} else {
ars, es := r.executeTransformations(arg.Value())
errs := es
cache[key] = &transformationValue{
arg: ars,
errs: es,
}
return ars, errs
}
}
}
Expand Down
18 changes: 9 additions & 9 deletions internal/corazawaf/rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,23 +506,23 @@ func TestTransformArgSimple(t *testing.T) {
rule := NewRule()
_ = rule.AddTransformation("AppendA", transformationAppendA)
_ = rule.AddTransformation("AppendB", transformationAppendB)
args, errs := rule.transformArg(md, 0, transformationCache)
arg, errs := rule.transformArg(md, 0, transformationCache)
if errs != nil {
t.Fatalf("Unexpected errors executing transformations: %v", errs)
}
if args[0] != "/testAB" {
t.Errorf("Expected \"/testAB\", got \"%s\"", args[0])
if arg != "/testAB" {
t.Errorf("Expected \"/testAB\", got \"%s\"", arg)
}
if len(transformationCache) != 1 {
t.Errorf("Expected 1 transformations in cache, got %d", len(transformationCache))
}
// Repeating the same transformation, expecting still one element in the cache (that means it is a cache hit)
args, errs = rule.transformArg(md, 0, transformationCache)
arg, errs = rule.transformArg(md, 0, transformationCache)
if errs != nil {
t.Fatalf("Unexpected errors executing transformations: %v", errs)
}
if args[0] != "/testAB" {
t.Errorf("Expected \"/testAB\", got \"%s\"", args[0])
if arg != "/testAB" {
t.Errorf("Expected \"/testAB\", got \"%s\"", arg)
}
if len(transformationCache) != 1 {
t.Errorf("Expected 1 transformations in cache, got %d", len(transformationCache))
Expand All @@ -538,12 +538,12 @@ func TestTransformArgNoCacheForTXVariable(t *testing.T) {
}
rule := NewRule()
_ = rule.AddTransformation("AppendA", transformationAppendA)
args, errs := rule.transformArg(md, 0, transformationCache)
arg, errs := rule.transformArg(md, 0, transformationCache)
if errs != nil {
t.Fatalf("Unexpected errors executing transformations: %v", errs)
}
if args[0] != "testA" {
t.Errorf("Expected \"testA\", got \"%s\"", args[0])
if arg != "testA" {
t.Errorf("Expected \"testA\", got \"%s\"", arg)
}
if len(transformationCache) != 0 {
t.Errorf("Expected 0 transformations in cache, got %d. It is not expected to cache TX variable transformations", len(transformationCache))
Expand Down
2 changes: 1 addition & 1 deletion internal/corazawaf/rulegroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,6 @@ type transformationKey struct {
}

type transformationValue struct {
args []string
arg string
errs []error
}
4 changes: 2 additions & 2 deletions testing/coreruleset/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ go 1.22.3

require (
github.com/bmatcuk/doublestar/v4 v4.7.1
github.com/corazawaf/coraza-coreruleset/v4 v4.6.0
github.com/corazawaf/coraza/v3 v3.2.1
github.com/corazawaf/coraza-coreruleset/v4 v4.7.0
github.com/corazawaf/coraza/v3 v3.2.2
github.com/coreruleset/albedo v0.0.16
github.com/coreruleset/go-ftw v1.1.1
github.com/rs/zerolog v1.33.0
Expand Down
2 changes: 2 additions & 0 deletions testing/coreruleset/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ github.com/corazawaf/coraza-coreruleset v0.0.0-20240226094324-415b1017abdc h1:Ol
github.com/corazawaf/coraza-coreruleset v0.0.0-20240226094324-415b1017abdc/go.mod h1:7rsocqNDkTCira5T0M7buoKR2ehh7YZiPkzxRuAgvVU=
github.com/corazawaf/coraza-coreruleset/v4 v4.6.0 h1:VGlMw3QMuKaV7XgifPgcqCm66K+HRSdM4d9PRh1nD50=
github.com/corazawaf/coraza-coreruleset/v4 v4.6.0/go.mod h1:1FQt1p+JSQ6tYrafMqZrEEdDmhq6aVuIJdnk+bM9hMY=
github.com/corazawaf/coraza-coreruleset/v4 v4.7.0 h1:j02CDxQYHVFZfBxbKLWYg66jSLbPmZp1GebyMwzN9Z0=
github.com/corazawaf/coraza-coreruleset/v4 v4.7.0/go.mod h1:1FQt1p+JSQ6tYrafMqZrEEdDmhq6aVuIJdnk+bM9hMY=
github.com/corazawaf/libinjection-go v0.2.2 h1:Chzodvb6+NXh6wew5/yhD0Ggioif9ACrQGR4qjTCs1g=
github.com/corazawaf/libinjection-go v0.2.2/go.mod h1:OP4TM7xdJ2skyXqNX1AN1wN5nNZEmJNuWbNPOItn7aw=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
Expand Down

0 comments on commit 3c50384

Please sign in to comment.