refactor: move CEL checker to its own package

Signed-off-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
Xe Iaso 2025-07-25 19:52:07 +00:00
parent 590d8303ad
commit e98d749bf2
No known key found for this signature in database
13 changed files with 135 additions and 78 deletions

View File

@ -31,6 +31,7 @@ import (
"github.com/TecharoHQ/anubis/data" "github.com/TecharoHQ/anubis/data"
"github.com/TecharoHQ/anubis/internal" "github.com/TecharoHQ/anubis/internal"
libanubis "github.com/TecharoHQ/anubis/lib" libanubis "github.com/TecharoHQ/anubis/lib"
"github.com/TecharoHQ/anubis/lib/checker/headerexists"
botPolicy "github.com/TecharoHQ/anubis/lib/policy" botPolicy "github.com/TecharoHQ/anubis/lib/policy"
"github.com/TecharoHQ/anubis/lib/policy/config" "github.com/TecharoHQ/anubis/lib/policy/config"
"github.com/TecharoHQ/anubis/lib/thoth" "github.com/TecharoHQ/anubis/lib/thoth"
@ -323,7 +324,7 @@ func main() {
if *debugBenchmarkJS { if *debugBenchmarkJS {
policy.Bots = []botPolicy.Bot{{ policy.Bots = []botPolicy.Bot{{
Name: "", Name: "",
Rules: botPolicy.NewHeaderExistsChecker("User-Agent"), Rules: headerexists.New("User-Agent"),
Action: config.RuleBenchmark, Action: config.RuleBenchmark,
}} }}
} }

View File

@ -12,6 +12,7 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/TecharoHQ/anubis/lib/checker/expression"
"github.com/TecharoHQ/anubis/lib/policy/config" "github.com/TecharoHQ/anubis/lib/policy/config"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
@ -37,11 +38,11 @@ type RobotsRule struct {
} }
type AnubisRule struct { type AnubisRule struct {
Expression *config.ExpressionOrList `yaml:"expression,omitempty" json:"expression,omitempty"` Expression *expression.Config `yaml:"expression,omitempty" json:"expression,omitempty"`
Challenge *config.ChallengeRules `yaml:"challenge,omitempty" json:"challenge,omitempty"` Challenge *config.ChallengeRules `yaml:"challenge,omitempty" json:"challenge,omitempty"`
Weight *config.Weight `yaml:"weight,omitempty" json:"weight,omitempty"` Weight *config.Weight `yaml:"weight,omitempty" json:"weight,omitempty"`
Name string `yaml:"name" json:"name"` Name string `yaml:"name" json:"name"`
Action string `yaml:"action" json:"action"` Action string `yaml:"action" json:"action"`
} }
func init() { func init() {
@ -224,11 +225,11 @@ func convertToAnubisRules(robotsRules []RobotsRule) []AnubisRule {
} }
if userAgent == "*" { if userAgent == "*" {
rule.Expression = &config.ExpressionOrList{ rule.Expression = &expression.Config{
All: []string{"true"}, // Always applies All: []string{"true"}, // Always applies
} }
} else { } else {
rule.Expression = &config.ExpressionOrList{ rule.Expression = &expression.Config{
All: []string{fmt.Sprintf("userAgent.contains(%q)", userAgent)}, All: []string{fmt.Sprintf("userAgent.contains(%q)", userAgent)},
} }
} }
@ -249,11 +250,11 @@ func convertToAnubisRules(robotsRules []RobotsRule) []AnubisRule {
rule.Name = fmt.Sprintf("%s-global-restriction-%d", *policyName, ruleCounter) rule.Name = fmt.Sprintf("%s-global-restriction-%d", *policyName, ruleCounter)
rule.Action = "WEIGH" rule.Action = "WEIGH"
rule.Weight = &config.Weight{Adjust: 20} // Increase difficulty significantly rule.Weight = &config.Weight{Adjust: 20} // Increase difficulty significantly
rule.Expression = &config.ExpressionOrList{ rule.Expression = &expression.Config{
All: []string{"true"}, // Always applies All: []string{"true"}, // Always applies
} }
} else { } else {
rule.Expression = &config.ExpressionOrList{ rule.Expression = &expression.Config{
All: []string{fmt.Sprintf("userAgent.contains(%q)", userAgent)}, All: []string{fmt.Sprintf("userAgent.contains(%q)", userAgent)},
} }
} }
@ -285,7 +286,7 @@ func convertToAnubisRules(robotsRules []RobotsRule) []AnubisRule {
pathCondition := buildPathCondition(disallow) pathCondition := buildPathCondition(disallow)
conditions = append(conditions, pathCondition) conditions = append(conditions, pathCondition)
rule.Expression = &config.ExpressionOrList{ rule.Expression = &expression.Config{
All: conditions, All: conditions,
} }

View File

@ -38,8 +38,7 @@ import (
_ "github.com/TecharoHQ/anubis/lib/checker/all" _ "github.com/TecharoHQ/anubis/lib/checker/all"
// challenge implementations // challenge implementations
_ "github.com/TecharoHQ/anubis/lib/challenge/metarefresh" _ "github.com/TecharoHQ/anubis/lib/challenge/all"
_ "github.com/TecharoHQ/anubis/lib/challenge/proofofwork"
) )
var ( var (

6
lib/challenge/all/all.go Normal file
View File

@ -0,0 +1,6 @@
package all
import (
_ "github.com/TecharoHQ/anubis/lib/challenge/metarefresh"
_ "github.com/TecharoHQ/anubis/lib/challenge/proofofwork"
)

View File

@ -2,6 +2,7 @@
package all package all
import ( import (
_ "github.com/TecharoHQ/anubis/lib/checker/expression"
_ "github.com/TecharoHQ/anubis/lib/checker/headerexists" _ "github.com/TecharoHQ/anubis/lib/checker/headerexists"
_ "github.com/TecharoHQ/anubis/lib/checker/headermatches" _ "github.com/TecharoHQ/anubis/lib/checker/headermatches"
_ "github.com/TecharoHQ/anubis/lib/checker/path" _ "github.com/TecharoHQ/anubis/lib/checker/path"

View File

@ -1,22 +1,22 @@
package policy package expression
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/TecharoHQ/anubis/internal" "github.com/TecharoHQ/anubis/internal"
"github.com/TecharoHQ/anubis/lib/policy/config"
"github.com/TecharoHQ/anubis/lib/policy/expressions" "github.com/TecharoHQ/anubis/lib/policy/expressions"
"github.com/google/cel-go/cel" "github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types" "github.com/google/cel-go/common/types"
) )
type CELChecker struct { type Checker struct {
program cel.Program program cel.Program
src string src string
hash string
} }
func NewCELChecker(cfg *config.ExpressionOrList) (*CELChecker, error) { func New(cfg *Config) (*Checker, error) {
env, err := expressions.BotEnvironment() env, err := expressions.BotEnvironment()
if err != nil { if err != nil {
return nil, err return nil, err
@ -27,17 +27,18 @@ func NewCELChecker(cfg *config.ExpressionOrList) (*CELChecker, error) {
return nil, fmt.Errorf("can't compile CEL program: %w", err) return nil, fmt.Errorf("can't compile CEL program: %w", err)
} }
return &CELChecker{ return &Checker{
src: cfg.String(), src: cfg.String(),
hash: internal.FastHash(cfg.String()),
program: program, program: program,
}, nil }, nil
} }
func (cc *CELChecker) Hash() string { func (cc *Checker) Hash() string {
return internal.FastHash(cc.src) return cc.hash
} }
func (cc *CELChecker) Check(r *http.Request) (bool, error) { func (cc *Checker) Check(r *http.Request) (bool, error) {
result, _, err := cc.program.ContextEval(r.Context(), &CELRequest{r}) result, _, err := cc.program.ContextEval(r.Context(), &CELRequest{r})
if err != nil { if err != nil {

View File

@ -1,4 +1,4 @@
package config package expression
import ( import (
"encoding/json" "encoding/json"
@ -9,18 +9,18 @@ import (
) )
var ( var (
ErrExpressionOrListMustBeStringOrObject = errors.New("config: this must be a string or an object") ErrExpressionOrListMustBeStringOrObject = errors.New("expression: this must be a string or an object")
ErrExpressionEmpty = errors.New("config: this expression is empty") ErrExpressionEmpty = errors.New("expression: this expression is empty")
ErrExpressionCantHaveBoth = errors.New("config: expression block can't contain multiple expression types") ErrExpressionCantHaveBoth = errors.New("expression: expression block can't contain multiple expression types")
) )
type ExpressionOrList struct { type Config struct {
Expression string `json:"-" yaml:"-"` Expression string `json:"-" yaml:"-"`
All []string `json:"all,omitempty" yaml:"all,omitempty"` All []string `json:"all,omitempty" yaml:"all,omitempty"`
Any []string `json:"any,omitempty" yaml:"any,omitempty"` Any []string `json:"any,omitempty" yaml:"any,omitempty"`
} }
func (eol ExpressionOrList) String() string { func (eol Config) String() string {
switch { switch {
case len(eol.Expression) != 0: case len(eol.Expression) != 0:
return eol.Expression return eol.Expression
@ -46,7 +46,7 @@ func (eol ExpressionOrList) String() string {
panic("this should not happen") panic("this should not happen")
} }
func (eol ExpressionOrList) Equal(rhs *ExpressionOrList) bool { func (eol Config) Equal(rhs *Config) bool {
if eol.Expression != rhs.Expression { if eol.Expression != rhs.Expression {
return false return false
} }
@ -62,7 +62,7 @@ func (eol ExpressionOrList) Equal(rhs *ExpressionOrList) bool {
return true return true
} }
func (eol *ExpressionOrList) MarshalYAML() (any, error) { func (eol *Config) MarshalYAML() (any, error) {
switch { switch {
case len(eol.All) == 1 && len(eol.Any) == 0: case len(eol.All) == 1 && len(eol.Any) == 0:
eol.Expression = eol.All[0] eol.Expression = eol.All[0]
@ -76,11 +76,11 @@ func (eol *ExpressionOrList) MarshalYAML() (any, error) {
return eol.Expression, nil return eol.Expression, nil
} }
type RawExpressionOrList ExpressionOrList type RawExpressionOrList Config
return RawExpressionOrList(*eol), nil return RawExpressionOrList(*eol), nil
} }
func (eol *ExpressionOrList) MarshalJSON() ([]byte, error) { func (eol *Config) MarshalJSON() ([]byte, error) {
switch { switch {
case len(eol.All) == 1 && len(eol.Any) == 0: case len(eol.All) == 1 && len(eol.Any) == 0:
eol.Expression = eol.All[0] eol.Expression = eol.All[0]
@ -94,17 +94,17 @@ func (eol *ExpressionOrList) MarshalJSON() ([]byte, error) {
return json.Marshal(string(eol.Expression)) return json.Marshal(string(eol.Expression))
} }
type RawExpressionOrList ExpressionOrList type RawExpressionOrList Config
val := RawExpressionOrList(*eol) val := RawExpressionOrList(*eol)
return json.Marshal(val) return json.Marshal(val)
} }
func (eol *ExpressionOrList) UnmarshalJSON(data []byte) error { func (eol *Config) UnmarshalJSON(data []byte) error {
switch string(data[0]) { switch string(data[0]) {
case `"`: // string case `"`: // string
return json.Unmarshal(data, &eol.Expression) return json.Unmarshal(data, &eol.Expression)
case "{": // object case "{": // object
type RawExpressionOrList ExpressionOrList type RawExpressionOrList Config
var val RawExpressionOrList var val RawExpressionOrList
if err := json.Unmarshal(data, &val); err != nil { if err := json.Unmarshal(data, &val); err != nil {
return err return err
@ -118,7 +118,7 @@ func (eol *ExpressionOrList) UnmarshalJSON(data []byte) error {
return ErrExpressionOrListMustBeStringOrObject return ErrExpressionOrListMustBeStringOrObject
} }
func (eol *ExpressionOrList) Valid() error { func (eol *Config) Valid() error {
if eol.Expression == "" && len(eol.All) == 0 && len(eol.Any) == 0 { if eol.Expression == "" && len(eol.All) == 0 && len(eol.Any) == 0 {
return ErrExpressionEmpty return ErrExpressionEmpty
} }

View File

@ -1,4 +1,4 @@
package config package expression
import ( import (
"bytes" "bytes"
@ -12,13 +12,13 @@ import (
func TestExpressionOrListMarshalJSON(t *testing.T) { func TestExpressionOrListMarshalJSON(t *testing.T) {
for _, tt := range []struct { for _, tt := range []struct {
name string name string
input *ExpressionOrList input *Config
output []byte output []byte
err error err error
}{ }{
{ {
name: "single expression", name: "single expression",
input: &ExpressionOrList{ input: &Config{
Expression: "true", Expression: "true",
}, },
output: []byte(`"true"`), output: []byte(`"true"`),
@ -26,7 +26,7 @@ func TestExpressionOrListMarshalJSON(t *testing.T) {
}, },
{ {
name: "all", name: "all",
input: &ExpressionOrList{ input: &Config{
All: []string{"true", "true"}, All: []string{"true", "true"},
}, },
output: []byte(`{"all":["true","true"]}`), output: []byte(`{"all":["true","true"]}`),
@ -34,7 +34,7 @@ func TestExpressionOrListMarshalJSON(t *testing.T) {
}, },
{ {
name: "all one", name: "all one",
input: &ExpressionOrList{ input: &Config{
All: []string{"true"}, All: []string{"true"},
}, },
output: []byte(`"true"`), output: []byte(`"true"`),
@ -42,7 +42,7 @@ func TestExpressionOrListMarshalJSON(t *testing.T) {
}, },
{ {
name: "any", name: "any",
input: &ExpressionOrList{ input: &Config{
Any: []string{"true", "false"}, Any: []string{"true", "false"},
}, },
output: []byte(`{"any":["true","false"]}`), output: []byte(`{"any":["true","false"]}`),
@ -50,7 +50,7 @@ func TestExpressionOrListMarshalJSON(t *testing.T) {
}, },
{ {
name: "any one", name: "any one",
input: &ExpressionOrList{ input: &Config{
Any: []string{"true"}, Any: []string{"true"},
}, },
output: []byte(`"true"`), output: []byte(`"true"`),
@ -75,13 +75,13 @@ func TestExpressionOrListMarshalJSON(t *testing.T) {
func TestExpressionOrListMarshalYAML(t *testing.T) { func TestExpressionOrListMarshalYAML(t *testing.T) {
for _, tt := range []struct { for _, tt := range []struct {
name string name string
input *ExpressionOrList input *Config
output []byte output []byte
err error err error
}{ }{
{ {
name: "single expression", name: "single expression",
input: &ExpressionOrList{ input: &Config{
Expression: "true", Expression: "true",
}, },
output: []byte(`"true"`), output: []byte(`"true"`),
@ -89,7 +89,7 @@ func TestExpressionOrListMarshalYAML(t *testing.T) {
}, },
{ {
name: "all", name: "all",
input: &ExpressionOrList{ input: &Config{
All: []string{"true", "true"}, All: []string{"true", "true"},
}, },
output: []byte(`all: output: []byte(`all:
@ -99,7 +99,7 @@ func TestExpressionOrListMarshalYAML(t *testing.T) {
}, },
{ {
name: "all one", name: "all one",
input: &ExpressionOrList{ input: &Config{
All: []string{"true"}, All: []string{"true"},
}, },
output: []byte(`"true"`), output: []byte(`"true"`),
@ -107,7 +107,7 @@ func TestExpressionOrListMarshalYAML(t *testing.T) {
}, },
{ {
name: "any", name: "any",
input: &ExpressionOrList{ input: &Config{
Any: []string{"true", "false"}, Any: []string{"true", "false"},
}, },
output: []byte(`any: output: []byte(`any:
@ -117,7 +117,7 @@ func TestExpressionOrListMarshalYAML(t *testing.T) {
}, },
{ {
name: "any one", name: "any one",
input: &ExpressionOrList{ input: &Config{
Any: []string{"true"}, Any: []string{"true"},
}, },
output: []byte(`"true"`), output: []byte(`"true"`),
@ -145,14 +145,14 @@ func TestExpressionOrListUnmarshalJSON(t *testing.T) {
for _, tt := range []struct { for _, tt := range []struct {
err error err error
validErr error validErr error
result *ExpressionOrList result *Config
name string name string
inp string inp string
}{ }{
{ {
name: "simple", name: "simple",
inp: `"\"User-Agent\" in headers"`, inp: `"\"User-Agent\" in headers"`,
result: &ExpressionOrList{ result: &Config{
Expression: `"User-Agent" in headers`, Expression: `"User-Agent" in headers`,
}, },
}, },
@ -161,7 +161,7 @@ func TestExpressionOrListUnmarshalJSON(t *testing.T) {
inp: `{ inp: `{
"all": ["\"User-Agent\" in headers"] "all": ["\"User-Agent\" in headers"]
}`, }`,
result: &ExpressionOrList{ result: &Config{
All: []string{ All: []string{
`"User-Agent" in headers`, `"User-Agent" in headers`,
}, },
@ -172,7 +172,7 @@ func TestExpressionOrListUnmarshalJSON(t *testing.T) {
inp: `{ inp: `{
"any": ["\"User-Agent\" in headers"] "any": ["\"User-Agent\" in headers"]
}`, }`,
result: &ExpressionOrList{ result: &Config{
Any: []string{ Any: []string{
`"User-Agent" in headers`, `"User-Agent" in headers`,
}, },
@ -195,7 +195,7 @@ func TestExpressionOrListUnmarshalJSON(t *testing.T) {
}, },
} { } {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
var eol ExpressionOrList var eol Config
if err := json.Unmarshal([]byte(tt.inp), &eol); !errors.Is(err, tt.err) { if err := json.Unmarshal([]byte(tt.inp), &eol); !errors.Is(err, tt.err) {
t.Errorf("wanted unmarshal error: %v but got: %v", tt.err, err) t.Errorf("wanted unmarshal error: %v but got: %v", tt.err, err)
@ -217,40 +217,40 @@ func TestExpressionOrListUnmarshalJSON(t *testing.T) {
func TestExpressionOrListString(t *testing.T) { func TestExpressionOrListString(t *testing.T) {
for _, tt := range []struct { for _, tt := range []struct {
name string name string
in ExpressionOrList in Config
out string out string
}{ }{
{ {
name: "single expression", name: "single expression",
in: ExpressionOrList{ in: Config{
Expression: "true", Expression: "true",
}, },
out: "true", out: "true",
}, },
{ {
name: "all", name: "all",
in: ExpressionOrList{ in: Config{
All: []string{"true"}, All: []string{"true"},
}, },
out: "( true )", out: "( true )",
}, },
{ {
name: "all with &&", name: "all with &&",
in: ExpressionOrList{ in: Config{
All: []string{"true", "true"}, All: []string{"true", "true"},
}, },
out: "( true ) && ( true )", out: "( true ) && ( true )",
}, },
{ {
name: "any", name: "any",
in: ExpressionOrList{ in: Config{
All: []string{"true"}, All: []string{"true"},
}, },
out: "( true )", out: "( true )",
}, },
{ {
name: "any with ||", name: "any with ||",
in: ExpressionOrList{ in: Config{
Any: []string{"true", "true"}, Any: []string{"true", "true"},
}, },
out: "( true ) || ( true )", out: "( true ) || ( true )",

View File

@ -0,0 +1,43 @@
package expression
import (
"context"
"encoding/json"
"errors"
"github.com/TecharoHQ/anubis/lib/checker"
)
func init() {
checker.Register("expression", Factory{})
}
type Factory struct{}
func (f Factory) Build(ctx context.Context, data json.RawMessage) (checker.Interface, error) {
var fc = &Config{}
if err := json.Unmarshal([]byte(data), fc); err != nil {
return nil, errors.Join(checker.ErrUnparseableConfig, err)
}
if err := fc.Valid(); err != nil {
return nil, errors.Join(checker.ErrInvalidConfig, err)
}
return New(fc)
}
func (f Factory) Valid(ctx context.Context, data json.RawMessage) error {
var fc = &Config{}
if err := json.Unmarshal([]byte(data), fc); err != nil {
return err
}
if err := fc.Valid(); err != nil {
return err
}
return nil
}

View File

@ -12,6 +12,7 @@ import (
"time" "time"
"github.com/TecharoHQ/anubis/data" "github.com/TecharoHQ/anubis/data"
"github.com/TecharoHQ/anubis/lib/checker/expression"
"github.com/TecharoHQ/anubis/lib/checker/headermatches" "github.com/TecharoHQ/anubis/lib/checker/headermatches"
"github.com/TecharoHQ/anubis/lib/checker/path" "github.com/TecharoHQ/anubis/lib/checker/path"
"github.com/TecharoHQ/anubis/lib/checker/remoteaddress" "github.com/TecharoHQ/anubis/lib/checker/remoteaddress"
@ -58,15 +59,15 @@ func (r Rule) Valid() error {
const DefaultAlgorithm = "fast" const DefaultAlgorithm = "fast"
type BotConfig struct { type BotConfig struct {
UserAgentRegex *string `json:"user_agent_regex,omitempty" yaml:"user_agent_regex,omitempty"` UserAgentRegex *string `json:"user_agent_regex,omitempty" yaml:"user_agent_regex,omitempty"`
PathRegex *string `json:"path_regex,omitempty" yaml:"path_regex,omitempty"` PathRegex *string `json:"path_regex,omitempty" yaml:"path_regex,omitempty"`
HeadersRegex map[string]string `json:"headers_regex,omitempty" yaml:"headers_regex,omitempty"` HeadersRegex map[string]string `json:"headers_regex,omitempty" yaml:"headers_regex,omitempty"`
Expression *ExpressionOrList `json:"expression,omitempty" yaml:"expression,omitempty"` Expression *expression.Config `json:"expression,omitempty" yaml:"expression,omitempty"`
Challenge *ChallengeRules `json:"challenge,omitempty" yaml:"challenge,omitempty"` Challenge *ChallengeRules `json:"challenge,omitempty" yaml:"challenge,omitempty"`
Weight *Weight `json:"weight,omitempty" yaml:"weight,omitempty"` Weight *Weight `json:"weight,omitempty" yaml:"weight,omitempty"`
Name string `json:"name" yaml:"name"` Name string `json:"name" yaml:"name"`
Action Rule `json:"action" yaml:"action"` Action Rule `json:"action" yaml:"action"`
RemoteAddr []string `json:"remote_addresses,omitempty" yaml:"remote_addresses,omitempty"` RemoteAddr []string `json:"remote_addresses,omitempty" yaml:"remote_addresses,omitempty"`
// Thoth features // Thoth features
GeoIP *GeoIP `json:"geoip,omitempty"` GeoIP *GeoIP `json:"geoip,omitempty"`

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"github.com/TecharoHQ/anubis" "github.com/TecharoHQ/anubis"
"github.com/TecharoHQ/anubis/lib/checker/expression"
) )
var ( var (
@ -17,7 +18,7 @@ var (
DefaultThresholds = []Threshold{ DefaultThresholds = []Threshold{
{ {
Name: "legacy-anubis-behaviour", Name: "legacy-anubis-behaviour",
Expression: &ExpressionOrList{ Expression: &expression.Config{
Expression: "weight > 0", Expression: "weight > 0",
}, },
Action: RuleChallenge, Action: RuleChallenge,
@ -31,10 +32,10 @@ var (
) )
type Threshold struct { type Threshold struct {
Name string `json:"name" yaml:"name"` Name string `json:"name" yaml:"name"`
Expression *ExpressionOrList `json:"expression" yaml:"expression"` Expression *expression.Config `json:"expression" yaml:"expression"`
Action Rule `json:"action" yaml:"action"` Action Rule `json:"action" yaml:"action"`
Challenge *ChallengeRules `json:"challenge" yaml:"challenge"` Challenge *ChallengeRules `json:"challenge" yaml:"challenge"`
} }
func (t Threshold) Valid() error { func (t Threshold) Valid() error {

View File

@ -6,6 +6,8 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/TecharoHQ/anubis/lib/checker/expression"
) )
func TestThresholdValid(t *testing.T) { func TestThresholdValid(t *testing.T) {
@ -18,7 +20,7 @@ func TestThresholdValid(t *testing.T) {
name: "basic allow", name: "basic allow",
input: &Threshold{ input: &Threshold{
Name: "basic-allow", Name: "basic-allow",
Expression: &ExpressionOrList{Expression: "true"}, Expression: &expression.Config{Expression: "true"},
Action: RuleAllow, Action: RuleAllow,
}, },
err: nil, err: nil,
@ -27,7 +29,7 @@ func TestThresholdValid(t *testing.T) {
name: "basic challenge", name: "basic challenge",
input: &Threshold{ input: &Threshold{
Name: "basic-challenge", Name: "basic-challenge",
Expression: &ExpressionOrList{Expression: "true"}, Expression: &expression.Config{Expression: "true"},
Action: RuleChallenge, Action: RuleChallenge,
Challenge: &ChallengeRules{ Challenge: &ChallengeRules{
Algorithm: "fast", Algorithm: "fast",
@ -50,9 +52,9 @@ func TestThresholdValid(t *testing.T) {
{ {
name: "invalid expression", name: "invalid expression",
input: &Threshold{ input: &Threshold{
Expression: &ExpressionOrList{}, Expression: &expression.Config{},
}, },
err: ErrExpressionEmpty, err: expression.ErrExpressionEmpty,
}, },
{ {
name: "invalid action", name: "invalid action",

View File

@ -9,6 +9,7 @@ import (
"sync/atomic" "sync/atomic"
"github.com/TecharoHQ/anubis/lib/checker" "github.com/TecharoHQ/anubis/lib/checker"
"github.com/TecharoHQ/anubis/lib/checker/expression"
"github.com/TecharoHQ/anubis/lib/checker/headermatches" "github.com/TecharoHQ/anubis/lib/checker/headermatches"
"github.com/TecharoHQ/anubis/lib/checker/path" "github.com/TecharoHQ/anubis/lib/checker/path"
"github.com/TecharoHQ/anubis/lib/checker/remoteaddress" "github.com/TecharoHQ/anubis/lib/checker/remoteaddress"
@ -115,7 +116,7 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
} }
if b.Expression != nil { if b.Expression != nil {
c, err := NewCELChecker(b.Expression) c, err := expression.New(b.Expression)
if err != nil { if err != nil {
validationErrs = append(validationErrs, fmt.Errorf("while processing rule %s expressions: %w", b.Name, err)) validationErrs = append(validationErrs, fmt.Errorf("while processing rule %s expressions: %w", b.Name, err))
} else { } else {