molecule-core/workspace-server/internal/middleware
Hongming Wang f2a4b6e0d3 fix: dev-mode bypass for IP rate limiter + 429 retry on GET
The 600-req/min/IP bucket is sized for SaaS where each tenant has
a distinct client IP. On a local Docker setup every panel shares
one IP — hydration (/workspaces + /templates + /org/templates +
/approvals/pending) plus polling (A2A overlay + activity tabs +
approvals + schedule + channels + audit trail) can burst past the
bucket inside a minute, blanking the canvas with 429s. The user
reported it after dragging workspaces — dragging itself is
release-only (savePosition in onNodeDragStop), but the polling
that's always running added onto startup tripped the limit.

Two-layer fix:

Server: RateLimiter.Middleware short-circuits when isDevModeFailOpen
is true (MOLECULE_ENV=development + empty ADMIN_TOKEN), matching
the Tier-1b hatch already applied to AdminAuth, WorkspaceAuth, and
discovery. SaaS production keeps the bucket.

Client: api.ts auto-retries a single 429 on idempotent GET requests,
waiting the server-provided Retry-After (capped at 20s). Mutations
(POST/PUT/PATCH/DELETE) never auto-retry to avoid double-applying.
Users on SaaS hitting a legitimate rate-limit spike get one
transparent recovery instead of an immediately-blank Canvas.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 20:44:09 -07:00
..
devmode_test.go refactor(middleware): extract dev-mode fail-open predicate 2026-04-23 14:55:34 -07:00
devmode.go fix: six UX bugs (peers auth, scroll, chat tabs, config persist, + visibility) 2026-04-23 20:18:30 -07:00
mcp_ratelimit_test.go chore: open-source restructure — rename dirs, remove internal files, scrub secrets 2026-04-18 00:24:44 -07:00
mcp_ratelimit.go chore: open-source restructure — rename dirs, remove internal files, scrub secrets 2026-04-18 00:24:44 -07:00
ratelimit_test.go chore: open-source restructure — rename dirs, remove internal files, scrub secrets 2026-04-18 00:24:44 -07:00
ratelimit.go fix: dev-mode bypass for IP rate limiter + 429 retry on GET 2026-04-23 20:44:09 -07:00
securityheaders_test.go chore: open-source restructure — rename dirs, remove internal files, scrub secrets 2026-04-18 00:24:44 -07:00
securityheaders.go chore: open-source restructure — rename dirs, remove internal files, scrub secrets 2026-04-18 00:24:44 -07:00
session_auth_test.go fix: close cross-tenant authz + cp_proxy admin-traversal gaps 2026-04-20 13:45:57 -07:00
session_auth.go fix(canvas/a11y): aria-hidden SVGs, MissingKeysModal semantics, session cookie auth (#1744) 2026-04-23 17:39:38 +00:00
tenant_guard_test.go fix(tenant-guard): allowlist /registry/register + /registry/heartbeat (#1236) 2026-04-21 02:47:27 +00:00
tenant_guard.go fix(tenant-guard): allowlist /registry/register + /registry/heartbeat (#1236) 2026-04-21 02:47:27 +00:00
wsauth_middleware_org_id_test.go fix(security): P0 — F1085/KI-005/CWE-78 security fixes rebased clean onto staging 2026-04-23 20:52:49 +00:00
wsauth_middleware_test.go Merge remote-tracking branch 'origin/staging' into fix/restore-quickstart-plus-hotfixes 2026-04-23 16:42:41 -07:00
wsauth_middleware.go refactor(middleware): extract dev-mode fail-open predicate 2026-04-23 14:55:34 -07:00