fix(webui): surface tool-level quarantine on the Servers list#519
Merged
Dumbris merged 1 commit intoMay 24, 2026
Merged
Conversation
The Servers grid only renders the big orange "Server is quarantined" banner + Approve button when `server.quarantined === true`. Servers that are trusted at the server level but ship tools blocked by Spec 032 tool-level quarantine (pending / changed) had only a tiny `stat-desc` under the tool count — easy to miss, and shadowed entirely by the `X disabled` line when any tool was also disabled, because both lines shared a `v-if / v-else-if` chain. The asymmetry is confusing: the detail page DOES escalate tool-level quarantine to a yellow alert panel with an Approve-All button, so users who hit the "tool requires approval" error from the daemon find clear remediation on Details but nothing on the list view. They report the list as broken or inconsistent. This commit: * Adds a second `alert-warning` banner (`v-else-if="quarantineToolCount > 0"`) with a Review link that routes to `/servers/<name>?tab=tools`. Server and tool quarantine remain mutually exclusive on the card — the server-level banner already implies the tools won't run, so we don't stack two warnings. * Splits the stat-desc `v-if / v-else-if` chain so `X disabled` and `N pending approval` can render side-by-side. Token-size hint stays the "nothing wrong" fallback. * Computes a context-aware summary string: - "All N tools pending security approval" when every tool is pending - "N of M tools pending security approval" when partial - "N tools changed since approval — re-review needed" for rug-pull - mixed pending+changed when both apply No backend change: the `quarantine.pending_count` / `changed_count` / `blocked_count` block is already populated by `enrichServersWithQuarantineStats` (REST + SSE). Extends the existing ServerCard test with five new cases covering the partial / full / changed / mixed-with-server-level / mixed-with-disabled scenarios.
3 tasks
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Dumbris
approved these changes
May 24, 2026
Dumbris
approved these changes
May 24, 2026
Member
Dumbris
left a comment
There was a problem hiding this comment.
Thanks for this, Roman — really nicely scoped fix. 🙏
A few things I appreciated:
- Correct precedence: routing the tool-level banner through
v-else-ifafterserver.quarantinedmeans a fully-quarantined server shows only the existing banner — no double warning. The dedicated test for this makes the intent unambiguous. - Unbundling the stat-desc chain so
X disabledandN pending approvalcan coexist is exactly right — the oldv-else-ifmasking was the subtle part of the bug, and you caught it. quarantineToolCountsummingpending_count + changed_countmeans the rug-pull (changed-only) path correctly surfaces the banner, andtoolQuarantineSummarycovers all four states (all/partial/changed/mixed) with clean pluralization.- Zero backend change, and you verified the
quarantine.{pending,changed}_countblock +v-memodeps were already wired for reactivity. Solid homework.
Five well-targeted test cases. CI frontend job is green, so the local sandbox limitation is fully covered.
One tiny non-blocking nit for a future pass: the compact stat-desc still reads {{ quarantineToolCount }} pending approval while the count includes changed tools, so a changed-only server reads "2 pending approval" in the small line (the banner itself says "changed" correctly). Not worth holding the merge.
Approving — thank you!
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.
Problem
The Servers grid in the Web UI renders the big orange Server is quarantined banner + Approve button only when
server.quarantined === true. Servers that are trusted at the server level but ship tools blocked by Spec 032 tool-level quarantine (pending/changed) get only a tinystat-descline under the tool count — easy to miss, and shadowed entirely by theX disabledline whenever any tool is also disabled, because both lines share av-if / v-else-ifchain atServerCard.vue:32–46.The detail page does escalate tool-level quarantine to its own yellow alert with an Approve-All button (
ServerDetail.vue:325). So users who hit the daemon'squarantine pending approvalerror find clear remediation on Details, but nothing actionable on the list view — and they report the list as broken or inconsistent.A common path into this state is
setup.sh-style provisioning that registers servers with--no-quarantinebut doesn't catch every tool in the post-add auto-approve pass (OAuth servers like Atlassian, lazy-spawn servers, or anything exceeding the approval-poll timeout). Those servers end upquarantined=false+quarantine.pending_count > 0— exactly the gap this PR closes.Change
alert-warningbanner inServerCard.vuefor tool-level quarantine, with aReviewlink to/servers/<name>?tab=tools. Mutually exclusive with the server-level banner viav-else-if— when the server itself is quarantined the existing banner already implies the tools won't run.v-if / v-else-ifchain soX disabledandN pending approvalcan render side-by-side instead of one masking the other. The<token-size>hint stays the "nothing wrong" fallback.toolQuarantineSummarycomputed that picks one of:All N tools pending security approval(every tool pending)N of M tools pending security approval(partial)N tools changed since approval — re-review needed(rug-pull guard)pending, changedform when both applyNo backend change. The
quarantine.{pending_count,changed_count,blocked_count}block is already populated byenrichServersWithQuarantineStatsin both REST list (internal/httpapi/server.go:1140) and SSE paths (internal/runtime/event_bus.go:270). Thev-memodeps onServers.vue:165–175already include bothpending_countandchanged_count, so the new banner re-renders reactively.Tests
Extends
frontend/src/components/__tests__/ServerCard.test.tswith five new cases:3 of 10 tools pending+ Review link present + no server-level bannerAll 4 tools pending2 tools changed since approvalserver.quarantined === trueTest plan
frontendtests with the new cases (could not exercise locally — sandboxed environment couldn't reach@guolao/vue-monaco-editorto reinstall node modules).--no-quarantineand tools that aren't auto-approved → list now shows yellow banner + Review link.