feat: writing logs to the filesystem with rotation support (#1299)

* refactor: move lib/policy/config to lib/config

Signed-off-by: Xe Iaso <me@xeiaso.net>

* refactor: don't set global loggers anymore

Ref #864

You were right @kotx, it is a bad idea to set the global logger
instance.

Signed-off-by: Xe Iaso <me@xeiaso.net>

* feat(config): add log sink support

Signed-off-by: Xe Iaso <me@xeiaso.net>

* chore: update spelling

Signed-off-by: Xe Iaso <me@xeiaso.net>

* chore(test): go mod tidy

Signed-off-by: Xe Iaso <me@xeiaso.net>

* chore: update spelling

Signed-off-by: Xe Iaso <me@xeiaso.net>

* docs(admin/policies): add logging block documentation

Signed-off-by: Xe Iaso <me@xeiaso.net>

* docs: update CHANGELOG

Signed-off-by: Xe Iaso <me@xeiaso.net>

* fix(cmd/anubis): revert this change, it's meant to be its own PR

Signed-off-by: Xe Iaso <me@xeiaso.net>

* chore: go mod tidy

Signed-off-by: Xe Iaso <me@xeiaso.net>

* test: add file logging smoke test

Assisted-by: GLM 4.6 via Claude Code
Signed-off-by: Xe Iaso <me@xeiaso.net>

* fix: don't expose the old log file time format string

Signed-off-by: Xe Iaso <me@xeiaso.net>

---------

Signed-off-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
Xe Iaso 2025-11-21 11:46:00 -05:00 committed by GitHub
parent a709a2b2da
commit f032d5d0ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
118 changed files with 789 additions and 65 deletions

21
lib/config/testdata/bad/badregexes.json vendored Normal file
View file

@ -0,0 +1,21 @@
{
"bots": [
{
"name": "path-bad",
"path_regex": "a(b",
"action": "DENY"
},
{
"name": "user-agent-bad",
"user_agent_regex": "a(b",
"action": "DENY"
},
{
"name": "headers-bad",
"headers": {
"Accept-Encoding": "a(b"
},
"action": "DENY"
}
]
}

View 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

View file

@ -0,0 +1,10 @@
{
"bots": [
{
"import": "(data)/bots/ai-catchall.yaml",
"name": "generic-browser",
"user_agent_regex": "Mozilla|Opera\n",
"action": "CHALLENGE"
}
]
}

View file

@ -0,0 +1,6 @@
bots:
- import: (data)/bots/ai-catchall.yaml
name: generic-browser
user_agent_regex: >
Mozilla|Opera
action: CHALLENGE

View file

@ -0,0 +1,7 @@
{
"bots": [
{
"import": "(data)/does-not-exist-fake-file.yaml"
}
]
}

View file

@ -0,0 +1,2 @@
bots:
- import: (data)/does-not-exist-fake-file.yaml

View file

@ -0,0 +1,11 @@
bots:
- name: simple-weight-adjust
action: WEIGH
user_agent_regex: Mozilla
weight:
adjust: 5
impressum:
page:
title: Test
body: <p>This is a test</p>

View file

@ -0,0 +1,10 @@
bots:
- name: simple-weight-adjust
action: WEIGH
user_agent_regex: Mozilla
weight:
adjust: 5
impressum:
footer: "Hi there these are WORDS on the INTERNET."
page: {}

5
lib/config/testdata/bad/invalid.json vendored Normal file
View file

@ -0,0 +1,5 @@
{
"bots": [
{}
]
}

1
lib/config/testdata/bad/invalid.yaml vendored Normal file
View file

@ -0,0 +1 @@
bots: []

View file

@ -0,0 +1,2 @@
logging:
sink: "nope"

View file

@ -0,0 +1,2 @@
logging:
sink: "file"

View file

@ -0,0 +1,17 @@
{
"bots": [
{
"name": "multiple-expression-types",
"action": "ALLOW",
"expression": {
"all": [
"userAgent.startsWith(\"git/\") || userAgent.contains(\"libgit\")",
"\"Git-Protocol\" in headers && headers[\"Git-Protocol\"] == \"version=2\"\n"
],
"any": [
"userAgent.startsWith(\"evilbot/\")"
]
}
}
]
}

View file

@ -0,0 +1,10 @@
bots:
- name: multiple-expression-types
action: ALLOW
expression:
all:
- userAgent.startsWith("git/") || userAgent.contains("libgit")
- >
"Git-Protocol" in headers && headers["Git-Protocol"] == "version=2"
any:
- userAgent.startsWith("evilbot/")

1
lib/config/testdata/bad/nobots.json vendored Normal file
View file

@ -0,0 +1 @@
{}

1
lib/config/testdata/bad/nobots.yaml vendored Normal file
View file

@ -0,0 +1 @@
{}

View file

@ -0,0 +1,12 @@
bots:
- name: everything
user_agent_regex: .*
action: DENY
openGraph:
enabled: true
considerHost: false
ttl: taco
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"

View file

@ -0,0 +1,21 @@
{
"bots": [
{
"name": "user-agent-ends-newline",
"user_agent_regex": "Mozilla\n",
"action": "CHALLENGE"
},
{
"name": "path-ends-newline",
"path_regex": "^/evil/.*$\n",
"action": "CHALLENGE"
},
{
"name": "headers-ends-newline",
"headers_regex": {
"CF-Worker": ".*\n"
},
"action": "CHALLENGE"
}
]
}

View file

@ -0,0 +1,17 @@
bots:
- name: user-agent-ends-newline
# Subtle bug: this ends with a newline
user_agent_regex: >
Mozilla
action: CHALLENGE
- name: path-ends-newline
# Subtle bug: this ends with a newline
path_regex: >
^/evil/.*$
action: CHALLENGE
- name: headers-ends-newline
# Subtle bug: this ends with a newline
headers_regex:
CF-Worker: >
.*
action: CHALLENGE

View file

@ -0,0 +1,13 @@
{
"bots": [
{
"name": "everything",
"user_agent_regex": ".*",
"action": "DENY"
}
],
"status_codes": {
"CHALLENGE": 0,
"DENY": 0
}
}

View file

@ -0,0 +1,8 @@
bots:
- name: everything
user_agent_regex: .*
action: DENY
status_codes:
CHALLENGE: 0
DENY: 0

View file

@ -0,0 +1,11 @@
bots:
- name: simple-weight-adjust
action: WEIGH
user_agent_regex: Mozilla
weight:
adjust: 5
thresholds:
- name: extreme-suspicion
expression: "true"
action: WEIGH

15
lib/config/testdata/bad/thresholds.yaml vendored Normal file
View file

@ -0,0 +1,15 @@
bots:
- name: simple-weight-adjust
action: WEIGH
user_agent_regex: Mozilla
weight:
adjust: 5
thresholds:
- name: extreme-suspicion
expression: "true"
action: WEIGH
challenge:
algorithm: fast
difficulty: 4
report_as: 4

View file

@ -0,0 +1 @@
}

View file

@ -0,0 +1 @@
}