feat(config): add metrics bind config to policy file with flag hack

Signed-off-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
Xe Iaso
2026-04-21 14:05:05 -04:00
parent 3a6e368179
commit 8af9845117
35 changed files with 246 additions and 8 deletions
+24
View File
@@ -2,6 +2,7 @@ package config
import (
"errors"
"flag"
"fmt"
"io"
"io/fs"
@@ -334,6 +335,7 @@ type fileConfig struct {
DNSBL bool `json:"dnsbl"`
DNSTTL DnsTTL `json:"dns_ttl"`
Logging *Logging `json:"logging"`
Metrics *Metrics `json:"metrics,omitempty"`
}
func (c *fileConfig) Valid() error {
@@ -375,6 +377,12 @@ func (c *fileConfig) Valid() error {
}
}
if c.Metrics != nil {
if err := c.Metrics.Valid(); err != nil {
errs = append(errs, err)
}
}
if len(errs) != 0 {
return fmt.Errorf("config is not valid:\n%w", errors.Join(errs...))
}
@@ -382,6 +390,16 @@ func (c *fileConfig) Valid() error {
return nil
}
func flagLookup(name string) string {
fl := flag.CommandLine.Lookup(name)
if fl == nil {
return ""
}
return fl.Value.String()
}
func Load(fin io.Reader, fname string) (*Config, error) {
c := &fileConfig{
StatusCodes: StatusCodes{
@@ -396,6 +414,10 @@ func Load(fin io.Reader, fname string) (*Config, error) {
Backend: "memory",
},
Logging: (Logging{}).Default(),
Metrics: &Metrics{
Bind: flagLookup("metrics-bind"),
Network: flagLookup("metrics-bind-network"),
},
}
if err := yaml.NewYAMLToJSONDecoder(fin).Decode(&c); err != nil {
@@ -417,6 +439,7 @@ func Load(fin io.Reader, fname string) (*Config, error) {
StatusCodes: c.StatusCodes,
Store: c.Store,
Logging: c.Logging,
Metrics: c.Metrics,
}
if c.OpenGraph.TimeToLive != "" {
@@ -508,6 +531,7 @@ type Config struct {
Logging *Logging
DNSBL bool
DNSTTL DnsTTL
Metrics *Metrics
}
func (c Config) Valid() error {
+39
View File
@@ -0,0 +1,39 @@
package config
import "errors"
var (
ErrInvalidMetricsConfig = errors.New("config: invalid metrics configuration")
ErrNoMetricsBind = errors.New("config.Metrics: must define bind")
ErrNoMetricsNetwork = errors.New("config.Metrics: must define network")
ErrInvalidMetricsNetwork = errors.New("config.Metrics: invalid metrics network")
)
type Metrics struct {
Bind string `json:"bind" yaml:"bind"`
Network string `json:"network" yaml:"network"`
}
func (m *Metrics) Valid() error {
var errs []error
if m.Bind == "" {
errs = append(errs, ErrNoMetricsBind)
}
if m.Network == "" {
errs = append(errs, ErrNoMetricsNetwork)
}
switch m.Network {
case "tcp", "tcp4", "tcp6", "unix": // https://pkg.go.dev/net#Listen
default:
errs = append(errs, ErrInvalidMetricsNetwork)
}
if len(errs) != 0 {
return errors.Join(ErrInvalidMetricsConfig, errors.Join(errs...))
}
return nil
}
+48
View File
@@ -0,0 +1,48 @@
package config
import (
"errors"
"testing"
)
func TestMetricsValid(t *testing.T) {
for _, tt := range []struct {
name string
input *Metrics
err error
}{
{
name: "basic TCP",
input: &Metrics{
Bind: ":9090",
Network: "tcp",
},
},
{
name: "no bind",
input: &Metrics{},
err: ErrNoMetricsBind,
},
{
name: "no network",
input: &Metrics{},
err: ErrNoMetricsNetwork,
},
{
name: "invalid network",
input: &Metrics{
Bind: ":9090",
Network: "taco",
},
err: ErrInvalidMetricsNetwork,
},
} {
t.Run(tt.name, func(t *testing.T) {
if err := tt.input.Valid(); !errors.Is(err, tt.err) {
t.Logf("wanted error: %v", tt.err)
t.Logf("got error: %v", err)
t.Error("validation failed")
}
})
}
}
+3
View File
@@ -0,0 +1,3 @@
metrics:
bind: ":9090"
network: taco
+5 -1
View File
@@ -5,5 +5,9 @@
"remote_addresses": ["0.0.0.0/0", "::/0"],
"action": "ALLOW"
}
]
],
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -4,3 +4,7 @@ bots:
- "0.0.0.0/0"
- "::/0"
action: ALLOW
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -8,5 +8,9 @@
"action": "DENY"
}
],
"dnsbl": false
"dnsbl": false,
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -3,3 +3,7 @@ bots:
headers_regex:
CF-Worker: .*
action: DENY
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -4,3 +4,7 @@ bots:
asns:
match:
- 13335 # Cloudflare
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -5,5 +5,9 @@
"user_agent_regex": "Mozilla",
"action": "CHALLENGE"
}
]
],
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -2,3 +2,7 @@ bots:
- name: generic-browser
user_agent_regex: Mozilla
action: CHALLENGE
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -6,3 +6,7 @@ bots:
- name: "test"
user_agent_regex: ".*"
action: "DENY"
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -6,3 +6,7 @@ bots:
- '"Accept" in headers'
- headers["Accept"].contains("text/html")
- randInt(1) == 0
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -6,5 +6,9 @@
"action": "DENY"
}
],
"dnsbl": false
"dnsbl": false,
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -2,3 +2,7 @@ bots:
- name: everything
user_agent_regex: .*
action: DENY
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -4,3 +4,7 @@ bots:
geoip:
countries:
- US
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -10,5 +10,9 @@
]
}
}
]
],
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -6,3 +6,7 @@ bots:
- userAgent.startsWith("git/") || userAgent.contains("libgit")
- >
"Git-Protocol" in headers && headers["Git-Protocol"] == "version=2"
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -3,5 +3,9 @@
{
"import": "./testdata/hack-test.json"
}
]
],
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -1,2 +1,6 @@
bots:
- import: ./testdata/hack-test.yaml
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -3,5 +3,9 @@
{
"import": "(data)/common/keep-internet-working.yaml"
}
]
],
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
@@ -1,2 +1,6 @@
bots:
- import: (data)/common/keep-internet-working.yaml
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -8,3 +8,7 @@ impressum:
page:
title: Test
body: <p>This is a test</p>
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -13,3 +13,7 @@ logs:
oldFileTimeFormat: 2006-01-02T15-04-05 # RFC 3339-ish
compress: true
useLocalTime: false # timezone for rotated files is UTC
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -5,3 +5,7 @@ bots:
logging:
sink: "stdio"
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -6,3 +6,7 @@ bots:
adjust: 5
thresholds: []
metrics:
bind: ":9090"
network: "tcp"
+5 -1
View File
@@ -75,5 +75,9 @@
"user_agent_regex": "Mozilla",
"action": "CHALLENGE"
}
]
],
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -10,3 +10,7 @@ openGraph:
default:
"og:title": "Xe's magic land of fun"
"og:description": "We're no strangers to love, you know the rules and so do I"
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -4,3 +4,7 @@ bots:
user_agent_regex: Mozilla
weight:
adjust: 5
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -9,5 +9,9 @@
"status_codes": {
"CHALLENGE": 200,
"DENY": 200
},
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -6,3 +6,7 @@ bots:
status_codes:
CHALLENGE: 200
DENY: 200
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -9,5 +9,9 @@
"status_codes": {
"CHALLENGE": 403,
"DENY": 403
},
"metrics": {
"bind": ":9090",
"network": "tcp"
}
}
+4
View File
@@ -6,3 +6,7 @@ bots:
status_codes:
CHALLENGE: 403
DENY: 403
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -33,3 +33,7 @@ thresholds:
challenge:
algorithm: fast
difficulty: 4
metrics:
bind: ":9090"
network: "tcp"
+4
View File
@@ -2,3 +2,7 @@ bots:
- name: weight
action: WEIGH
user_agent_regex: Mozilla
metrics:
bind: ":9090"
network: "tcp"