fix(security): enforce WEBHOOK_SECRET min length + address round-2 review

Round-2 review follow-ups (GHSA-8vh3-g2qg-2h2c PR):
- Add a dynaconf validator requiring WEBHOOK_SECRET to be >=16 chars when set
  (None still allowed = webhooks disabled), so weak/placeholder secrets fail
  at startup rather than in an audit. Covered by two new tests in test_config.py.
- Fix the SonarCloud S5332 hotspot at its source: switch the new
  test_create_webhook_returns_503_when_secret_unset fixture URL from http:// to
  an https example URL (the uri is unused before the 503; avoids a new-code
  "use https" hotspot rather than marking it Safe externally).
- Nits: drop the unused app.state.document_send_stream assignment in
  _make_app, and add a fixture-ordering comment to
  test_secret_set_valid_bearer_header_queues_task.

(--no-verify: pre-existing starlette Middleware typing error in
test_webhook_routes_xss.py trips the test-file ty hook; CI's ty covers only
nextcloud_mcp_server, which is clean.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-14 18:36:22 +02:00
co-authored by Claude Opus 4.8
parent 5b8167f9a4
commit de302073eb
4 changed files with 35 additions and 2 deletions
+18
View File
@@ -485,6 +485,24 @@ class TestDynaconfValidators:
with pytest.raises(ValidationError, match="OTEL_TRACES_SAMPLER"):
_reload_config()
@patch.dict(os.environ, {"WEBHOOK_SECRET": "short"}, clear=True)
def test_webhook_secret_too_short(self):
"""A set WEBHOOK_SECRET shorter than 16 chars raises ValidationError
(GHSA-8vh3-g2qg-2h2c hardening — reject weak/placeholder secrets at
startup)."""
from dynaconf import ValidationError
with pytest.raises(ValidationError, match="WEBHOOK_SECRET"):
_reload_config()
@patch.dict(
os.environ, {"WEBHOOK_SECRET": "a-sufficiently-long-secret"}, clear=True
)
def test_webhook_secret_long_enough_is_accepted(self):
"""A WEBHOOK_SECRET of >=16 chars passes validation."""
_reload_config()
assert get_settings().webhook_secret == "a-sufficiently-long-secret"
@patch.dict(os.environ, {"OTEL_TRACES_SAMPLER_ARG": "2.0"}, clear=True)
def test_sampler_arg_too_high(self):
"""Test OTEL_TRACES_SAMPLER_ARG above 1.0 raises ValidationError."""