- Raise header to z-50 so toggle button stays clickable above backdrop
- Use document keydown listener for Escape instead of onKeyDown on backdrop
- Only render hamburger toggle when signed in
- Make SignedOutPanel col-span responsive (col-span-1 on mobile)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use ref-based previous pathname check instead of useEffect + setState,
which triggers the react-hooks/set-state-in-effect lint rule.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sidebar and backdrop were z-30, same as sticky page headers (live feed,
boards, etc.), causing the hamburger menu to render behind page content.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add hamburger menu with off-canvas sidebar drawer on mobile.
Responsive padding, full-width panels, and stacked layouts
for screens under 768px (md breakpoint).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restore the existing short token-prefix logging behavior for agent auth failures while keeping the optional bearer-path rate-limit fix. Update tests and docs so the replacement branch reflects the intended logging policy.
Co-Authored-By: Claude <noreply@anthropic.com>
Rate-limit the optional agent bearer path after user auth resolution so mixed user/agent routes no longer leave an unthrottled PBKDF2 path. Stop logging token prefixes on agent auth failures and require a locally supplied token for backend/.env.test instead of committing one.
Update tests and docs to cover agent bearer fallback, configurable webhook signature headers, and the operator-facing security settings added by the hardening work.
Co-Authored-By: Claude <noreply@anthropic.com>
The BASE_URL validation added to Settings breaks the CI migration check
which only sets AUTH_MODE, LOCAL_AUTH_TOKEN, and DATABASE_URL.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use _env_file=None and explicit base_url so tests don't depend on
global env vars or .env file loading.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Always append the timestamp before checking the count so that sustained
spam extends the window, matching the Redis backend's zadd-before-zcard
semantics.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace sync redis.Redis with redis.asyncio to avoid blocking the
event loop during rate-limit checks. Make RateLimiter.is_allowed async
across both backends and update all call sites to await.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Set a9b1c2d3e4f7.down_revision = "a1b2c3d4e5f6" so the activity_events
migration depends on the webhook_secret migration, creating a linear
chain instead of two heads from the same parent.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add get_client_ip() helper that inspects Forwarded and X-Forwarded-For
headers only when the direct peer is in TRUSTED_PROXIES (comma-separated
IPs/CIDRs). Replaces raw request.client.host in rate-limit and webhook
source_ip to prevent all traffic collapsing behind a reverse proxy IP.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents normal user requests with Authorization: Bearer from being
throttled by the agent auth limiter in the shared require_user_or_agent
dependency path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Strip whitespace (blank → None) and reject non-ASCII-token characters
to prevent impossible header lookups that would fail all signed requests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add RedisRateLimiter using sorted-set sliding window alongside the
existing InMemoryRateLimiter. Users choose via RATE_LIMIT_BACKEND
(memory|redis) with RATE_LIMIT_REDIS_URL falling back to RQ_REDIS_URL.
Redis backend validates connectivity at startup and fails open on
transient errors during requests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Not all webhook providers use X-Hub-Signature-256 or X-Webhook-Signature.
Add an optional signature_header field so users can specify which header
carries the HMAC signature. When set, that exact header is checked;
when unset, the existing auto-detect fallback is preserved. The custom
header is also excluded from stored/exposed payload headers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
get_agent_auth_context_optional was not rate-limited, allowing
brute-force token guessing via routes that use require_user_or_agent.
Now applies agent_auth_limiter when a token is actually presented.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The has_token redaction was reverted to avoid a frontend breaking
change. Update docs to match: tokens are currently returned in API
responses, redaction is planned for a future PR. Also note the
configurable payload size limit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
node:20-alpine uses BusyBox which does not support GNU-style
--system/--ingroup flags. Switch to -S/-G equivalents.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous field_validator approach passed `cls` as the first argument
to `_normalize_secret`, which only accepted `v`, causing a TypeError at
runtime. Switch to `Annotated[str | None, BeforeValidator(...)]` which
calls the function with just the value and also eliminates the repeated
validator assignment in both schema classes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move blank/whitespace-only secret normalization to a shared
field_validator on both BoardWebhookCreate and BoardWebhookUpdate.
This ensures consistent behavior across create and update paths
and removes the inline normalization from the endpoint handlers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The has_token boolean redaction requires coordinated frontend changes
(detail page, edit page, orval types). Revert to returning the raw
token for now; token redaction will be handled in a dedicated PR.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
A 6-character prefix of the token is standard practice for debugging
failed auth attempts and is not a security risk. Restored in both
required and optional auth paths, and removed the now-incorrect test
that asserted its absence.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add WEBHOOK_MAX_PAYLOAD_BYTES setting (default 1 MB) so deployments
with larger webhook payloads can raise the limit via environment
variable instead of being hard-blocked at 1 MB.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
_captured_headers was storing all x-* headers including
X-Hub-Signature-256 and X-Webhook-Signature. Since stored headers
are exposed via the payload read endpoint, this enabled replay
attacks without knowing the webhook secret. Now signature and
authorization headers are excluded from capture.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These two tests were exact subsets of the dedicated test_rate_limit.py
suite. Consolidating to a single file avoids maintenance drift.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These dependencies check actor type (human user vs agent), not admin
privilege. The old names were misleading and could cause authorization
mistakes when wiring new endpoints. Renamed across all 10 consumer
files along with their local ADMIN_AUTH_DEP / ADMIN_OR_AGENT_DEP
aliases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>