273 Commits
Author SHA1 Message Date
1c98c70f14 ⬆️ renovate: Update all (#349)
Co-authored-by: Renovate Bot <22881669+maxlerebourg@users.noreply.github.com>
2026-07-05 19:56:15 +02:00
be13c49144 🐛 ci(renovate): fix OOM crash and stop using Mend's default gitAuthor (#347)
The 2026-07-03 runs surfaced two config problems:

- The grouped "renovate/all" branch made Renovate fetch and hold the
  changelog of every upgrade instance separately (Traefik v3.0.0->v3.7.6
  was fetched ~10x, once per compose file), which blew the default 4GB
  V8 heap: "FATAL ERROR: ... JavaScript heap out of memory" (exit 134),
  killing the run after the branch was pushed but before the PR was
  opened. Disable changelog fetching (release notes were truncated in
  the grouped PR body anyway) and raise the Node heap to 8GB as a
  safety net.

- No gitAuthor was set, so commits were authored as Mend's
  renovate@whitesourcesoftware.com, which GitHub flags "Unverified"
  (Vigilant Mode) and Renovate warns about on every run. Use the token
  owner's noreply address instead.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 19:36:44 +02:00
5a2998bc62 ⬆️ renovate: Update all (#345)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2026-07-03 10:19:28 +02:00
26ce12f7e3 🤖 chore: adopt Renovate for automated dependency updates (#330)
* ⬆️ bump example image versions to latest stable

Align every docker-compose and Helm-values example on the same set:
- Traefik       v3.0.0 / v3.5.0 → v3.7.1
- Crowdsec      v1.6.1-2 / v1.6.8 / latest → v1.7.8
- Plugin pin    v1.3.0 / v1.4.5 / v1.5.0 → v1.6.0

No env / volume changes needed: every Crowdsec example already mounts
/var/lib/crowdsec/data, so the v1.7 strict volume check is already
satisfied (CROWDSEC_BYPASS_DB_VOLUME_CHECK is only required when
running without persistence, as in the E2E suite).

* 🤖 chore: adopt Renovate (weekly, self-hosted) to replace manual version bumps

Automate the kind of bump this PR did by hand. Renovate covers what Dependabot
could not reach here:

- example docker-compose image tags (traefik / crowdsec) — native manager;
- the plugin self-pin (`experimental.plugins.bouncer.version=` in compose args
  and `version:` in the Traefik Helm values) — customManager, github-tags;
- the Crowdsec/Traefik image tags in the Helm values (no `repository` key, so
  matched by file) — customManager, docker;
- the pinned Traefik binary in the e2e mock suite (`TRAEFIK_VERSION`) —
  customManager, github-releases;
- go.mod + GitHub Actions — native managers (this is why we drop Dependabot:
  running both would open duplicate PRs).

Runs weekly via a self-hosted workflow (Mondays 04:00 UTC, plus manual
dispatch). Needs a RENOVATE_TOKEN secret (documented in the workflow). Renovate
PRs trigger the existing e2e CI, so a Traefik/Crowdsec bump is validated to
actually boot and bounce before merge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* 🔒 ci: pin Go to 1.22 (yaegi ceiling) and cap Renovate's Go updates

The plugin is interpreted by yaegi, bundled in Traefik. Even the latest Traefik
(v3.7.1) ships yaegi v0.16.1, which only supports Go 1.22 — so the plugin's real
ceiling is Go 1.22 on every current Traefik, regardless of the Go version
Traefik itself is built with.

- main.yml: build/test on Go 1.22 (was 1.23) so `go build`/`go test` reject
  newer stdlib early; yaegi v0.16.1 stays the required yaegi_test guard.
- renovate.json: cap the go.mod `go`/`toolchain` directive at `<1.23` so
  Renovate keeps deps/actions/toolchain current but never pushes the plugin
  past what yaegi supports. Raise the cap when Traefik ships a newer yaegi.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* 🐛 ci(renovate): stop ignoring examples/ and tests/ so custom managers run

config:recommended ships a default ignorePaths that excludes **/examples/**
and **/tests/** (and **/vendor/**). That silently disabled 4 of the 5 custom
managers and all example/helm coverage this PR adds — Renovate only saw the
root docker-compose, go.mod and workflows.

Override ignorePaths to keep only vendor/node_modules. Verified via
`renovate --platform=local --dry-run=full`: package files detected go from
7 -> 32, and every custom manager now extracts its dep (plugin self-pin
across 11 compose files, traefik/crowdsec helm tags, e2e TRAEFIK_VERSION pin).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

*  chore: drop one-time example version bumps, let Renovate own them

The manual version catch-up across the example docker-compose files and the
Helm values is now redundant: Renovate (this PR) covers all of them via its
native docker-compose/docker managers plus the custom managers for the plugin
self-pin and the e2e Traefik binary. Reverting these files to keep the PR a
clean "adopt Renovate" change; Renovate will open the bump PRs itself.

Note: examples/tls-auth uses crowdsecurity/crowdsec:latest again — Renovate
does not pin rolling tags, so that one stays floating unless pinned separately.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* 📌 examples(tls-auth): pin crowdsec to v1.6.8 instead of :latest

Rolling `latest` tags aren't reproducible and Renovate can't manage them.
v1.6.8 is already the crowdsec tag used in the root docker-compose files and,
unlike the `-2` build-suffixed tags, Renovate bumps it (→ v1.7.8).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* 📌 examples: normalize crowdsec v1.6.1-2 -> v1.6.8 so Renovate can manage it

Renovate's docker versioning won't advance a build-suffixed tag (v1.6.1-2) to
a clean release (v1.7.8), so those 8 examples would have stayed frozen. v1.6.8
is already used in the root compose files and Renovate bumps it. Also updated
the captcha README snippet to match its compose.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* 🍱 group all + no dashboard + branch prefix

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: maxlerebourg <maxlerebourg@gmail.com>
2026-07-03 09:22:14 +02:00
d32f271195 🐛 appsec: do not buffer unreadable (gRPC/HTTP2) request bodies (#332)
* 🐛 fix appsec silently 403-ing gRPC streams with unreadable body

A bidirectional gRPC stream is an HTTP/2 request with no Content-Length
whose body never reaches EOF. Since #321 removed the ContentLength guard,
appsecQuery buffered it with io.ReadAll, which blocked until the request
timed out and was turned into a 403 (issue #323). The backend was never
reached (OriginStatus:0).

Mirror the reference lua-cs-bouncer behaviour: detect an unreadable body
(ProtoMajor >= 2 && ContentLength < 0) and, instead of buffering it,
forward the request to Appsec with headers only. Add a new
CrowdsecAppsecDropUnreadableBody option (default false) that mirrors the
reference APPSEC_DROP_UNREADABLE_BODY: when true, such requests are
blocked outright instead of forwarded without their body.

Readable HTTP/1.1 bodies are still buffered and inspected, so the bypass
closed by #321 stays closed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* 🚨 appsec: satisfy linters (gocritic ifElseChain, misspell)

Rewrite the body-handling if/else chain in appsecQuery as a switch
(gocritic) and use US spelling "behavior" (misspell).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* 🔇 appsec: drop redundant unreadable-body debug log

Address review on #332: the caller (handleNextServeHTTP) already logs the
returned error with the request IP, so the inner Debug line duplicated it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* 🍱 increase gocyclo

* 🍱 fix lint

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: maxlerebourg <maxlerebourg@gmail.com>
v1.7.0-alpha
2026-07-01 12:44:58 +02:00
1c1672c856 Consider 502, 503 and 504 as unavaible for appsec (#338)
* Consider 502, 503 and 504 as unavaible for appsec

Fixes #337

*  add test and the function isReverseProxyError

---------

Co-authored-by: maxlerebourg <maxlerebourg@gmail.com>
2026-06-30 22:03:06 +02:00
21895fbb9d ⬆️ Bump actions/cache from 5 to 6 (#344)
Bumps [actions/cache](https://github.com/actions/cache) from 5 to 6.
- [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/v5...v6)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-29 10:11:22 +02:00
7c73cb38dd Add parameter to configure the ban page Content-Type response header (#325)
* Add parameter to configure Ban Response Content-Type

* Add testing for new BanResponseContentType parameter

* Ensure there is a fallback to default Content-Type is user provided empty value

* Set Content-Type even if banTemplate is nil

* Add more edge cases for testing ban response Content-Type

* Add CR/LF validation for BanResponseContentType

* Add CaptchaResponseContentType to allow separate Content-Type configuration for captcha responses

* Add testing for new CaptchaResponseContentType

* Update README

* Split nil and CR/LF response Content-Type value validation into separate function

* Throw error instead of setting the default in case of empty parameter declaration

* Update testing accordingly

*  remove HTML from var name, add tests and infer content type from filePath

* 🍱 fix lint ?

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint + naming

* 🍱 fix lint

* 🍱 fuck lint

---------

Co-authored-by: maxlerebourg <maxlerebourg@gmail.com>
2026-06-28 22:30:48 +02:00
f4dcd933c8 🐛 fall back to system trust store when no custom TLS CA is set (#331)
* 🐛 fall back to system trust store when no custom TLS CA is set

Closes #327.

Until now, configuring `crowdsecLapiScheme=https` forced the operator
to either provide `crowdsecLapiTLSCertificateAuthority` (a custom CA)
or set `crowdsecLapiTLSInsecureVerify=true` — there was no way to rely
on the host's system trust store, which is the expected setup when the
LAPI sits behind a reverse proxy with a publicly trusted (e.g. Let's
Encrypt) certificate.

Two contributing bugs:
  - `validateParamsTLS` rejected an empty CA up-front.
  - `getTLSConfig` always allocated an empty `tls.Config.RootCAs`,
    which silently disabled the standard library's fall-back to
    `x509.SystemCertPool()`.

Fix: drop the validation error for the empty-CA case and only allocate
`RootCAs` when a custom CA is actually provided. Same change applies
symmetrically to the AppSec path since the helper is shared.

Add unit tests covering the four meaningful states (HTTP, HTTPS with
system CA, HTTPS with custom CA, HTTPS with insecure verify) plus the
malformed-PEM rejection. README updated to document the system trust
store as an explicit option for both LAPI and AppSec HTTPS.

* 📝 fix gofmt alignment in TLS test struct

*  update existing test: https without CA is now accepted

* ♻️ tests: hoist shared validPEM to package level, rename cfgGarbage

Address review on #331:
- the self-signed validPEM block was duplicated in two test funcs; declare it
  once at package level and drop both local copies.
- rename cfgGarbage -> cfgInvalidCA (and its test case) for a descriptive name.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

*  e2e mock: add tls-system-ca scenario (HTTPS LAPI via system trust store)

CI regression coverage for this PR: with no custom CA configured, the bouncer
must fall back to the OS/system trust store for an HTTPS LAPI.

In the binary suite the "system trust store" is whatever Go's
x509.SystemCertPool() reads, which honours SSL_CERT_FILE on the Traefik process.
The scenario mints a throwaway CA, serves the mock LAPI over HTTPS with a cert
signed by it, and runs the stack twice:
  - positive: SSL_CERT_FILE = our CA       -> LAPI trusted    -> 200
  - negative: SSL_CERT_FILE = empty bundle  -> not trusted     -> 403 (fail-closed)
The negative run proves the patch still VERIFIES (not an insecure skip).

- mocklapi: optional --lapi-tls-cert/--lapi-tls-key to serve the LAPI over TLS.
- common.sh: opt-in LAPI_TLS_CERT/KEY (HTTPS mock) and TRAEFIK_SSL_CERT_FILE
  (inject SSL_CERT_FILE into Traefik); both default-empty, other scenarios
  unaffected.
- adds openssl as a scenario-only dependency.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 09:27:32 +02:00
67b33dcf13 ⬆️ Bump actions/checkout from 6 to 7 (#341)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 08:56:27 +02:00
661a89ea9c ⬆️ Bump actions/upload-artifact from 4 to 7 (#336)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-15 08:49:57 +02:00
14b9c47ab2 tests: CI end-to-end suite — Traefik binary + mock LAPI (#329)
*  tests: end-to-end suite scaffold + stream-mode scenario

Add tests/e2e/ structure with shared bash helpers and the first
scenario (stream-mode): spin up real Traefik + Crowdsec via docker
compose, mount the repo as a local plugin, add a ban via cscli, verify
the bouncer blocks the matching X-Forwarded-For, then delete the
decision and verify pass-through.

Adds .github/workflows/e2e.yml with one matrix job per scenario
(stream-mode for now), and Makefile targets `e2e` and `e2e_<scenario>`
for local runs.

Refs #328

*  tests: revert to docker provider + bump versions + add 6 scenarios

Reverts the stream-mode scenario to the Traefik docker provider (the
file provider was a workaround for a local docker daemon API version
mismatch, irrelevant in CI). Bumps Traefik to v3.7.1 and Crowdsec to
v1.7.8 across all scenarios.

Adds six new E2E scenarios:
- live-mode: short defaultDecisionSeconds, verifies cache-then-recheck
- none-mode: verifies LAPI is queried per request, no caching
- trusted-ips: clientTrustedIPs bypass even when the trusted IP is banned
- custom-ban-page: BanHTMLFilePath body + Content-Type validation
- captcha: captcha decision serves the captcha page (HTTP 200)
- appsec: SQLi probe blocked by appsec-virtual-patching

Each scenario uses an isolated compose project, mounts the repo as a
local plugin, and asserts behavior via curl. Workflow matrix and
Makefile E2E_SCENARIOS updated accordingly.

Refs #328

* 🐛 tests: set CROWDSEC_BYPASS_DB_VOLUME_CHECK for v1.7+

Crowdsec v1.7 refuses to start without an explicit volume mount on
/var/lib/crowdsec/data (or the bypass env var). For E2E we don't need
db persistence — set the bypass everywhere so the stack boots.

* 🐛 tests: appsec scenario uses OWASP CRS inband collection

appsec-virtual-patching only ships CVE-specific rules, not generic
SQLi. Switch to crowdsecurity/appsec-crs-inband (the blocking OWASP
Core Rule Set) and use a SQLi probe that CRS paranoia level 1
matches (rule 942100/942130).

* ♻️ tests: run e2e suite in a single sequential job

The matrix spawned one runner per scenario, so the Traefik, Crowdsec and
whoami images were pulled — and Crowdsec booted — once per scenario. Run
the whole suite in a single job with `make -k e2e` instead: Docker caches
the images locally so they are pulled only once, and `-k` keeps the
remaining scenarios running after a failure (make still exits non-zero).

Scenarios already share the canonical `crowdsec` container name and the
8000 port, so they were meant to run sequentially anyway.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

*  tests: add binary e2e suite (Traefik binary + Go mock LAPI), run it in CI

Add a second e2e suite that runs Traefik as a downloaded binary with the
plugin loaded from source, and replaces Crowdsec with a small stdlib-only Go
LAPI mock driven via /admin endpoints. No Docker, no real Crowdsec.

The mock lives in its own nested Go module (tests/e2e/mock/mocklapi) so it
stays out of the plugin module's build, lint, test and vendor.

This suite validates the plugin's own behaviour (live/none/stream modes,
caching, trusted-IP bypass, ban/captcha rendering). Crowdsec and AppSec
correctness are out of scope on purpose — they are validated upstream by the
maintainer — so the AppSec scenario is intentionally absent and the README
says so to avoid misfiled issues.

CI now runs this suite only (`make e2e_mock`), since it needs neither Docker
nor a real Crowdsec. The Docker suite (tests/e2e/scenarios) is kept for local
debugging (`make e2e`).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* 🔧 e2e mock: address review — clarify backend flag, move ignore to root

- Document the --backend-addr flag: it is the stub upstream service Traefik
  proxies allowed requests to (the traefik/whoami equivalent), not AppSec.
- Move the .cache/ ignore rule from the per-suite .gitignore to the repo root
  .gitignore, and make the wording accurate: the cache persists across local
  runs but is recreated on every (fresh-runner) CI run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ♻️ tests: move local Docker e2e suite to its own PR (#333)

Per review, split the e2e work so each PR is focused. CI runs the binary +
mock-LAPI suite (this PR); the heavier, local-only Docker suite (real Traefik
+ Crowdsec, incl. appsec) now lives in #333.

Removes tests/e2e/scenarios, tests/e2e/lib and the Docker-suite README, and
drops the `e2e` Make target here (kept in #333). The binary/mock suite and its
`e2e_mock` target are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* 🔥 e2e mock: simplify the Crowdsec LAPI mock

Per review, trim the mock to the minimum the plugin actually exercises:

- Drop the stream delta bookkeeping (startup flag + "already streamed" set).
  The plugin re-Sets/Deletes its cache on every poll, so reporting the whole
  active set as "new" and removed ones as "deleted" is enough.
- Shrink the Decision struct to the three fields the plugin reads
  (value/type/duration); drop id/origin/scope/scenario and the id counter.
- Drop API-key auth and the /admin/reset endpoint — no scenario exercises
  either. Also drop the now-unused lapi_reset helper.
- Replace the store struct + methods with two package-level maps + a mutex.

mocklapi/main.go: 234 -> 118 lines. All six scenarios still pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

*  e2e mock: replace fixed sleeps with condition polling

The `sleep 4` / `sleep 3` after a decision change were magic numbers tied to
updateIntervalSeconds / defaultDecisionSeconds. Replace them with waits on the
actual condition:

- After a ban/unban, poll with wait_for_status until the expected code shows up
  (stream propagation / live-mode cache TTL).
- Captcha keeps status 200 before and after, so gate on the body marker via a
  new wait_for_body_contains helper.
- Control assertions that must NOT change stay immediate (assert_status).

Self-documenting, faster on the happy path (returns on the first poll that
sees the change), and more robust under slow CI. No fixed sleeps remain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ⬆️ e2e mock: bump module go directive to 1.23

Align the mock module with the project's Go version (CI uses 1.23). Part of
standardising the whole project on Go 1.23; the plugin module is bumped
separately.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ⬇️ e2e mock: keep Go floor at 1.22 (yaegi ceiling)

Revert the mock module back to go 1.22 and make the e2e workflow read the Go
version from go.mod (go-version-file) instead of hardcoding 1.23.

Rationale: the plugin is interpreted by yaegi, and even Traefik v3.7.1 ships
yaegi v0.16.1 (Go 1.22), so the project stays on 1.22. The earlier bump to 1.23
is dropped (plugin go.mod stays 1.22, see #330 for the Renovate cap + CI pin).
Mock + all six scenarios verified on Go 1.22.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

*  e2e mock: add AppSec scenario + custom remediation header assertion

Address review feedback on the binary e2e suite:

- mocklapi: add an AppSec WAF stand-in (--appsec-addr) that blocks any URI
  containing "rpc2" — the exact probe from examples/appsec-enabled — and allows
  the rest. Lets the suite exercise the plugin's AppSec wiring (header
  forwarding + allow/block enforcement) without the real CRS engine.
- new scenarios/appsec: benign request passes, /foo/rpc2 is 403.
- custom-ban-page: assert the banned response carries the custom remediation
  header (remediationHeadersCustomName), per review.
- README: drop the "don't open issues / AppSec intentionally absent" framing;
  describe what the suite actually covers, including AppSec wiring.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 18:49:18 +02:00
f5d580578c 📝 docs: fix Mermaid diagrams not rendering (lowercase destroy keyword) (#335)
The sequence diagrams used the keyword `Destroy` (capital D). Mermaid
keywords are case-sensitive, so the invalid token aborted parsing and
every diagram failed to render on GitHub.

Lowercase all `Destroy` -> `destroy` in README.md and the captcha
example README. The `create` keyword was already correct, and each
create/destroy is properly paired with an adjacent message.

Fixes #270

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 18:40:56 +02:00
71d845faae ️ Do not block middleware startup due to stream intialization (#281)
* 🍱 not block on stream startup

* 🍱 fix

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 update readme

* 📚 clarify StreamStartupBlock warning in README

Make the fail-open implication of StreamStartupBlock=false explicit:
banned IPs are allowed through until the first stream sync completes.

* 🐛 clear isCrowdsecStreamStartup on alreadyUpdated path

When cacheTimeoutKey is already set (another instance/process has
populated the stream cache within the update window), the early return
in handleStreamCache used to leave isCrowdsecStreamStartup at true,
causing this instance to keep sending startup=true on subsequent ticks.
Flip the flag in the early-return path so startup is correctly tracked
across multi-instance deployments sharing a cache.

---------

Co-authored-by: mhx <mathieu@hanotaux.fr>
2026-06-06 11:07:18 +02:00
maxlerebourgandGitHub 0d8fd2a7a9 🍱 Header.Add -> Set, log Info -> Debug, version bump (#324) 2026-05-05 15:51:35 +02:00
maxlerebourgandGitHub 1f6a8991c8 🐛 fix appsec bypass with invalid content-length (#321) v1.6.0 2026-04-27 08:33:11 +02:00
7f776fe0fe 🔊 Improve Logging: move to slog and add trace level (#276)
* Add Warn and Trace loglevels

* Move to slog

* fixes

* missing test file

* Fix tests

* Add wrapper with trace

* fix

* fix lint

* LINT

* LINT

* 🍱 Use only 4 level of logs

* fix after merge

* 🍱 fix lint

* 🍱 fix lint + remove trace logger from tests

* 🍱 fix tests

* 🍱 fix lint

* 🍱 try to fix test

* 🍱 Fix tests

* 🍱 fix README + adjust logs

---------

Co-authored-by: maxlerebourg <maxlerebourg@gmail.com>
v1.6.0-alpha
2026-03-13 18:03:12 +01:00
cliffjaoandGitHub e54c1d5c4f Update README.md to show simplified dynamic configuration (#313)
* Update README.md to show simplified dynamic configuration

The full dynamic configuration can be pretty intimidating as a starting point. Provide a simplified dynamic configuration to get up & running quickly.

* Update README.md

Set enabled to true
2026-02-21 19:45:02 +01:00
c2bbc4dac5 cicd: Automate proper version tagging in the bouncer.go that is reported to Crowdsec LAPI (#314)
* cicd(versioning): Automate proper version tagging in the bouncer.go that is reported to Crowdsec LAPI

* cicd(versioning): Move pluginVersion to it's own file

* Disablie lint check for no global variables

* Remove trailing new-line

* Update pluginVersion declaration style

* 🍱 Simplify for tests

Removed the verification step after updating the version and modified the commit message to include an emoji.

---------

Co-authored-by: maxlerebourg <maxlerebourg@gmail.com>
v1.5.1
2026-02-19 23:41:55 +01:00
maxlerebourgandGitHub 889c5b55fe Add solved-captcha as option of remediationCustomHeader (#310) v1.5.0 2026-01-23 11:36:32 +01:00
efb3a67019 🔒️ Potential fix for code scanning alert no. 8: Workflow does not contain permissions (#311)
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-01-22 09:44:33 +01:00
omerandGitHub 0780027252 🐛 Do not validate Crowdsec LAPI authentication credentials if bouncer is in Appsec mode (#305)
* Do not validate Crowdsec LAPI key and TLS authentication if bouncer is in AppSec mode

* Add extra validation checks for lapiKey or appsecKey definition

* Fix linting on changed error message

* Update configuration.go

- Show paramName in validateParamsApiKey
- Remove check for empty appsecKey or lapiKey (LAPI can have TLS auth)
- Remove check for emptry appsecKey if CrowdsecMode is Appsec

* Update configuration_test.go after updated validateParamsAPIKey
v1.5.0-beta2
2026-01-20 23:42:24 +01:00
892909b9b8 🐛 fix start up config error for appsec and review doc for appsec tls (#300)
* 🐛 fix start up config error for appsec

* :doc: add documentation on appsec variables and missing conf parameter

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix after lot of tests

* update exemple tls with new variables tested

* fix exemple appsec with release and not localplugin

---------

Co-authored-by: mhx <mathieu@hanotaux.fr>
v1.5.0-beta1
2025-12-21 21:52:19 +01:00
c26923dee5 ⬆️ Bump actions/cache from 4 to 5 (#303)
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 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/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-20 14:30:49 +01:00
maxlerebourgandGitHub a9d83f2097 Separate TLS conf for LAPI and Appsec (#293)
*   Separate TLS conf for LAPI and Appsec

* 🍱 fix lint

* 🍱 fix test

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint ?

* 🍱 fix lint

* 🍱 Add default for traceCustomHeaders
v1.4.7
2025-12-11 07:58:12 +01:00
omerandGitHub e20ccc5d0c Add support for injecting request header value into ban HTML template (#296)
* Add parameter to specify Request header value to inject in HTML template

* Add documentation for specifying request header value

* Fix example in docs for CustomHeader

* Update parameter name to traceCustomHeader

* Ensure naming is consitent with project
2025-12-10 07:54:07 +01:00
50beb4294f ⬆️ Bump actions/checkout from 5 to 6 (#294)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-27 15:40:18 +01:00
maxlerebourgandGitHub 4ab4f3f183 Transform banTemplate to add blocking reason and client IP (#290)
*  Transform banTemplate to add blocking reason

* 🍱 fix test

* 🍱 fix lint

* 🍱 fix test

* 🍱 fix lint

* 🍱 fix lint

* 🍱 add doc and fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint

* 🍱 lint html

* 🍱 fix comments + fix wicketpeeker readme

* 🍱 Give ClientIP in ban page

* 🍱 fix test
v1.4.6
2025-11-15 10:42:14 +01:00
usr3andGitHub 2aac531ea7 📝 docs: fix captcha profile reference doc link (#289)
Fixed broken link referencing the captcha profile in Crowdsec documentation
2025-10-30 14:20:02 +01:00
Patrick EvansandGitHub e8e60c958f 📝 docs: fix wicketkeeper name references (#285) 2025-10-19 12:53:07 +02:00
a2d3708bc3 Do not cache decisions if DefaultDecisionSeconds=0 (#280)
* xx

* Remove outdated comment on decision caching

Remove comment about decision caching based on timeout.

---------

Co-authored-by: maxlerebourg <maxlerebourg@gmail.com>
2025-10-18 11:58:00 +02:00
65a2f79fb3 🐛Not write response body for HEAD requests (#277)
* Fixes

* XX

* Fix

* 🍱 Lint

* 🍱 remove useless comments

---------

Co-authored-by: Max Lerebourg <maxlerebourg@gmail.com>
2025-10-06 11:19:19 +02:00
a2ecc95dc9 ⬆️ Bump actions/setup-go from 5 to 6 (#268)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5 to 6.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-08 16:23:10 +02:00
7c4f5163e9 add custom selfhosted captcha (#259)
*  Add wicketkeeper captcha

*  Anom config

* 🍱 fix readme

* 🍱 fix lint

* 🍱 fix lint

* 🍱 normalize

* 🍱 fix lint

* 🍱 fix lint

*  Add env for RemediationStatusCode (#250)

*  Add env for defaultStatusCode

* 📝 doc

* change name of the parameter

* 🔧 Add config check

* fix lint

* 📈 Report traffic dropped metrics to LAPI (#223)

* Initial implementation

* fix

* fixes

* Fixes

* xx

* progress

* xx

* xx

* xx

* fix linter

* Progress

* Fixes

* xx

* xx

* Remove trace logger

* Last fix

* fix lint

* fix lint

* fix lint

---------

Co-authored-by: Max Lerebourg <maxlerebourg@gmail.com>

*  Anom config

* 🍱 fix readme

* 🍱 fix lint

* 🍱 normalize

* 🍱 fix lint

* 📝 Add documentation

* 📝 Fix example and makefile and doc for wicketkeeper

* 🍱 fix last things

* 🍱 add disclaimer to use maxlerebourg docker image

* 🍱 Use official wicketpeeker image

* 🍱 revert unnecessary code

* 🍱 fix

---------

Co-authored-by: David <deivid.garcia.garcia@gmail.com>
Co-authored-by: max.lerebourg <max.lerebourg@monisnap.com>
Co-authored-by: mhx <mathieu@hanotaux.fr>
v1.4.5
2025-09-01 19:41:45 +02:00
734975c206 ⬆️ Bump github.com/maxlerebourg/simpleredis (#262)
Bumps [github.com/maxlerebourg/simpleredis](https://github.com/maxlerebourg/simpleredis) from 1.0.11 to 1.0.12.
- [Release notes](https://github.com/maxlerebourg/simpleredis/releases)
- [Commits](https://github.com/maxlerebourg/simpleredis/compare/v1.0.11...v1.0.12)

---
updated-dependencies:
- dependency-name: github.com/maxlerebourg/simpleredis
  dependency-version: 1.0.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 12:00:02 +02:00
7397834e58 ⬆️ Bump actions/checkout from 4 to 5 (#261)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 11:59:31 +02:00
84a5674b14 📈 Report traffic dropped metrics to LAPI (#223)
* Initial implementation

* fix

* fixes

* Fixes

* xx

* progress

* xx

* xx

* xx

* fix linter

* Progress

* Fixes

* xx

* xx

* Remove trace logger

* Last fix

* fix lint

* fix lint

* fix lint

---------

Co-authored-by: Max Lerebourg <maxlerebourg@gmail.com>
v1.4.4
2025-07-02 11:36:09 +02:00
maxlerebourgandGitHub de7e382fde Add env for RemediationStatusCode (#250)
*  Add env for defaultStatusCode

* 📝 doc

* change name of the parameter

* 🔧 Add config check

* fix lint
v1.4.3
2025-07-01 21:59:12 +02:00
gptlangandGitHub abae855d9e Set traefik logs to json so it can actually be parsed (#235) 2025-05-07 11:22:27 +02:00
Lluís D.andGitHub 4bb6e830dc Fix query of the GET /decisions endpoint (#236)
- banned=true query parameter doesn't exist based on LAPI
  dcoumentation, remove it
2025-04-28 16:12:54 +02:00
mathieuHaandGitHub 78869ecf77 🔧 Add support for logLevel in any case (#231) 2025-04-06 10:41:16 +02:00
maxlerebourgandGitHub 7f99266f99 📝 doc: rename RedisUnreachableBlock to RedisCacheUnreachableBlock (#230) 2025-04-05 11:34:06 +02:00
mathieuHaandGitHub 5418d35feb feat(logs) add supports write logs to files (#217)
*  feat(logs) add supports write logs to files

* fix(lint) 🚨 fix go lint

* 🐛 fix(bug) check path is done only if provided

* 📝 doc(vars) add LogFilePath to vars

* 🦺 chore(review) update doc, configuration check and logger
v1.4.2
2025-03-31 20:19:44 +02:00
maxlerebourgandGitHub a184ae6db9 💄 Center recaptcha div (#225) 2025-03-25 09:34:06 +01:00
blotusandGitHub e4c84409e7 🔨 always set custom remediation header if configured for bans (#218) 2025-02-17 14:02:21 +01:00
maxlerebourgandGitHub 4708d76854 Add variable to not block if redis is unreachable (#214)
*  Add variable to not block if redis is unreachable

* 🚨 fix lint

* 📝 Update README.md
v1.4.1
2025-02-10 20:10:29 +01:00
maxlerebourgandGitHub c34d7f4617 🍱 Fix lint (#211) 2025-01-29 08:14:15 +01:00
0e9620bfe9 👷 chore(ci) bump CI and automate dep updates (#210)
* 👷 chore(ci) bump CI and automate dep updates

* 🚨 chore(go) fix golang lint

* 🍱 fix lint

---------

Co-authored-by: Max Lerebourg <maxlerebourg@gmail.com>
v1.4.0
2025-01-29 08:07:04 +01:00
maxlerebourgandGitHub 92f05b0ba5 [BREAKING-CHANGE] Add CrowdsecAppsecBodyLimit (#208)
*  Add CrowdsecAppsecBodyLimit

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix error on main
2025-01-24 21:04:45 +01:00
980a7dd05e Add AppSec Path Variable (#202)
* Added Appsec Path config Variable

*  Add path env var for lapi and appsec

* 🍱 Update README.md

---------

Co-authored-by: Tobias Heinze <tobias.heinze@telekom.de>
Co-authored-by: Max Lerebourg <maxlerebourg@gmail.com>
2025-01-24 20:12:30 +01:00