lib: move config to yaml (#307)
* lib: move config to yaml Signed-off-by: Xe Iaso <me@xeiaso.net> * web: run go generate Signed-off-by: Xe Iaso <me@xeiaso.net> * Add Haiku to known instances (#304) Signed-off-by: Asmodeus <46908100+AsmodeumX@users.noreply.github.com> * Add headers bot rule (#300) * Closes #291: add headers support to bot policy rules * Fix config validator * update docs for JSON -> YAML Signed-off-by: Xe Iaso <me@xeiaso.net> * docs: document http header based actions Signed-off-by: Xe Iaso <me@xeiaso.net> * lib: add missing test Signed-off-by: Xe Iaso <me@xeiaso.net> * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Xe Iaso <me@xeiaso.net> --------- Signed-off-by: Xe Iaso <me@xeiaso.net> Signed-off-by: Asmodeus <46908100+AsmodeumX@users.noreply.github.com> Co-authored-by: Asmodeus <46908100+AsmodeumX@users.noreply.github.com> Co-authored-by: Neur0toxine <pashok9825@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
022eb59ff3
commit
d40b5cfdab
22 changed files with 854 additions and 19 deletions
|
|
@ -90,8 +90,8 @@ func LoadPoliciesOrDefault(fname string, defaultDifficulty int) (*policy.ParsedC
|
|||
return nil, fmt.Errorf("can't parse policy file %s: %w", fname, err)
|
||||
}
|
||||
} else {
|
||||
fname = "(data)/botPolicies.json"
|
||||
fin, err = data.BotPolicies.Open("botPolicies.json")
|
||||
fname = "(data)/botPolicies.yaml"
|
||||
fin, err = data.BotPolicies.Open("botPolicies.yaml")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[unexpected] can't parse builtin policy file %s: %w", fname, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/TecharoHQ/anubis"
|
||||
"github.com/TecharoHQ/anubis/data"
|
||||
"github.com/TecharoHQ/anubis/internal"
|
||||
"github.com/TecharoHQ/anubis/lib/policy"
|
||||
)
|
||||
|
|
@ -15,7 +16,7 @@ import (
|
|||
func loadPolicies(t *testing.T, fname string) *policy.ParsedConfig {
|
||||
t.Helper()
|
||||
|
||||
anubisPolicy, err := LoadPoliciesOrDefault("", anubis.DefaultDifficulty)
|
||||
anubisPolicy, err := LoadPoliciesOrDefault(fname, anubis.DefaultDifficulty)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -55,6 +56,22 @@ func makeChallenge(t *testing.T, ts *httptest.Server) challenge {
|
|||
return chall
|
||||
}
|
||||
|
||||
func TestLoadPolicies(t *testing.T) {
|
||||
for _, fname := range []string{"botPolicies.json", "botPolicies.yaml"} {
|
||||
t.Run(fname, func(t *testing.T) {
|
||||
fin, err := data.BotPolicies.Open(fname)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer fin.Close()
|
||||
|
||||
if _, err := policy.ParseConfig(fin, fname, 4); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Regression test for CVE-2025-24369
|
||||
func TestCVE2025_24369(t *testing.T) {
|
||||
pol := loadPolicies(t, "")
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
)
|
||||
|
||||
func p[V any](v V) *V { return &v }
|
||||
|
|
@ -219,7 +220,7 @@ func TestConfigValidKnownGood(t *testing.T) {
|
|||
defer fin.Close()
|
||||
|
||||
var c Config
|
||||
if err := json.NewDecoder(fin).Decode(&c); err != nil {
|
||||
if err := yaml.NewYAMLToJSONDecoder(fin).Decode(&c); err != nil {
|
||||
t.Fatalf("can't decode file: %v", err)
|
||||
}
|
||||
|
||||
|
|
@ -246,7 +247,7 @@ func TestConfigValidBad(t *testing.T) {
|
|||
defer fin.Close()
|
||||
|
||||
var c Config
|
||||
if err := json.NewDecoder(fin).Decode(&c); err != nil {
|
||||
if err := yaml.NewYAMLToJSONDecoder(fin).Decode(&c); err != nil {
|
||||
t.Fatalf("can't decode file: %v", err)
|
||||
}
|
||||
|
||||
|
|
|
|||
7
lib/policy/config/testdata/bad/badregexes.yaml
vendored
Normal file
7
lib/policy/config/testdata/bad/badregexes.yaml
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
bots:
|
||||
- name: path-bad
|
||||
path_regex: "a(b"
|
||||
action: DENY
|
||||
- name: user-agent-bad
|
||||
user_agent_regex: "a(b"
|
||||
action: DENY
|
||||
1
lib/policy/config/testdata/bad/invalid.yaml
vendored
Normal file
1
lib/policy/config/testdata/bad/invalid.yaml
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
bots: []
|
||||
1
lib/policy/config/testdata/bad/nobots.yaml
vendored
Normal file
1
lib/policy/config/testdata/bad/nobots.yaml
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
6
lib/policy/config/testdata/good/allow_everyone.yaml
vendored
Normal file
6
lib/policy/config/testdata/good/allow_everyone.yaml
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
bots:
|
||||
- name: everyones-invited
|
||||
remote_addresses:
|
||||
- "0.0.0.0/0"
|
||||
- "::/0"
|
||||
action: ALLOW
|
||||
5
lib/policy/config/testdata/good/block_cf_workers.yaml
vendored
Normal file
5
lib/policy/config/testdata/good/block_cf_workers.yaml
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
bots:
|
||||
- name: cloudflare-workers
|
||||
headers_regex:
|
||||
CF-Worker: .*
|
||||
action: DENY
|
||||
4
lib/policy/config/testdata/good/challengemozilla.yaml
vendored
Normal file
4
lib/policy/config/testdata/good/challengemozilla.yaml
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
bots:
|
||||
- name: generic-browser
|
||||
user_agent_regex: Mozilla
|
||||
action: CHALLENGE
|
||||
4
lib/policy/config/testdata/good/everything_blocked.yaml
vendored
Normal file
4
lib/policy/config/testdata/good/everything_blocked.yaml
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
bots:
|
||||
- name: everything
|
||||
user_agent_regex: .*
|
||||
action: DENY
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package policy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -11,6 +10,7 @@ import (
|
|||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/yl2chen/cidranger"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
|
||||
"github.com/TecharoHQ/anubis/lib/policy/config"
|
||||
)
|
||||
|
|
@ -38,8 +38,8 @@ func NewParsedConfig(orig config.Config) *ParsedConfig {
|
|||
|
||||
func ParseConfig(fin io.Reader, fname string, defaultDifficulty int) (*ParsedConfig, error) {
|
||||
var c config.Config
|
||||
if err := json.NewDecoder(fin).Decode(&c); err != nil {
|
||||
return nil, fmt.Errorf("can't parse policy config JSON %s: %w", fname, err)
|
||||
if err := yaml.NewYAMLToJSONDecoder(fin).Decode(&c); err != nil {
|
||||
return nil, fmt.Errorf("can't parse policy config YAML %s: %w", fname, err)
|
||||
}
|
||||
|
||||
if err := c.Valid(); err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue