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>
Binary e2e suite (Traefik binary + mock LAPI)
This suite runs Traefik as a downloaded binary with the plugin loaded from
the local source tree, and replaces Crowdsec with a small HTTP mock
(mocklapi/, a stdlib-only Go command). No Docker, no real
Crowdsec.
It is what CI runs (make e2e_mock). The Docker suite in
../scenarios is kept for local debugging against a real
Crowdsec, but is not exercised in CI.
Scope — what this suite does and does NOT test
These tests validate the plugin's own behaviour: the request flow through the Traefik middleware, the live / none / stream modes, caching, trusted-IP bypass, and ban / captcha page rendering.
They deliberately do not test that Crowdsec or its AppSec engine work correctly — that is validated and owned by the upstream maintainer (@maxlerebourg), not by this plugin. The mock only emulates the slice of the LAPI HTTP contract the plugin consumes.
So please don't open issues here about Crowdsec/AppSec detection accuracy based on this suite: the AppSec scenario is intentionally absent, and the mock returns whatever decisions the test tells it to.
What runs
| Component | How |
|---|---|
| Traefik | Binary v3.7.1, downloaded once and cached under .cache/ |
| Plugin | Loaded via experimental.localPlugins from the repo root (symlinked into plugins-local/) |
| LAPI | mocklapi — a stdlib-only Go command (its own nested module), compiled and cached under .cache/, driven through /admin endpoints instead of cscli |
| Backend | A plain HTTP responder built into the mock |
Fixed ports (override with env vars if needed): Traefik 8000, LAPI 8090,
backend 8091.
Running locally
Prerequisites: bash, curl, go, tar. The Traefik binary is fetched and
the mock is compiled automatically on first run (both cached under .cache/).
# one scenario
make e2e_mock_stream-mode
# or directly
./tests/e2e/mock/scenarios/stream-mode/run.sh
# the whole suite
make e2e_mock
Layout
mock/
lib/
common.sh # stack lifecycle, Traefik download, mock build, assertions, admin client
traefik.yml # static Traefik config (shared by all scenarios)
mocklapi/
go.mod # nested module — kept out of the plugin's build/lint/vendor
main.go # mock LAPI + backend
scenarios/
<name>/
dynamic.yml # Traefik dynamic config (router + bouncer middleware + backend)
run.sh # assertions for the scenario
*.html # optional fixtures (ban / captcha templates)
dynamic.yml uses placeholders (@@APIKEY@@, @@LAPI_HOST@@,
@@BACKEND_URL@@, @@SCENARIO_DIR@@) that common.sh substitutes at runtime.
Adding a scenario
- Create
scenarios/<name>/dynamic.ymlandrun.sh(copystream-mode/as a template). - In
run.sh, define abodyfunction with the assertions and callrun_scenario "<name>" "$HERE" body. - Drive decisions with
lapi_add_decision <ip> [type] [duration],lapi_delete_decision <ip>,lapi_reset. - Add
<name>toE2E_MOCK_SCENARIOSin theMakefile.