mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
fix(desktop): connectionCacheKey identity includes remote host (fs cache collision)
connectionCacheKey() keyed the desktop-fs cache on mode:profile:baseUrl only. Local forwarded ports are reusable across different remotes, so two remotes that map to the same 127.0.0.1:<localPort> (e.g. two SSH hosts whose tunnels land on the same local port across reconnects) collide — one host's cached directory listings and file reads get served for the other. Fold the remote host into the identity: remoteHost (user@host for SSH, the real backend host for token/oauth), with a baseUrl fallback. This is a latent bug on main for ANY two remotes sharing a forwarded port, not only SSH — but SSH mode makes it reachable in normal use. Adds vitest coverage: two SSH hosts on the same local port get distinct keys; the no-remoteHost fallback and local key are preserved. vitest deferred (no node_modules in the worktree on this host); the regression guard ships with the fix.
This commit is contained in:
parent
7c21034330
commit
f0693a3232
2 changed files with 30 additions and 1 deletions
|
|
@ -5,6 +5,7 @@ import { $connection } from '@/store/session'
|
|||
import {
|
||||
desktopDefaultCwd,
|
||||
desktopGitRoot,
|
||||
desktopFsCacheKey,
|
||||
readDesktopDir,
|
||||
readDesktopFileDataUrl,
|
||||
readDesktopFileText,
|
||||
|
|
@ -113,4 +114,25 @@ describe('desktop filesystem facade', () => {
|
|||
expect(remoteSelect).not.toHaveBeenCalled()
|
||||
expect(selectPaths).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('cache key distinguishes two SSH hosts that share the same local forwarded port', () => {
|
||||
// Both remotes resolve to the same loopback tunnel baseUrl (the local
|
||||
// forwarded port is reusable across remotes). Without the remoteHost in the
|
||||
// identity these collide and one host's cached fs reads serve the other.
|
||||
$connection.set({ mode: 'remote', baseUrl: 'http://127.0.0.1:50001', remoteHost: 'jonny@mac-mini' } as never)
|
||||
const keyA = desktopFsCacheKey()
|
||||
$connection.set({ mode: 'remote', baseUrl: 'http://127.0.0.1:50001', remoteHost: 'jonny@ubuntu-box' } as never)
|
||||
const keyB = desktopFsCacheKey()
|
||||
|
||||
expect(keyA).not.toBe(keyB)
|
||||
expect(keyA).toContain('mac-mini')
|
||||
expect(keyB).toContain('ubuntu-box')
|
||||
})
|
||||
|
||||
it('cache key falls back to baseUrl when no remoteHost is present', () => {
|
||||
$connection.set({ mode: 'remote', baseUrl: 'https://box.tail1234.ts.net' } as never)
|
||||
expect(desktopFsCacheKey()).toContain('box.tail1234.ts.net')
|
||||
$connection.set(null)
|
||||
expect(desktopFsCacheKey()).toBe('local:')
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -21,7 +21,14 @@ function connectionCacheKey(connection: HermesConnection | null) {
|
|||
if (!connection) {
|
||||
return 'local:'
|
||||
}
|
||||
return `${connection.mode || 'local'}:${connection.profile || ''}:${connection.baseUrl || ''}`
|
||||
// The remote host is part of the cache identity, NOT just the baseUrl. Local
|
||||
// forwarded ports are reusable across different remotes, so two SSH hosts
|
||||
// that happen to map to the same 127.0.0.1:<localPort> would otherwise
|
||||
// collide — serving one host's cached fs reads for the other. remoteHost is
|
||||
// the user@host (SSH) or the real backend host (token/oauth); fall back to
|
||||
// baseUrl for safety.
|
||||
const host = connection.remoteHost || connection.baseUrl || ''
|
||||
return `${connection.mode || 'local'}:${connection.profile || ''}:${host}:${connection.baseUrl || ''}`
|
||||
}
|
||||
|
||||
export function desktopFsCacheKey() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue