* 🐛 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>
* Consider 502, 503 and 504 as unavaible for appsec
Fixes#337
* ✨ add test and the function isReverseProxyError
---------
Co-authored-by: maxlerebourg <maxlerebourg@gmail.com>
* 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>
* 🍱 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>
* 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>
* 🐛 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>
* 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
* xx
* Remove outdated comment on decision caching
Remove comment about decision caching based on timeout.
---------
Co-authored-by: maxlerebourg <maxlerebourg@gmail.com>
* 🐛 fix(user-agent) add version in ua to reduce warning logs from crowdsec LAPI
* 🐛 fix(user-agent) add version in ua to reduce warning logs from crowdsec LAPI
* 🐛 fix(user-agent) remove whitespaces
* 🐛 fix(user-agent) Add Cap for Bouncer
---------
Co-authored-by: maxlerebourg <maxlerebourg@gmail.com>
* ✨ Add ban html template
* 📝 Add doc for custom ban page
* ⚰️ Remove old code due to merge
* ✏️ Fix merge remaining in html
* ✨ render banTemplate from html/template to string
* 🚨 : fix lint
---------
Co-authored-by: max.lerebourg <max.lerebourg@monisnap.com>