feat: traces and console improvement - #164
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (21)
🚧 Files skipped from review as they are similar to previous changes (14)
📝 WalkthroughWalkthroughThis PR adds a resizable chat dock with density-aware chat components and a ConversationsProvider, refactors trace filters into a top-row + popover, and introduces critical-path and engine-routing toggles with container-aware panel resizing and ARIA improvements. ChangesChat Dock and Density-Based Layout System
Trace View Filtering and Critical-Path Toggles
Sequence DiagramsequenceDiagram
participant User
participant App as App.tsx
participant Provider as ConversationsProvider
participant Dock as ChatDock
participant Panel as ChatPanel
participant Sidebar as ConversationSidebar
participant View as ChatView
User->>App: navigate to chat or view dock
App->>Provider: wrap layout with context
Provider->>Provider: aggregate conversations + model state
App->>Dock: conditionally render if eligible
Dock->>Panel: render ChatPanel (density='dock')
Panel->>Sidebar: render with conversation list
Panel->>View: render active conversation with density prop
User->>Dock: drag resize handle
Dock->>Dock: compute clamped width, persist to localStorage
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
skill-check — worker0 verified, 10 skipped (no docs/).
Three for three. Nicely done. |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (2)
console/web/src/pages/Traces/components/TraceFilters.tsx (1)
198-205: ⚡ Quick winPopover position can drift after open.
Position is only measured once. If the viewport/layout changes while open, the popover can detach from its trigger.
Suggested fix (recompute while open)
useEffect(() => { if (!open || !triggerRef.current) return - const rect = triggerRef.current.getBoundingClientRect() - setPos({ - top: rect.bottom + 4, - right: window.innerWidth - rect.right, - }) + const updatePos = () => { + const rect = triggerRef.current?.getBoundingClientRect() + if (!rect) return + setPos({ + top: rect.bottom + 4, + right: window.innerWidth - rect.right, + }) + } + updatePos() + window.addEventListener('resize', updatePos) + window.addEventListener('scroll', updatePos, true) + return () => { + window.removeEventListener('resize', updatePos) + window.removeEventListener('scroll', updatePos, true) + } }, [open, triggerRef])Also applies to: 207-224
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@console/web/src/pages/Traces/components/TraceFilters.tsx` around lines 198 - 205, The popover position is only measured once in the useEffect that reads triggerRef.getBoundingClientRect() (when open), so it can drift; update TraceFilters to recompute position while open by adding listeners (window resize and scroll, and/or a MutationObserver) that call the same positioning logic used in the existing useEffect and update setPos, and clean them up when open becomes false; modify the effect that depends on [open, triggerRef] (and the similar block at the other range) to register these listeners when open is true and remove them on cleanup so the popover follows layout/viewport changes without code duplication.console/web/src/components/chat/ChatDock.tsx (1)
96-110: ⚡ Quick winAdd keyboard resize behavior for the separator handle.
The handle is focusable but not operable via keyboard; add
onKeyDown(Arrow/Home/End) so keyboard-only users can resize.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@console/web/src/components/chat/ChatDock.tsx` around lines 96 - 110, Add keyboard support to the separator by wiring an onKeyDown handler on the same div that currently uses handleMouseDown and handleReset; intercept ArrowLeft/ArrowRight (or ArrowUp/ArrowDown if your layout uses vertical keyboard mapping) to decrement/increment the dock width in small steps, and handle Home to set width to DOCK_MIN_WIDTH and End to set width to maxWidth. Use the existing width state setter (the same state updated by handleMouseDown/drag) and ensure you call event.preventDefault() for handled keys and update any isResizing state consistently; reference the separator div, handleMouseDown, handleReset, width, DOCK_MIN_WIDTH and maxWidth when implementing the onKeyDown logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@console/web/src/App.tsx`:
- Line 9: The ConversationsProvider is being mounted unconditionally (causing
chat backend/model/catalog initialization) even on non-chat routes; wrap the
ConversationsProvider usage so it only renders when the chat UI is visible by
guarding it with the condition (view === 'chat' || dockVisible) where view is
the current active view and dockVisible is the dock visibility flag, e.g.
replace the unconditional <ConversationsProvider>...</ConversationsProvider>
block (the component named ConversationsProvider) with a conditional render that
returns the provider and its children only when that boolean expression is true,
leaving other routes to avoid loading chat state.
In `@console/web/src/components/chat/ChatDock.tsx`:
- Around line 56-77: The cleanup of the useEffect that tracks dragging only
removes event listeners and relies on handleMouseUp to reset global styles, so
if the component unmounts mid-drag document.body.style.cursor and
document.body.style.userSelect can stay set; update the effect cleanup to also
reset document.body.style.cursor and document.body.style.userSelect to their
defaults (empty string) so both the returned cleanup function and handleMouseUp
perform the same reset; locate the useEffect that depends on isResizing and
references handleMouseMove/handleMouseUp/reserveStartRef/onWidthChange and add
the style resets there.
In `@console/web/src/components/sidebar/ConversationSidebar.tsx`:
- Around line 30-41: The collapsed UI currently always renders an "expand"
button even when the optional onToggleCollapsed prop is undefined; update the
collapsed branch in ConversationSidebar (where collapsed is checked and the
button with PanelLeftOpen is rendered) to conditionally render that button only
if onToggleCollapsed is provided, so the interactive control is suppressed when
the callback is absent and avoids a dead/no-op control.
In `@console/web/src/pages/Traces/hooks/useResizablePanels.ts`:
- Around line 191-223: The effect in useResizablePanels currently only listens
to window.resize so container-driven layout changes can leave panel widths
stale; replace/augment the window listener by creating a ResizeObserver on
containerRef.current (use getContainerWidth inside the same sync callback) to
call sync whenever the container element's size changes, keep the existing
window.resize for viewport changes, and ensure both the observer and the window
listener are cleaned up in the returned cleanup; update any dependencies
accordingly while continuing to use setContainerWidth, setPanelWidths and
selectedSpanIdRef in the same sync logic.
In `@console/web/src/pages/Traces/hooks/useShowEngineRouting.ts`:
- Around line 11-18: The hook useShowEngineRouting currently accesses
window.localStorage directly in the useState initializer and in the useEffect
setter; wrap both localStorage.getItem and localStorage.setItem calls in
try/catch blocks (and still guard for typeof window === 'undefined') so any
SecurityError/QuotaExceededError is caught and handled, returning the safe
default (false) on read errors and silently failing on write errors; reference
STORAGE_KEY in the catches and ensure the useState initializer returns false if
an exception occurs and the useEffect swallow errors rather than letting them
propagate.
In `@console/web/vite.config.ts`:
- Line 14: Remove the insecure wildcard host setting by deleting the
allowedHosts: true entry in vite.config.ts and replace it with an explicit
allowlist (or omit the option to use Vite defaults); locate the dev server
config (export default defineConfig -> dev -> allowedHosts) and set allowedHosts
to a concrete array of trusted hostnames/IPs (e.g., 'localhost', '127.0.0.1',
and any required dev host) instead of true to prevent DNS rebinding.
---
Nitpick comments:
In `@console/web/src/components/chat/ChatDock.tsx`:
- Around line 96-110: Add keyboard support to the separator by wiring an
onKeyDown handler on the same div that currently uses handleMouseDown and
handleReset; intercept ArrowLeft/ArrowRight (or ArrowUp/ArrowDown if your layout
uses vertical keyboard mapping) to decrement/increment the dock width in small
steps, and handle Home to set width to DOCK_MIN_WIDTH and End to set width to
maxWidth. Use the existing width state setter (the same state updated by
handleMouseDown/drag) and ensure you call event.preventDefault() for handled
keys and update any isResizing state consistently; reference the separator div,
handleMouseDown, handleReset, width, DOCK_MIN_WIDTH and maxWidth when
implementing the onKeyDown logic.
In `@console/web/src/pages/Traces/components/TraceFilters.tsx`:
- Around line 198-205: The popover position is only measured once in the
useEffect that reads triggerRef.getBoundingClientRect() (when open), so it can
drift; update TraceFilters to recompute position while open by adding listeners
(window resize and scroll, and/or a MutationObserver) that call the same
positioning logic used in the existing useEffect and update setPos, and clean
them up when open becomes false; modify the effect that depends on [open,
triggerRef] (and the similar block at the other range) to register these
listeners when open is true and remove them on cleanup so the popover follows
layout/viewport changes without code duplication.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6342a17a-4adc-4777-baf5-92c6377e0324
📒 Files selected for processing (21)
console/web/src/App.tsxconsole/web/src/components/chat/ChatDock.tsxconsole/web/src/components/chat/ChatPanel.tsxconsole/web/src/components/chat/ChatView.tsxconsole/web/src/components/chat/Composer.tsxconsole/web/src/components/chat/MessageList.tsxconsole/web/src/components/sidebar/ConversationSidebar.tsxconsole/web/src/components/ui/Sheet.tsxconsole/web/src/hooks/use-chat-dock.tsconsole/web/src/lib/conversations-context.tsxconsole/web/src/pages/Chat.tsxconsole/web/src/pages/Traces/components/FlameGraph.tsxconsole/web/src/pages/Traces/components/IconToggleButton.tsxconsole/web/src/pages/Traces/components/TraceFilters.tsxconsole/web/src/pages/Traces/components/WaterfallChart.tsxconsole/web/src/pages/Traces/hooks/useResizablePanels.tsconsole/web/src/pages/Traces/hooks/useShowEngineRouting.tsconsole/web/src/pages/Traces/index.tsxconsole/web/src/pages/Traces/lib/spanTree.test.tsconsole/web/src/pages/Traces/lib/spanTree.tsconsole/web/vite.config.ts
| import { useChatDock } from '@/hooks/use-chat-dock' | ||
| import { useHashRoute, type View } from '@/hooks/use-hash-route' | ||
| import { type Theme, useTheme } from '@/hooks/use-theme' | ||
| import { ConversationsProvider } from '@/lib/conversations-context' |
There was a problem hiding this comment.
Avoid mounting chat state on every route.
Line 52 now mounts ConversationsProvider even when the active view is traces, examples, or playground and the dock is closed. Since this provider now owns the chat backend/model/catalog state, those routes will still pay that initialization cost and any related fetches with no chat UI on screen. Please scope the provider to a chat-visible condition such as view === 'chat' || dockVisible.
Also applies to: 52-86
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@console/web/src/App.tsx` at line 9, The ConversationsProvider is being
mounted unconditionally (causing chat backend/model/catalog initialization) even
on non-chat routes; wrap the ConversationsProvider usage so it only renders when
the chat UI is visible by guarding it with the condition (view === 'chat' ||
dockVisible) where view is the current active view and dockVisible is the dock
visibility flag, e.g. replace the unconditional
<ConversationsProvider>...</ConversationsProvider> block (the component named
ConversationsProvider) with a conditional render that returns the provider and
its children only when that boolean expression is true, leaving other routes to
avoid loading chat state.
| useEffect(() => { | ||
| if (!isResizing) return | ||
|
|
||
| const handleMouseMove = (e: MouseEvent) => { | ||
| const dx = e.clientX - resizeStartRef.current.x | ||
| onWidthChange( | ||
| clamp(resizeStartRef.current.width + dx, resizeStartRef.current.max), | ||
| ) | ||
| } | ||
|
|
||
| const handleMouseUp = () => { | ||
| setIsResizing(false) | ||
| document.body.style.cursor = '' | ||
| document.body.style.userSelect = '' | ||
| } | ||
|
|
||
| document.addEventListener('mousemove', handleMouseMove) | ||
| document.addEventListener('mouseup', handleMouseUp) | ||
| return () => { | ||
| document.removeEventListener('mousemove', handleMouseMove) | ||
| document.removeEventListener('mouseup', handleMouseUp) | ||
| } |
There was a problem hiding this comment.
Reset global body styles in effect cleanup.
When unmount happens mid-drag, document.body.style.cursor/userSelect can remain stuck because only handleMouseUp resets them.
💡 Suggested fix
useEffect(() => {
if (!isResizing) return
@@
document.addEventListener('mousemove', handleMouseMove)
document.addEventListener('mouseup', handleMouseUp)
return () => {
document.removeEventListener('mousemove', handleMouseMove)
document.removeEventListener('mouseup', handleMouseUp)
+ document.body.style.cursor = ''
+ document.body.style.userSelect = ''
}
}, [isResizing, onWidthChange])📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| useEffect(() => { | |
| if (!isResizing) return | |
| const handleMouseMove = (e: MouseEvent) => { | |
| const dx = e.clientX - resizeStartRef.current.x | |
| onWidthChange( | |
| clamp(resizeStartRef.current.width + dx, resizeStartRef.current.max), | |
| ) | |
| } | |
| const handleMouseUp = () => { | |
| setIsResizing(false) | |
| document.body.style.cursor = '' | |
| document.body.style.userSelect = '' | |
| } | |
| document.addEventListener('mousemove', handleMouseMove) | |
| document.addEventListener('mouseup', handleMouseUp) | |
| return () => { | |
| document.removeEventListener('mousemove', handleMouseMove) | |
| document.removeEventListener('mouseup', handleMouseUp) | |
| } | |
| useEffect(() => { | |
| if (!isResizing) return | |
| const handleMouseMove = (e: MouseEvent) => { | |
| const dx = e.clientX - resizeStartRef.current.x | |
| onWidthChange( | |
| clamp(resizeStartRef.current.width + dx, resizeStartRef.current.max), | |
| ) | |
| } | |
| const handleMouseUp = () => { | |
| setIsResizing(false) | |
| document.body.style.cursor = '' | |
| document.body.style.userSelect = '' | |
| } | |
| document.addEventListener('mousemove', handleMouseMove) | |
| document.addEventListener('mouseup', handleMouseUp) | |
| return () => { | |
| document.removeEventListener('mousemove', handleMouseMove) | |
| document.removeEventListener('mouseup', handleMouseUp) | |
| document.body.style.cursor = '' | |
| document.body.style.userSelect = '' | |
| } | |
| }, [isResizing, onWidthChange]) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@console/web/src/components/chat/ChatDock.tsx` around lines 56 - 77, The
cleanup of the useEffect that tracks dragging only removes event listeners and
relies on handleMouseUp to reset global styles, so if the component unmounts
mid-drag document.body.style.cursor and document.body.style.userSelect can stay
set; update the effect cleanup to also reset document.body.style.cursor and
document.body.style.userSelect to their defaults (empty string) so both the
returned cleanup function and handleMouseUp perform the same reset; locate the
useEffect that depends on isResizing and references
handleMouseMove/handleMouseUp/reserveStartRef/onWidthChange and add the style
resets there.
| if (collapsed) { | ||
| return ( | ||
| <aside className="w-9 shrink-0 border-r border-rule flex flex-col items-center bg-bg gap-1 py-2"> | ||
| <button | ||
| type="button" | ||
| onClick={onToggleCollapsed} | ||
| aria-label="expand conversations" | ||
| title="expand conversations" | ||
| className="flex items-center justify-center size-7 text-ink-faint hover:text-ink transition-colors" | ||
| > | ||
| <PanelLeftOpen className="size-4" /> | ||
| </button> |
There was a problem hiding this comment.
Avoid rendering a dead “expand” button when no toggle handler is provided.
onToggleCollapsed is optional, but the collapsed branch always renders an interactive expand control. Guard this button behind the callback to prevent a no-op control.
💡 Suggested fix
- <button
- type="button"
- onClick={onToggleCollapsed}
- aria-label="expand conversations"
- title="expand conversations"
- className="flex items-center justify-center size-7 text-ink-faint hover:text-ink transition-colors"
- >
- <PanelLeftOpen className="size-4" />
- </button>
+ {onToggleCollapsed ? (
+ <button
+ type="button"
+ onClick={onToggleCollapsed}
+ aria-label="expand conversations"
+ title="expand conversations"
+ className="flex items-center justify-center size-7 text-ink-faint hover:text-ink transition-colors"
+ >
+ <PanelLeftOpen className="size-4" />
+ </button>
+ ) : null}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (collapsed) { | |
| return ( | |
| <aside className="w-9 shrink-0 border-r border-rule flex flex-col items-center bg-bg gap-1 py-2"> | |
| <button | |
| type="button" | |
| onClick={onToggleCollapsed} | |
| aria-label="expand conversations" | |
| title="expand conversations" | |
| className="flex items-center justify-center size-7 text-ink-faint hover:text-ink transition-colors" | |
| > | |
| <PanelLeftOpen className="size-4" /> | |
| </button> | |
| if (collapsed) { | |
| return ( | |
| <aside className="w-9 shrink-0 border-r border-rule flex flex-col items-center bg-bg gap-1 py-2"> | |
| {onToggleCollapsed ? ( | |
| <button | |
| type="button" | |
| onClick={onToggleCollapsed} | |
| aria-label="expand conversations" | |
| title="expand conversations" | |
| className="flex items-center justify-center size-7 text-ink-faint hover:text-ink transition-colors" | |
| > | |
| <PanelLeftOpen className="size-4" /> | |
| </button> | |
| ) : null} |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@console/web/src/components/sidebar/ConversationSidebar.tsx` around lines 30 -
41, The collapsed UI currently always renders an "expand" button even when the
optional onToggleCollapsed prop is undefined; update the collapsed branch in
ConversationSidebar (where collapsed is checked and the button with
PanelLeftOpen is rendered) to conditionally render that button only if
onToggleCollapsed is provided, so the interactive control is suppressed when the
callback is absent and avoids a dead/no-op control.
| useEffect(() => { | ||
| if (typeof window === 'undefined') return | ||
| const sync = () => { | ||
| const cw = getContainerWidth(containerRef) | ||
| setContainerWidth(cw) | ||
| setPanelWidths((p) => { | ||
| const hasSpan = selectedSpanIdRef.current !== null | ||
| const handles = hasSpan ? HANDLE_WIDTH * 2 : HANDLE_WIDTH | ||
| const otherForTrace = hasSpan ? p.span : 0 | ||
| const maxTrace = Math.max( | ||
| PANEL_MIN_WIDTH, | ||
| cw - PANEL_NEIGHBOR_MIN_WIDTH - handles - otherForTrace, | ||
| ) | ||
| const nextTrace = Math.max( | ||
| PANEL_MIN_WIDTH, | ||
| Math.min(maxTrace, p.trace), | ||
| ) | ||
| let nextSpan = p.span | ||
| if (hasSpan) { | ||
| const maxSpan = Math.max( | ||
| PANEL_MIN_WIDTH, | ||
| cw - PANEL_NEIGHBOR_MIN_WIDTH - handles - nextTrace, | ||
| ) | ||
| nextSpan = Math.max(PANEL_MIN_WIDTH, Math.min(maxSpan, p.span)) | ||
| } | ||
| if (nextTrace === p.trace && nextSpan === p.span) return p | ||
| return { trace: nextTrace, span: nextSpan } | ||
| }) | ||
| } | ||
| sync() | ||
| window.addEventListener('resize', sync) | ||
| return () => window.removeEventListener('resize', sync) | ||
| }, [containerRef]) |
There was a problem hiding this comment.
Re-clamping is not actually container-aware yet.
The effect only subscribes to window.resize, so panel widths/maxes can go stale when the container width changes due to layout changes (without viewport resize). This breaks the stated container-coupling behavior.
Suggested fix (observe the container directly)
useEffect(() => {
- if (typeof window === 'undefined') return
+ if (typeof window === 'undefined') return
const sync = () => {
const cw = getContainerWidth(containerRef)
setContainerWidth(cw)
setPanelWidths((p) => {
const hasSpan = selectedSpanIdRef.current !== null
const handles = hasSpan ? HANDLE_WIDTH * 2 : HANDLE_WIDTH
const otherForTrace = hasSpan ? p.span : 0
const maxTrace = Math.max(
PANEL_MIN_WIDTH,
cw - PANEL_NEIGHBOR_MIN_WIDTH - handles - otherForTrace,
)
const nextTrace = Math.max(
PANEL_MIN_WIDTH,
Math.min(maxTrace, p.trace),
)
let nextSpan = p.span
if (hasSpan) {
const maxSpan = Math.max(
PANEL_MIN_WIDTH,
cw - PANEL_NEIGHBOR_MIN_WIDTH - handles - nextTrace,
)
nextSpan = Math.max(PANEL_MIN_WIDTH, Math.min(maxSpan, p.span))
}
if (nextTrace === p.trace && nextSpan === p.span) return p
return { trace: nextTrace, span: nextSpan }
})
}
sync()
- window.addEventListener('resize', sync)
- return () => window.removeEventListener('resize', sync)
+ const node = containerRef.current
+ const ro =
+ node && typeof ResizeObserver !== 'undefined'
+ ? new ResizeObserver(sync)
+ : null
+ if (node && ro) ro.observe(node)
+ window.addEventListener('resize', sync)
+ return () => {
+ if (ro) ro.disconnect()
+ window.removeEventListener('resize', sync)
+ }
}, [containerRef])🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@console/web/src/pages/Traces/hooks/useResizablePanels.ts` around lines 191 -
223, The effect in useResizablePanels currently only listens to window.resize so
container-driven layout changes can leave panel widths stale; replace/augment
the window listener by creating a ResizeObserver on containerRef.current (use
getContainerWidth inside the same sync callback) to call sync whenever the
container element's size changes, keep the existing window.resize for viewport
changes, and ensure both the observer and the window listener are cleaned up in
the returned cleanup; update any dependencies accordingly while continuing to
use setContainerWidth, setPanelWidths and selectedSpanIdRef in the same sync
logic.
| }, | ||
| }, | ||
| server: { | ||
| allowedHosts: true, |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Vite 8 official docs, what is the security guidance for server.allowedHosts: true?
💡 Result:
In the official Vite 8 documentation, setting server.allowedHosts to true is strongly discouraged due to significant security risks [1][2]. The documentation explicitly warns that setting this option to true allows any website to send requests to your development server, which makes you vulnerable to DNS rebinding attacks [1][2]. These attacks can allow malicious actors to download your source code and other sensitive content [1][2]. Vite recommends that you always use an explicit list of allowed hosts instead of setting the value to true [1][2]. For further details on the underlying security concern, the documentation references vulnerability GHSA-vg6x-rcgg-rjx6 [1][2].
Citations:
- 1: https://github.com/vitejs/vite/blob/v8.0.8/docs/config/server-options.md
- 2: https://vite.dev/config/server-options
Remove allowedHosts: true to prevent DNS rebinding attacks.
Line 14 sets allowedHosts: true, which disables host filtering in the dev server. This is explicitly discouraged in Vite 8 documentation because it allows any website to send requests to your server, opening the door to DNS rebinding attacks that can expose source code and sensitive content. Use an explicit list of allowed hosts instead.
🔧 Proposed fix
server: {
- allowedHosts: true,
+ // Host checks enabled by default. Add specific hosts only when required
+ // (e.g. via __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS).
proxy: {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| allowedHosts: true, | |
| // Host checks enabled by default. Add specific hosts only when required | |
| // (e.g. via __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS). |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@console/web/vite.config.ts` at line 14, Remove the insecure wildcard host
setting by deleting the allowedHosts: true entry in vite.config.ts and replace
it with an explicit allowlist (or omit the option to use Vite defaults); locate
the dev server config (export default defineConfig -> dev -> allowedHosts) and
set allowedHosts to a concrete array of trusted hostnames/IPs (e.g.,
'localhost', '127.0.0.1', and any required dev host) instead of true to prevent
DNS rebinding.
193eb7b to
e230f3c
Compare
Summary by CodeRabbit
New Features
Bug Fixes & Improvements