Release: security/perf audit fixes + frontend reload state fix#251
Merged
Conversation
Deep security + performance audit of frontend, gateway/API, infra, MCP, and connector. 19 findings fixed, 2 partial, 3 deferred. All fixes were adversarially re-reviewed; the review's corrections are folded in. Security - approval: gate resolve_permission on membership/admin OR bot-owner and purge stale approval_delegations + RESPOND grants on member removal (#1) - agent_bridge: require bot channel membership in handle_acp_event_frame before any store write / event-log / broadcast (#3) - ratelimit: bound eviction (retain live windows + hard-clear fallback) (#12) - email: never log one-time codes when an email provider is configured (#13) - CSP: add default/script/style/img/font/connect/media-src; allow https images and blob media (#17) - connector: cap self-update downloads, monotonic anti-downgrade guard, bound the loopback pre-auth request body (413) (#14, #24, #15) - workspace: escape LIKE wildcards; files: normalize content_type to a safe allowlist (#22, #23) Performance - auth: run all bcrypt hash/verify on spawn_blocking, incl. admin seed (#2) - db: bounded unread/mention scan (99+), partial index for pending permissions, batched Fleet policy resolution (#6, #7, #5) - gateway: TTL cache for per-trace bot rules, presence roster cache (#8, #9) - frontend: plain-text streaming render + memoized MarkdownRenderer, stable channelFiles memo, offline stream-finalize guard (#10, #11) - connector: Value::take / mem::take to drop redundant deep clones (#20, #21) Deferred (documented): #4 Redis-backed cross-replica limiter (interim: replicaCount=1), #16 httpOnly-cookie session token, #18 Arc fan-out. Verified offline: server cargo check + 172/172 lib tests; connector cargo check + 98/98 tests; mcp-server cargo check; frontend typecheck (changed files clean) + 66/66 vitest. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The chat route was `/chat/*` and carried no selection, while `selectedWorkspaceId` lived only in memory (chatStore persists just `lastChannelByWorkspace`). So after every reload it was necessarily null and ChatLayout's bootstrap unconditionally fell back to the personal workspace — a user reading a team workspace got dumped back home, and a channel could never be linked or shared. Put the selection in the path (`/chat/:workspaceId?/:channelId?`) and make that the source of truth across reloads. The store stays the sole selection API — all 11 call sites (rail, sidebar, dialogs, invite and register flows) are untouched — with ChatLayout reconciling the two in one place: path → store on mount and back/forward, store → path for in-app selections. `hydrateSelection` applies an explicit pair without selectWorkspace's last-channel derivation, which would otherwise clobber the channel the path names. Two things worth flagging for review: - The mirror navigates with `replace`, not `push`. On mobile the conversation screen is itself a pushed history entry, so an entry per channel switch would make Back land on the previous channel instead of popping to the list. Refresh-restore and shareable links both work; browser back/forward *between channels* is deliberately not wired up, as that needs the mobile history model reworked first. - loadWorkspaces read `selectedWorkspaceId` through its mount-time closure, which the path now races: the captured null would overwrite the workspace just restored. It reads fresh via getState() and also validates membership, so a stale or foreign link falls back home instead of resting on a workspace that renders empty. Verified against the kind stack (vite dev → in-cluster gateway): reload on a team workspace stays put; reload on a channel restores it; a non-member workspace id in the path falls back and corrects the URL. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
cargo fmt --check on the agent packages requires the (mem::take, clone) tuple from the #21 fix to wrap across lines. Formatting only, no behavior change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Security + performance audit fixes (19 fixed, 2 partial, 3 deferred)
…resh-d169b8 fix(frontend): keep the open workspace/channel across a reload
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Test plan