mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 18:37:24 +00:00
fix(cloud): the held-agent cancel confirmation shows only over its own workspace (N-03 defense in depth)
This commit is contained in:
@@ -291,6 +291,8 @@ describe('NOACCT-MISLABEL: no Claude account is a setup hold, never "didn’t st
|
||||
const { toast } = await import('sonner')
|
||||
vi.mocked(toast).mockClear()
|
||||
useAppStore.setState({
|
||||
activeView: 'terminal',
|
||||
activeWorktreeId: 'w1',
|
||||
tabsByWorktree: {
|
||||
w1: [makeTerminalTab({ id: toWebTerminalSurfaceTabId('h1'), worktreeId: 'w1' })]
|
||||
}
|
||||
@@ -302,4 +304,30 @@ describe('NOACCT-MISLABEL: no Claude account is a setup hold, never "didn’t st
|
||||
await result
|
||||
expect(toast).toHaveBeenCalledWith('The agent didn’t start. The shell is still open.')
|
||||
})
|
||||
|
||||
it('never confirms a cancel over another workspace or Settings (N-03)', async () => {
|
||||
const { useAppStore } = await import('@/store')
|
||||
const { makeTerminalTab } = await import('@/store/terminals/terminal-row.test-fixture')
|
||||
const { toast } = await import('sonner')
|
||||
const tabs = {
|
||||
w1: [makeTerminalTab({ id: toWebTerminalSurfaceTabId('h1'), worktreeId: 'w1' })]
|
||||
}
|
||||
const cancelHold = async (): Promise<void> => {
|
||||
setOrcaCloudAgentAccountsStateForTest(accounts({ state: 'none' }))
|
||||
const result = createWithCloudAgentHold(CREATE_AGENT, hostCreate())
|
||||
await flush()
|
||||
releaseCloudAgentHold(cloudTabHoldKey(toWebTerminalSurfaceTabId('h1')), 'cancel')
|
||||
await result
|
||||
}
|
||||
vi.mocked(toast).mockClear()
|
||||
useAppStore.setState({
|
||||
activeView: 'terminal',
|
||||
activeWorktreeId: 'other',
|
||||
tabsByWorktree: tabs
|
||||
})
|
||||
await cancelHold()
|
||||
useAppStore.setState({ activeView: 'settings', activeWorktreeId: 'w1', tabsByWorktree: tabs })
|
||||
await cancelHold()
|
||||
expect(toast).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -83,7 +83,8 @@ export async function createWithCloudAgentHold(
|
||||
// NOACCT-MISLABEL: the confirmation answers the person's own Cancel, while the shell is still
|
||||
// there. A hold that ended because its tab or workspace went away (deleted, archived, closed)
|
||||
// says nothing: there is no shell left, and nothing failed to start.
|
||||
if (isTabOpen(args.worktreeId, tabId)) {
|
||||
// Defense in depth (N-03): only over its own workspace, never over another one or Settings.
|
||||
if (isTabOpen(args.worktreeId, tabId) && workspaceOnScreen(args.worktreeId)) {
|
||||
toast(
|
||||
translate(
|
||||
'agentSignInStrip.cancelledToast',
|
||||
@@ -122,6 +123,12 @@ export function isTabOpen(worktreeId: string, tabId: string): boolean {
|
||||
return (useAppStore.getState().tabsByWorktree[worktreeId] ?? []).some((tab) => tab.id === tabId)
|
||||
}
|
||||
|
||||
/** The workspace is the one in front, in the workspace view (not Settings or another page). */
|
||||
function workspaceOnScreen(worktreeId: string): boolean {
|
||||
const state = useAppStore.getState()
|
||||
return state.activeView === 'terminal' && state.activeWorktreeId === worktreeId
|
||||
}
|
||||
|
||||
// The agent's tab can reach the store after the placeholder's close (a create's sync is slower).
|
||||
const AGENT_TAB_FOCUS_WAIT_MS = 10_000
|
||||
|
||||
|
||||
Reference in New Issue
Block a user