Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot] 4b6475caa4 build(deps): bump the github-actions group across 1 directory with 7 updates
Bumps the github-actions group with 7 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [actions/setup-node](https://github.com/actions/setup-node) | `6.3.0` | `6.4.0` |
| [docker/build-push-action](https://github.com/docker/build-push-action) | `7.0.0` | `7.1.0` |
| [actions-hub/kubectl](https://github.com/actions-hub/kubectl) | `1.35.3` | `1.36.0` |
| [actions/cache](https://github.com/actions/cache) | `5.0.4` | `5.0.5` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `7.0.0` | `7.0.1` |
| [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) | `8.0.0` | `8.1.0` |
| [github/codeql-action](https://github.com/github/codeql-action) | `4.35.1` | `4.35.2` |



Updates `actions/setup-node` from 6.3.0 to 6.4.0
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/53b83947a5a98c8d113130e565377fae1a50d02f...48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e)

Updates `docker/build-push-action` from 7.0.0 to 7.1.0
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/d08e5c354a6adb9ed34480a06d141179aa583294...bcafcacb16a39f128d818304e6c9c0c18556b85f)

Updates `actions-hub/kubectl` from 1.35.3 to 1.36.0
- [Release notes](https://github.com/actions-hub/kubectl/releases)
- [Commits](https://github.com/actions-hub/kubectl/compare/934aaa4354bbbc3d2176ae8d7cae92d515032dff...f8645c756533365a9fc1ae9aad8980b2a892d2c2)

Updates `actions/cache` from 5.0.4 to 5.0.5
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/668228422ae6a00e4ad889ee87cd7109ec5666a7...27d5ce7f107fe9357f9df03efb73ab90386fccae)

Updates `actions/upload-artifact` from 7.0.0 to 7.0.1
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/bbbca2ddaa5d8feaa63e36b76fdaad77386f024f...043fb46d1a93c77aae656e7c1c64a875d1fc6a0a)

Updates `astral-sh/setup-uv` from 8.0.0 to 8.1.0
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](https://github.com/astral-sh/setup-uv/compare/cec208311dfd045dd5311c1add060b2062131d57...08807647e7069bb48b6ef5acd8ec9567f424441b)

Updates `github/codeql-action` from 4.35.1 to 4.35.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/c10b8064de6f491fea524254123dbe5e09572f13...95e58e9a2cdfd71adc6e0353d5c52f41a045d225)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 6.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: docker/build-push-action
  dependency-version: 7.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: actions-hub/kubectl
  dependency-version: 1.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: actions/cache
  dependency-version: 5.0.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: astral-sh/setup-uv
  dependency-version: 8.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: github/codeql-action
  dependency-version: 4.35.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-27 00:42:23 +00:00
26 changed files with 66 additions and 253 deletions
-3
View File
@@ -120,7 +120,6 @@ fahedouch
fastcgi fastcgi
FCr FCr
fcrdns fcrdns
fcvg
fediverse fediverse
ffprobe ffprobe
fhdr fhdr
@@ -239,7 +238,6 @@ mnt
Mojeek Mojeek
mojeekbot mojeekbot
mozilla mozilla
mqvh
myclient myclient
mymaster mymaster
mypass mypass
@@ -389,7 +387,6 @@ vnd
VPS VPS
Vultr Vultr
WAIFU WAIFU
wcg
weblate weblate
webmaster webmaster
webpage webpage
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install -y build-essential sudo apt-get install -y build-essential
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: "24.11.0" node-version: "24.11.0"
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install -y build-essential sudo apt-get install -y build-essential
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: "24.11.0" node-version: "24.11.0"
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
run: | run: |
echo "IMAGE=ghcr.io/${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV echo "IMAGE=ghcr.io/${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: "24.11.0" node-version: "24.11.0"
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
+3 -3
View File
@@ -42,7 +42,7 @@ jobs:
- name: Build and push - name: Build and push
id: build id: build
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with: with:
context: ./docs context: ./docs
cache-to: type=gha cache-to: type=gha
@@ -53,14 +53,14 @@ jobs:
push: true push: true
- name: Apply k8s manifests to limsa lominsa - name: Apply k8s manifests to limsa lominsa
uses: actions-hub/kubectl@934aaa4354bbbc3d2176ae8d7cae92d515032dff # v1.35.3 uses: actions-hub/kubectl@f8645c756533365a9fc1ae9aad8980b2a892d2c2 # v1.36.0
env: env:
KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }} KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }}
with: with:
args: apply -k docs/manifest args: apply -k docs/manifest
- name: Apply k8s manifests to limsa lominsa - name: Apply k8s manifests to limsa lominsa
uses: actions-hub/kubectl@934aaa4354bbbc3d2176ae8d7cae92d515032dff # v1.35.3 uses: actions-hub/kubectl@f8645c756533365a9fc1ae9aad8980b2a892d2c2 # v1.36.0
env: env:
KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }} KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }}
with: with:
+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
- name: Build and push - name: Build and push
id: build id: build
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with: with:
context: ./docs context: ./docs
cache-to: type=gha cache-to: type=gha
+2 -2
View File
@@ -24,7 +24,7 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install -y build-essential sudo apt-get install -y build-essential
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: "24.11.0" node-version: "24.11.0"
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@@ -32,7 +32,7 @@ jobs:
go-version: "stable" go-version: "stable"
- name: Cache playwright binaries - name: Cache playwright binaries
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
id: playwright-cache id: playwright-cache
with: with:
path: | path: |
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install -y build-essential sudo apt-get install -y build-essential
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: "24.11.0" node-version: "24.11.0"
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@@ -26,7 +26,7 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install -y build-essential sudo apt-get install -y build-essential
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: "24.11.0" node-version: "24.11.0"
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@@ -41,7 +41,7 @@ jobs:
run: | run: |
go tool yeet go tool yeet
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: packages name: packages
path: var/* path: var/*
+2 -2
View File
@@ -34,7 +34,7 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: "24.11.0" node-version: "24.11.0"
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@@ -57,7 +57,7 @@ jobs:
run: echo "ARTIFACT_NAME=${{ matrix.test }}" | sed 's|/|-|g' >> $GITHUB_ENV run: echo "ARTIFACT_NAME=${{ matrix.test }}" | sed 's|/|-|g' >> $GITHUB_ENV
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
if: always() if: always()
with: with:
name: ${{ env.ARTIFACT_NAME }} name: ${{ env.ARTIFACT_NAME }}
+2 -2
View File
@@ -21,7 +21,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Install the latest version of uv - name: Install the latest version of uv
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
- name: Run zizmor 🌈 - name: Run zizmor 🌈
run: uvx zizmor --format sarif . > results.sarif run: uvx zizmor --format sarif . > results.sarif
@@ -29,7 +29,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload SARIF file - name: Upload SARIF file
uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with: with:
sarif_file: results.sarif sarif_file: results.sarif
category: zizmor category: zizmor
+1 -1
View File
@@ -259,7 +259,7 @@ func main() {
} }
lg.Info("loading policy file", "fname", *policyFname) lg.Info("loading policy file", "fname", *policyFname)
policy, err := libanubis.LoadPoliciesOrDefault(ctx, *policyFname, *challengeDifficulty, *slogLevel, strings.TrimSpace(*target) == "") policy, err := libanubis.LoadPoliciesOrDefault(ctx, *policyFname, *challengeDifficulty, *slogLevel)
if err != nil { if err != nil {
log.Fatalf("can't parse policy file: %v", err) log.Fatalf("can't parse policy file: %v", err)
} }
-3
View File
@@ -13,7 +13,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<!-- This changes the project to: --> <!-- This changes the project to: -->
- Patch [GHSA-6wcg-mqvh-fcvg](https://github.com/TecharoHQ/anubis/security/advisories/GHSA-6wcg-mqvh-fcvg) by containing subrequest logic to Anubis instances in subrequest mode.
- Move metrics server configuration to [the policy file](./admin/policies.mdx#metrics-server). - Move metrics server configuration to [the policy file](./admin/policies.mdx#metrics-server).
- Expose [pprof endpoints](https://pkg.go.dev/net/http/pprof) on the metrics listener to enable profiling Anubis in production. - Expose [pprof endpoints](https://pkg.go.dev/net/http/pprof) on the metrics listener to enable profiling Anubis in production.
- fix: prevent nil pointer panic in challenge validation when threshold rules match during PassChallenge (#1463) - fix: prevent nil pointer panic in challenge validation when threshold rules match during PassChallenge (#1463)
@@ -26,8 +25,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Enable [metrics serving via TLS](./admin/policies.mdx#tls), including [mutual TLS (mTLS)](./admin/policies.mdx#mtls). - Enable [metrics serving via TLS](./admin/policies.mdx#tls), including [mutual TLS (mTLS)](./admin/policies.mdx#mtls).
- Enable [HTTP basic auth](./admin/policies.mdx#http-basic-authentication) for the metrics server. - Enable [HTTP basic auth](./admin/policies.mdx#http-basic-authentication) for the metrics server.
- Fix a bug in the dataset poisoning maze that could allow denial of service [#1580](https://github.com/TecharoHQ/anubis/issues/1580). - Fix a bug in the dataset poisoning maze that could allow denial of service [#1580](https://github.com/TecharoHQ/anubis/issues/1580).
- Add config option to add ASN to logs/metrics.
- Log weight when issuing challenge
## v1.25.0: Necron ## v1.25.0: Necron
-1
View File
@@ -411,7 +411,6 @@ Anubis exposes the following logging settings in the policy file:
| `level` | [log level](#log-levels) | `info` | The logging level threshold. Any logs that are at or above this threshold will be drained to the sink. Any other logs will be discarded. | | `level` | [log level](#log-levels) | `info` | The logging level threshold. Any logs that are at or above this threshold will be drained to the sink. Any other logs will be discarded. |
| `sink` | string | `stdio`, `file` | The sink where the logs drain to as they are being recorded in Anubis. | | `sink` | string | `stdio`, `file` | The sink where the logs drain to as they are being recorded in Anubis. |
| `parameters` | object | | Parameters for the given logging sink. This will vary based on the logging sink of choice. See below for more information. | | `parameters` | object | | Parameters for the given logging sink. This will vary based on the logging sink of choice. See below for more information. |
| `asn` | bool | `true`, `false` | Add ASN information to logs/metrics. (Requires a Thoth client configured) |
Anubis supports the following logging sinks: Anubis supports the following logging sinks:
+1 -1
View File
@@ -595,7 +595,7 @@ func spawnAnubisWithOptions(t *testing.T, basePrefix string) string {
fmt.Fprintf(w, "<html><body><span id=anubis-test>%d</span></body></html>", time.Now().Unix()) fmt.Fprintf(w, "<html><body><span id=anubis-test>%d</span></body></html>", time.Now().Unix())
}) })
policy, err := libanubis.LoadPoliciesOrDefault(t.Context(), "", anubis.DefaultDifficulty, "info", false) policy, err := libanubis.LoadPoliciesOrDefault(t.Context(), "", anubis.DefaultDifficulty, "info")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
+15 -72
View File
@@ -11,7 +11,6 @@ import (
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"strconv"
"strings" "strings"
"time" "time"
@@ -33,7 +32,6 @@ import (
"github.com/TecharoHQ/anubis/lib/policy" "github.com/TecharoHQ/anubis/lib/policy"
"github.com/TecharoHQ/anubis/lib/policy/checker" "github.com/TecharoHQ/anubis/lib/policy/checker"
"github.com/TecharoHQ/anubis/lib/store" "github.com/TecharoHQ/anubis/lib/store"
iptoasnv1 "github.com/TecharoHQ/thoth-proto/gen/techaro/thoth/iptoasn/v1"
// challenge implementations // challenge implementations
_ "github.com/TecharoHQ/anubis/lib/challenge/metarefresh" _ "github.com/TecharoHQ/anubis/lib/challenge/metarefresh"
@@ -41,52 +39,31 @@ import (
_ "github.com/TecharoHQ/anubis/lib/challenge/proofofwork" _ "github.com/TecharoHQ/anubis/lib/challenge/proofofwork"
) )
type contextKey int
const asnContextKey contextKey = iota
type asnInfo struct {
ASN string
Description string
}
func asnFromContext(ctx context.Context) (string, string) {
if v, ok := ctx.Value(asnContextKey).(asnInfo); ok {
return v.ASN, v.Description
}
return "", ""
}
var ( var (
challengesIssued = promauto.NewCounterVec(prometheus.CounterOpts{ challengesIssued = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "anubis_challenges_issued", Name: "anubis_challenges_issued",
Help: "The total number of challenges issued", Help: "The total number of challenges issued",
}, []string{"method", "asn", "asn_description"}) }, []string{"method"})
challengesValidated = promauto.NewCounterVec(prometheus.CounterOpts{ challengesValidated = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "anubis_challenges_validated", Name: "anubis_challenges_validated",
Help: "The total number of challenges validated", Help: "The total number of challenges validated",
}, []string{"method", "asn", "asn_description"}) }, []string{"method"})
droneBLHits = promauto.NewCounterVec(prometheus.CounterOpts{ droneBLHits = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "anubis_dronebl_hits", Name: "anubis_dronebl_hits",
Help: "The total number of hits from DroneBL", Help: "The total number of hits from DroneBL",
}, []string{"status", "asn", "asn_description"}) }, []string{"status"})
failedValidations = promauto.NewCounterVec(prometheus.CounterOpts{ failedValidations = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "anubis_failed_validations", Name: "anubis_failed_validations",
Help: "The total number of failed validations", Help: "The total number of failed validations",
}, []string{"method", "asn", "asn_description"}) }, []string{"method"})
requestsProxied = promauto.NewCounterVec(prometheus.CounterOpts{ requestsProxied = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "anubis_proxied_requests_total", Name: "anubis_proxied_requests_total",
Help: "Number of requests proxied through Anubis to upstream targets", Help: "Number of requests proxied through Anubis to upstream targets",
}, []string{"host", "asn", "asn_description"}) }, []string{"host"})
requestsByASN = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "anubis_requests_by_asn_total",
Help: "Number of requests by ASN",
}, []string{"asn", "asn_description"})
) )
type Server struct { type Server struct {
@@ -101,28 +78,6 @@ type Server struct {
hs512Secret []byte hs512Secret []byte
} }
func (s *Server) getRequestLogger(r *http.Request) (*slog.Logger, *http.Request) {
lg := internal.GetRequestLogger(s.logger, r)
if s.policy.LogASN && s.policy.ThothClient != nil {
ctx, cancel := context.WithTimeout(r.Context(), 500*time.Millisecond)
defer cancel()
ip := r.Header.Get("X-Real-Ip")
if info, err := s.policy.ThothClient.IPToASN.Lookup(ctx, &iptoasnv1.LookupRequest{IpAddress: ip}); err == nil && info.GetAnnounced() {
asn := strconv.FormatUint(uint64(info.GetAsNumber()), 10)
lg = lg.With("asn", info.GetAsNumber(), "asn_description", info.GetDescription())
requestsByASN.WithLabelValues(asn, info.GetDescription()).Inc()
r = r.WithContext(context.WithValue(r.Context(), asnContextKey, asnInfo{
ASN: asn,
Description: info.GetDescription(),
}))
}
}
return lg, r
}
func (s *Server) getTokenKeyfunc() jwt.Keyfunc { func (s *Server) getTokenKeyfunc() jwt.Keyfunc {
// return ED25519 key if HS512 is not set // return ED25519 key if HS512 is not set
if len(s.hs512Secret) == 0 { if len(s.hs512Secret) == 0 {
@@ -186,7 +141,7 @@ func (s *Server) issueChallenge(ctx context.Context, r *http.Request, lg *slog.L
return nil, err return nil, err
} }
lg.Info("new challenge issued", "challenge", id.String(), "weight", cr.Weight) lg.Info("new challenge issued", "challenge", id.String())
return &chall, err return &chall, err
} }
@@ -238,7 +193,7 @@ func (s *Server) maybeReverseProxyOrPage(w http.ResponseWriter, r *http.Request)
} }
func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpStatusOnly bool) { func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpStatusOnly bool) {
lg, r := s.getRequestLogger(r) lg := internal.GetRequestLogger(s.logger, r)
if val, _ := s.store.Get(r.Context(), fmt.Sprintf("ogtags:allow:%s%s", r.Host, r.URL.String())); val != nil { if val, _ := s.store.Get(r.Context(), fmt.Sprintf("ogtags:allow:%s%s", r.Host, r.URL.String())); val != nil {
lg.Debug("serving opengraph tag asset") lg.Debug("serving opengraph tag asset")
@@ -263,10 +218,7 @@ func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpS
r.Header.Add("X-Anubis-Rule", cr.Name) r.Header.Add("X-Anubis-Rule", cr.Name)
r.Header.Add("X-Anubis-Action", string(cr.Rule)) r.Header.Add("X-Anubis-Action", string(cr.Rule))
lg = lg.With("check_result", cr) lg = lg.With("check_result", cr)
{ policy.Applications.WithLabelValues(cr.Name, string(cr.Rule)).Add(1)
asn, asnDesc := asnFromContext(r.Context())
policy.Applications.WithLabelValues(cr.Name, string(cr.Rule), asn, asnDesc).Add(1)
}
ip := r.Header.Get("X-Real-Ip") ip := r.Header.Get("X-Real-Ip")
@@ -396,8 +348,7 @@ func (s *Server) handleDNSBL(w http.ResponseWriter, r *http.Request, ip string,
lg.Error("can't look up ip in dnsbl", "err", err) lg.Error("can't look up ip in dnsbl", "err", err)
} }
db.Set(r.Context(), ip, resp, 24*time.Hour) db.Set(r.Context(), ip, resp, 24*time.Hour)
asn, asnDesc := asnFromContext(r.Context()) droneBLHits.WithLabelValues(resp.String()).Inc()
droneBLHits.WithLabelValues(resp.String(), asn, asnDesc).Inc()
} }
if resp != dnsbl.AllGood { if resp != dnsbl.AllGood {
@@ -415,7 +366,7 @@ func (s *Server) handleDNSBL(w http.ResponseWriter, r *http.Request, ip string,
} }
func (s *Server) MakeChallenge(w http.ResponseWriter, r *http.Request) { func (s *Server) MakeChallenge(w http.ResponseWriter, r *http.Request) {
lg, r := s.getRequestLogger(r) lg := internal.GetRequestLogger(s.logger, r)
localizer := localization.GetLocalizer(r) localizer := localization.GetLocalizer(r)
redir := r.FormValue("redir") redir := r.FormValue("redir")
@@ -484,14 +435,11 @@ func (s *Server) MakeChallenge(w http.ResponseWriter, r *http.Request) {
return return
} }
lg.Debug("made challenge", "challenge", chall, "rules", rule.Challenge, "cr", cr) lg.Debug("made challenge", "challenge", chall, "rules", rule.Challenge, "cr", cr)
{ challengesIssued.WithLabelValues("api").Inc()
asn, asnDesc := asnFromContext(r.Context())
challengesIssued.WithLabelValues("api", asn, asnDesc).Inc()
}
} }
func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) { func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) {
lg, r := s.getRequestLogger(r) lg := internal.GetRequestLogger(s.logger, r)
localizer := localization.GetLocalizer(r) localizer := localization.GetLocalizer(r)
redir := r.FormValue("redir") redir := r.FormValue("redir")
@@ -582,8 +530,7 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) {
} }
if err := impl.Validate(r, lg, in); err != nil { if err := impl.Validate(r, lg, in); err != nil {
asn, asnDesc := asnFromContext(r.Context()) failedValidations.WithLabelValues(rule.Challenge.Algorithm).Inc()
failedValidations.WithLabelValues(rule.Challenge.Algorithm, asn, asnDesc).Inc()
var cerr *challenge.Error var cerr *challenge.Error
s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host}) s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host})
lg.Debug("challenge validate call failed", "err", err) lg.Debug("challenge validate call failed", "err", err)
@@ -643,10 +590,7 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) {
lg.Debug("can't update information about challenge", "err", err) lg.Debug("can't update information about challenge", "err", err)
} }
{ challengesValidated.WithLabelValues(rule.Challenge.Algorithm).Inc()
asn, asnDesc := asnFromContext(r.Context())
challengesValidated.WithLabelValues(rule.Challenge.Algorithm, asn, asnDesc).Inc()
}
lg.Debug("challenge passed, redirecting to app") lg.Debug("challenge passed, redirecting to app")
http.Redirect(w, r, redir, http.StatusFound) http.Redirect(w, r, redir, http.StatusFound)
} }
@@ -685,8 +629,7 @@ func (s *Server) check(r *http.Request, lg *slog.Logger) (policy.CheckResult, *p
return cr("bot/"+b.Name, b.Action, weight), &b, nil return cr("bot/"+b.Name, b.Action, weight), &b, nil
case config.RuleWeigh: case config.RuleWeigh:
lg.Debug("adjusting weight", "name", b.Name, "delta", b.Weight.Adjust) lg.Debug("adjusting weight", "name", b.Name, "delta", b.Weight.Adjust)
asn, asnDesc := asnFromContext(r.Context()) policy.Applications.WithLabelValues("bot/"+b.Name, "WEIGH").Add(1)
policy.Applications.WithLabelValues("bot/"+b.Name, "WEIGH", asn, asnDesc).Add(1)
weight += b.Weight.Adjust weight += b.Weight.Adjust
} }
} }
+2 -2
View File
@@ -58,7 +58,7 @@ func loadPolicies(t *testing.T, fname string, difficulty int) *policy.ParsedConf
t.Logf("loading policy file: %s", fname) t.Logf("loading policy file: %s", fname)
anubisPolicy, err := LoadPoliciesOrDefault(ctx, fname, difficulty, "info", false) anubisPolicy, err := LoadPoliciesOrDefault(ctx, fname, difficulty, "info")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -250,7 +250,7 @@ func TestLoadPolicies(t *testing.T) {
} }
defer fin.Close() defer fin.Close()
if _, err := policy.ParseConfig(t.Context(), fin, fname, 4, "info", false); err != nil { if _, err := policy.ParseConfig(t.Context(), fin, fname, 4, "info"); err != nil {
t.Fatal(err) t.Fatal(err)
} }
}) })
+2 -2
View File
@@ -55,7 +55,7 @@ type Options struct {
DifficultyInJWT bool DifficultyInJWT bool
} }
func LoadPoliciesOrDefault(ctx context.Context, fname string, defaultDifficulty int, logLevel string, subrequestMode bool) (*policy.ParsedConfig, error) { func LoadPoliciesOrDefault(ctx context.Context, fname string, defaultDifficulty int, logLevel string) (*policy.ParsedConfig, error) {
var fin io.ReadCloser var fin io.ReadCloser
var err error var err error
@@ -79,7 +79,7 @@ func LoadPoliciesOrDefault(ctx context.Context, fname string, defaultDifficulty
} }
}(fin) }(fin)
anubisPolicy, err := policy.ParseConfig(ctx, fin, fname, defaultDifficulty, logLevel, subrequestMode) anubisPolicy, err := policy.ParseConfig(ctx, fin, fname, defaultDifficulty, logLevel)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't parse policy file %s: %w", fname, err) return nil, fmt.Errorf("can't parse policy file %s: %w", fname, err)
} }
-1
View File
@@ -17,7 +17,6 @@ type Logging struct {
Sink string `json:"sink"` // Logging sink, either "stdio" or "file" Sink string `json:"sink"` // Logging sink, either "stdio" or "file"
Level *slog.Level `json:"level"` // Log level, if set supersedes the level in flags Level *slog.Level `json:"level"` // Log level, if set supersedes the level in flags
Parameters *LoggingFileConfig `json:"parameters"` // Logging parameters, to be dynamic in the future Parameters *LoggingFileConfig `json:"parameters"` // Logging parameters, to be dynamic in the future
LogASN bool `json:"asn" yaml:"asn"`
} }
const ( const (
+4 -4
View File
@@ -12,7 +12,7 @@ import (
) )
func TestInvalidChallengeMethod(t *testing.T) { func TestInvalidChallengeMethod(t *testing.T) {
if _, err := LoadPoliciesOrDefault(t.Context(), "testdata/invalid-challenge-method.yaml", 4, "info", false); !errors.Is(err, policy.ErrChallengeRuleHasWrongAlgorithm) { if _, err := LoadPoliciesOrDefault(t.Context(), "testdata/invalid-challenge-method.yaml", 4, "info"); !errors.Is(err, policy.ErrChallengeRuleHasWrongAlgorithm) {
t.Fatalf("wanted error %v but got %v", policy.ErrChallengeRuleHasWrongAlgorithm, err) t.Fatalf("wanted error %v but got %v", policy.ErrChallengeRuleHasWrongAlgorithm, err)
} }
} }
@@ -25,7 +25,7 @@ func TestBadConfigs(t *testing.T) {
for _, st := range finfos { for _, st := range finfos {
t.Run(st.Name(), func(t *testing.T) { t.Run(st.Name(), func(t *testing.T) {
if _, err := LoadPoliciesOrDefault(t.Context(), filepath.Join("config", "testdata", "bad", st.Name()), anubis.DefaultDifficulty, "info", false); err == nil { if _, err := LoadPoliciesOrDefault(t.Context(), filepath.Join("config", "testdata", "bad", st.Name()), anubis.DefaultDifficulty, "info"); err == nil {
t.Fatal(err) t.Fatal(err)
} else { } else {
t.Log(err) t.Log(err)
@@ -44,13 +44,13 @@ func TestGoodConfigs(t *testing.T) {
t.Run(st.Name(), func(t *testing.T) { t.Run(st.Name(), func(t *testing.T) {
t.Run("with-thoth", func(t *testing.T) { t.Run("with-thoth", func(t *testing.T) {
ctx := thothmock.WithMockThoth(t) ctx := thothmock.WithMockThoth(t)
if _, err := LoadPoliciesOrDefault(ctx, filepath.Join("config", "testdata", "good", st.Name()), anubis.DefaultDifficulty, "info", false); err != nil { if _, err := LoadPoliciesOrDefault(ctx, filepath.Join("config", "testdata", "good", st.Name()), anubis.DefaultDifficulty, "info"); err != nil {
t.Fatal(err) t.Fatal(err)
} }
}) })
t.Run("without-thoth", func(t *testing.T) { t.Run("without-thoth", func(t *testing.T) {
if _, err := LoadPoliciesOrDefault(t.Context(), filepath.Join("config", "testdata", "good", st.Name()), anubis.DefaultDifficulty, "info", false); err != nil { if _, err := LoadPoliciesOrDefault(t.Context(), filepath.Join("config", "testdata", "good", st.Name()), anubis.DefaultDifficulty, "info"); err != nil {
t.Fatal(err) t.Fatal(err)
} }
}) })
+7 -11
View File
@@ -207,7 +207,7 @@ func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, cr policy.C
return return
} }
lg, r := s.getRequestLogger(r) lg := internal.GetRequestLogger(s.logger, r)
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") && randomChance(64) { if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") && randomChance(64) {
lg.Error("client was given a challenge but does not in fact support gzip compression") lg.Error("client was given a challenge but does not in fact support gzip compression")
@@ -215,10 +215,7 @@ func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, cr policy.C
return return
} }
{ challengesIssued.WithLabelValues("embedded").Add(1)
asn, asnDesc := asnFromContext(r.Context())
challengesIssued.WithLabelValues("embedded", asn, asnDesc).Add(1)
}
chall, err := s.issueChallenge(r.Context(), r, lg, cr, rule) chall, err := s.issueChallenge(r.Context(), r, lg, cr, rule)
if err != nil { if err != nil {
lg.Error("can't get challenge", "err", err) lg.Error("can't get challenge", "err", err)
@@ -309,14 +306,14 @@ func (s *Server) constructRedirectURL(r *http.Request) (string, error) {
case "http", "https": case "http", "https":
// allowed // allowed
default: default:
lg, _ := s.getRequestLogger(r) lg := internal.GetRequestLogger(s.logger, r)
lg.Warn("invalid protocol in X-Forwarded-Proto", "proto", proto) lg.Warn("invalid protocol in X-Forwarded-Proto", "proto", proto)
return "", errors.New(localizer.T("invalid_redirect")) return "", errors.New(localizer.T("invalid_redirect"))
} }
// Check if host is allowed in RedirectDomains (supports '*' via glob) // Check if host is allowed in RedirectDomains (supports '*' via glob)
if len(s.opts.RedirectDomains) > 0 && !matchRedirectDomain(s.opts.RedirectDomains, host) { if len(s.opts.RedirectDomains) > 0 && !matchRedirectDomain(s.opts.RedirectDomains, host) {
lg, _ := s.getRequestLogger(r) lg := internal.GetRequestLogger(s.logger, r)
lg.Debug("domain not allowed", "domain", host) lg.Debug("domain not allowed", "domain", host)
return "", errors.New(localizer.T("redirect_domain_not_allowed")) return "", errors.New(localizer.T("redirect_domain_not_allowed"))
} }
@@ -418,7 +415,7 @@ func (s *Server) ServeHTTPNext(w http.ResponseWriter, r *http.Request) {
case "", "http", "https": case "", "http", "https":
// allowed: empty scheme means relative URL // allowed: empty scheme means relative URL
default: default:
lg, _ := s.getRequestLogger(r) lg := internal.GetRequestLogger(s.logger, r)
lg.Warn("XSS attempt blocked, invalid redirect scheme", "scheme", urlParsed.Scheme, "redir", redir) lg.Warn("XSS attempt blocked, invalid redirect scheme", "scheme", urlParsed.Scheme, "redir", redir)
s.respondWithStatus(w, r, localizer.T("invalid_redirect"), "", http.StatusBadRequest) s.respondWithStatus(w, r, localizer.T("invalid_redirect"), "", http.StatusBadRequest)
return return
@@ -430,7 +427,7 @@ func (s *Server) ServeHTTPNext(w http.ResponseWriter, r *http.Request) {
hostMismatch := r.URL.Host != "" && urlParsed.Host != "" && urlParsed.Host != r.URL.Host hostMismatch := r.URL.Host != "" && urlParsed.Host != "" && urlParsed.Host != r.URL.Host
if hostNotAllowed || hostMismatch { if hostNotAllowed || hostMismatch {
lg, _ := s.getRequestLogger(r) lg := internal.GetRequestLogger(s.logger, r)
lg.Debug("domain not allowed", "domain", urlParsed.Host) lg.Debug("domain not allowed", "domain", urlParsed.Host)
s.respondWithStatus(w, r, localizer.T("redirect_domain_not_allowed"), makeCode(err), http.StatusBadRequest) s.respondWithStatus(w, r, localizer.T("redirect_domain_not_allowed"), makeCode(err), http.StatusBadRequest)
return return
@@ -445,8 +442,7 @@ func (s *Server) ServeHTTPNext(w http.ResponseWriter, r *http.Request) {
web.Base(localizer.T("you_are_not_a_bot"), web.StaticHappy(localizer), s.policy.Impressum, localizer), web.Base(localizer.T("you_are_not_a_bot"), web.StaticHappy(localizer), s.policy.Impressum, localizer),
).ServeHTTP(w, r) ).ServeHTTP(w, r)
} else { } else {
asn, asnDesc := asnFromContext(r.Context()) requestsProxied.WithLabelValues(r.Host).Inc()
requestsProxied.WithLabelValues(r.Host, asn, asnDesc).Inc()
r = s.stripBasePrefixFromRequest(r) r = s.stripBasePrefixFromRequest(r)
s.next.ServeHTTP(w, r) s.next.ServeHTTP(w, r)
} }
+1 -1
View File
@@ -64,7 +64,7 @@ func (s *Server) run(ctx context.Context, lg *slog.Logger) error {
ErrorLog: internal.GetFilteredHTTPLogger(), ErrorLog: internal.GetFilteredHTTPLogger(),
} }
ln, metricsURL, err := internal.SetupListener(s.Config.Network, s.Config.Bind, s.Config.SocketMode) ln, metricsURL, err := internal.SetupListener(s.Config.Bind, s.Config.Network, s.Config.SocketMode)
if err != nil { if err != nil {
return fmt.Errorf("can't setup listener: %w", err) return fmt.Errorf("can't setup listener: %w", err)
} }
+2 -5
View File
@@ -96,26 +96,23 @@ func (hmc *HeaderMatchesChecker) Hash() string {
type PathChecker struct { type PathChecker struct {
regexp *regexp.Regexp regexp *regexp.Regexp
hash string hash string
subRequestMode bool
} }
func NewPathChecker(rexStr string, subrequestMode bool) (checker.Impl, error) { func NewPathChecker(rexStr string) (checker.Impl, error) {
rex, err := regexp.Compile(strings.TrimSpace(rexStr)) rex, err := regexp.Compile(strings.TrimSpace(rexStr))
if err != nil { if err != nil {
return nil, fmt.Errorf("%w: regex %s failed parse: %w", ErrMisconfiguration, rexStr, err) return nil, fmt.Errorf("%w: regex %s failed parse: %w", ErrMisconfiguration, rexStr, err)
} }
return &PathChecker{rex, internal.FastHash(rexStr), subrequestMode}, nil return &PathChecker{rex, internal.FastHash(rexStr)}, nil
} }
func (pc *PathChecker) Check(r *http.Request) (bool, error) { func (pc *PathChecker) Check(r *http.Request) (bool, error) {
if pc.subRequestMode {
originalUrl := r.Header.Get("X-Original-URI") originalUrl := r.Header.Get("X-Original-URI")
if originalUrl != "" { if originalUrl != "" {
if pc.regexp.MatchString(originalUrl) { if pc.regexp.MatchString(originalUrl) {
return true, nil return true, nil
} }
} }
}
if pc.regexp.MatchString(r.URL.Path) { if pc.regexp.MatchString(r.URL.Path) {
return true, nil return true, nil
+2 -107
View File
@@ -272,8 +272,8 @@ func TestPathChecker_XOriginalURI(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
// Create the PathChecker in subrequest mode so X-Original-URI is honored. // Create the PathChecker
pc, err := NewPathChecker(tt.regex, true) pc, err := NewPathChecker(tt.regex)
if err != nil { if err != nil {
if !tt.expectError { if !tt.expectError {
t.Fatalf("NewPathChecker() unexpected error: %v", err) t.Fatalf("NewPathChecker() unexpected error: %v", err)
@@ -305,108 +305,3 @@ func TestPathChecker_XOriginalURI(t *testing.T) {
}) })
} }
} }
// TestPathChecker_GHSA_6wcg_mqvh_fcvg is a regression test for
// https://github.com/TecharoHQ/anubis/security/advisories/GHSA-6wcg-mqvh-fcvg.
//
// PR https://github.com/TecharoHQ/anubis/pull/1015 added the ability for
// reverse proxies using Anubis in subrequest auth mode to look at the path
// of a request as there are many rules in the wild that rely on checking
// the path. This is how access to things like robots.txt or anything in the
// .well-known directory is unaffected by Anubis.
//
// However this logic was also enabled for non-subrequest deployments of Anubis,
// meaning that a specially crafted request could include a /.well-known/
// path in it and then get around Anubis with little effort.
//
// This fix gates the logic behind a new plumbed variable named subrequestMode
// that only fires when Anubis is running in subrequest auth mode. This
// properly contains that workaround so that the logic does not fire in
// most deployments.
func TestPathChecker_GHSA_6wcg_mqvh_fcvg(t *testing.T) {
tests := []struct {
name string
regex string
urlPath string
xOriginalURI string
subRequestMode bool
want bool
}{
{
name: "default mode ignores spoofed X-Original-URI when real path matches",
regex: "^/admin/.*",
urlPath: "/admin/secret",
xOriginalURI: "/public/index",
subRequestMode: false,
want: true,
},
{
name: "default mode ignores spoofed X-Original-URI when real path does not match",
regex: "^/admin/.*",
urlPath: "/public/index",
xOriginalURI: "/admin/secret",
subRequestMode: false,
want: false,
},
{
name: "default mode without X-Original-URI matches real path",
regex: "^/admin/.*",
urlPath: "/admin/dashboard",
xOriginalURI: "",
subRequestMode: false,
want: true,
},
{
name: "subrequest mode honors X-Original-URI",
regex: "^/admin/.*",
urlPath: "/auth",
xOriginalURI: "/admin/secret",
subRequestMode: true,
want: true,
},
{
name: "subrequest mode falls back to URL.Path when X-Original-URI does not match",
regex: "^/admin/.*",
urlPath: "/admin/dashboard",
xOriginalURI: "/public/index",
subRequestMode: true,
want: true,
},
{
name: "subrequest mode with empty X-Original-URI uses URL.Path",
regex: "^/admin/.*",
urlPath: "/admin/dashboard",
xOriginalURI: "",
subRequestMode: true,
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pc, err := NewPathChecker(tt.regex, tt.subRequestMode)
if err != nil {
t.Fatalf("NewPathChecker(%q, %v) returned error: %v", tt.regex, tt.subRequestMode, err)
}
req, err := http.NewRequest(http.MethodGet, "http://example.com"+tt.urlPath, nil)
if err != nil {
t.Fatalf("http.NewRequest: %v", err)
}
if tt.xOriginalURI != "" {
req.Header.Set("X-Original-URI", tt.xOriginalURI)
}
got, err := pc.Check(req)
if err != nil {
t.Fatalf("Check() unexpected error: %v", err)
}
if got != tt.want {
t.Errorf("Check() = %v, want %v (subRequestMode=%v, urlPath=%q, X-Original-URI=%q)",
got, tt.want, tt.subRequestMode, tt.urlPath, tt.xOriginalURI)
}
})
}
}
+3 -13
View File
@@ -27,7 +27,7 @@ var (
Applications = promauto.NewCounterVec(prometheus.CounterOpts{ Applications = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "anubis_policy_results", Name: "anubis_policy_results",
Help: "The results of each policy rule", Help: "The results of each policy rule",
}, []string{"rule", "action", "asn", "asn_description"}) }, []string{"rule", "action"})
ErrChallengeRuleHasWrongAlgorithm = errors.New("config.Bot.ChallengeRules: algorithm is invalid") ErrChallengeRuleHasWrongAlgorithm = errors.New("config.Bot.ChallengeRules: algorithm is invalid")
warnedAboutThresholds = &atomic.Bool{} warnedAboutThresholds = &atomic.Bool{}
@@ -47,8 +47,6 @@ type ParsedConfig struct {
Dns *dns.Dns Dns *dns.Dns
Logger *slog.Logger Logger *slog.Logger
Metrics *config.Metrics Metrics *config.Metrics
ThothClient *thoth.Client
LogASN bool
} }
func newParsedConfig(orig *config.Config) *ParsedConfig { func newParsedConfig(orig *config.Config) *ParsedConfig {
@@ -60,7 +58,7 @@ func newParsedConfig(orig *config.Config) *ParsedConfig {
} }
} }
func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDifficulty int, logLevel string, subrequestMode bool) (*ParsedConfig, error) { func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDifficulty int, logLevel string) (*ParsedConfig, error) {
c, err := config.Load(fin, fname) c, err := config.Load(fin, fname)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -72,10 +70,6 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
result := newParsedConfig(c) result := newParsedConfig(c)
result.DefaultDifficulty = defaultDifficulty result.DefaultDifficulty = defaultDifficulty
result.LogASN = c.Logging.LogASN
if hasThothClient {
result.ThothClient = tc
}
if c.Logging.Level != nil { if c.Logging.Level != nil {
logLevel = c.Logging.Level.String() logLevel = c.Logging.Level.String()
@@ -100,10 +94,6 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
lg := result.Logger.With("at", "config-validate") lg := result.Logger.With("at", "config-validate")
if result.LogASN && !hasThothClient {
lg.Warn("logging.asn is enabled but no Thoth client is configured; ASN logging and metrics will be skipped. Please read https://anubis.techaro.lol/docs/admin/thoth for more information")
}
stFac, ok := store.Get(c.Store.Backend) stFac, ok := store.Get(c.Store.Backend)
switch ok { switch ok {
case true: case true:
@@ -152,7 +142,7 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
} }
if b.PathRegex != nil { if b.PathRegex != nil {
c, err := NewPathChecker(*b.PathRegex, subrequestMode) c, err := NewPathChecker(*b.PathRegex)
if err != nil { if err != nil {
validationErrs = append(validationErrs, fmt.Errorf("while processing rule %s path regex: %w", b.Name, err)) validationErrs = append(validationErrs, fmt.Errorf("while processing rule %s path regex: %w", b.Name, err))
} else { } else {
+4 -4
View File
@@ -19,7 +19,7 @@ func TestDefaultPolicyMustParse(t *testing.T) {
} }
defer fin.Close() defer fin.Close()
if _, err := ParseConfig(ctx, fin, "botPolicies.yaml", anubis.DefaultDifficulty, "info", false); err != nil { if _, err := ParseConfig(ctx, fin, "botPolicies.yaml", anubis.DefaultDifficulty, "info"); err != nil {
t.Fatalf("can't parse config: %v", err) t.Fatalf("can't parse config: %v", err)
} }
} }
@@ -41,7 +41,7 @@ func TestGoodConfigs(t *testing.T) {
defer fin.Close() defer fin.Close()
ctx := thothmock.WithMockThoth(t) ctx := thothmock.WithMockThoth(t)
if _, err := ParseConfig(ctx, fin, fin.Name(), anubis.DefaultDifficulty, "info", false); err != nil { if _, err := ParseConfig(ctx, fin, fin.Name(), anubis.DefaultDifficulty, "info"); err != nil {
t.Fatal(err) t.Fatal(err)
} }
}) })
@@ -53,7 +53,7 @@ func TestGoodConfigs(t *testing.T) {
} }
defer fin.Close() defer fin.Close()
if _, err := ParseConfig(t.Context(), fin, fin.Name(), anubis.DefaultDifficulty, "info", false); err != nil { if _, err := ParseConfig(t.Context(), fin, fin.Name(), anubis.DefaultDifficulty, "info"); err != nil {
t.Fatal(err) t.Fatal(err)
} }
}) })
@@ -77,7 +77,7 @@ func TestBadConfigs(t *testing.T) {
} }
defer fin.Close() defer fin.Close()
if _, err := ParseConfig(ctx, fin, fin.Name(), anubis.DefaultDifficulty, "info", false); err == nil { if _, err := ParseConfig(ctx, fin, fin.Name(), anubis.DefaultDifficulty, "info"); err == nil {
t.Fatal(err) t.Fatal(err)
} else { } else {
t.Log(err) t.Log(err)