diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index e45d2a22..461b486d 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -114,4 +114,36 @@ jobs: run: | chmod +x mvnw ./mvnw clean test - working-directory: backend \ No newline at end of file + working-directory: backend + + # ─── fail2ban Regex Regression ──────────────────────────────────────────────── + # The filter parses Caddy's JSON access log; a Caddy upgrade that reorders + # the JSON keys would silently break it (fail2ban-regex would return + # "0 matches", fail2ban would stop banning, no error surface). This job + # pins the contract against a deterministic sample line. + fail2ban-regex: + name: fail2ban Regex + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install fail2ban + run: | + sudo apt-get update + sudo apt-get install -y fail2ban + + - name: Matches /api/auth/login 401 + run: | + echo '{"level":"info","ts":1700000000.12,"logger":"http.log.access","msg":"handled request","request":{"remote_ip":"203.0.113.42","method":"POST","host":"archiv.raddatz.cloud","uri":"/api/auth/login"},"status":401}' > /tmp/sample.log + out=$(fail2ban-regex /tmp/sample.log infra/fail2ban/filter.d/familienarchiv-auth.conf) + echo "$out" + echo "$out" | grep -qE '1 matched' \ + || { echo "expected 1 match for /api/auth/login 401"; exit 1; } + + - name: Does not match /api/auth/login 200 + run: | + echo '{"level":"info","ts":1700000000.12,"logger":"http.log.access","msg":"handled request","request":{"remote_ip":"203.0.113.42","method":"POST","host":"archiv.raddatz.cloud","uri":"/api/auth/login"},"status":200}' > /tmp/sample.log + out=$(fail2ban-regex /tmp/sample.log infra/fail2ban/filter.d/familienarchiv-auth.conf) + echo "$out" + echo "$out" | grep -qE '0 matched' \ + || { echo "expected 0 matches for /api/auth/login 200"; exit 1; } \ No newline at end of file