fix(desktop): refuse a foreign backend's session token after readiness

The served-token fallback adopts whatever token the dashboard HTML
injects. That is correct when our own child regenerated the token (env
pin lost across a shell-wrapped spawn), but wrong when the readiness
probe answered from a process we did not spawn: /api/status is public,
so an orphaned dashboard squatting the port passes waitForHermes while
our child dies on the bind conflict. Silently adopting that process's
token would authenticate the renderer against a foreign backend,
possibly on the wrong profile.

Discriminate on child liveness: the desktop pins
HERMES_DASHBOARD_SESSION_TOKEN on every spawn, so a live child always
serves our token. Served-token mismatch + dead child = foreign backend;
fail the boot loudly instead of connecting. Mismatch + live child keeps
the adopt-served-token salvage from #43720.
This commit is contained in:
Brooklyn Nicholson
2026-06-11 18:18:22 -05:00
parent 7a2d498b9d
commit e3ed7722b5
3 changed files with 73 additions and 1 deletions
@@ -12,6 +12,7 @@ const {
dashboardIndexUrl,
extractInjectedDashboardToken,
fetchPublicText,
isForeignBackendToken,
resolveServedDashboardToken
} = require('./dashboard-token.cjs')
@@ -87,3 +88,23 @@ test('resolveServedDashboardToken propagates fetch errors so callers can fall ba
test('fetchPublicText rejects unsupported protocols', async () => {
await assert.rejects(() => fetchPublicText('file:///tmp/index.html'), /Unsupported Hermes backend URL protocol/)
})
test('isForeignBackendToken flags a mismatched token from a dead child', () => {
assert.equal(isForeignBackendToken({ servedToken: 'other', spawnToken: 'mine', childAlive: false }), true)
})
test('isForeignBackendToken trusts a mismatched token while our child is alive', () => {
// Live child + different token = our own backend regenerated the token
// because the env pin did not survive the spawn. Adopting it is correct.
assert.equal(isForeignBackendToken({ servedToken: 'other', spawnToken: 'mine', childAlive: true }), false)
})
test('isForeignBackendToken trusts a matching token regardless of liveness', () => {
assert.equal(isForeignBackendToken({ servedToken: 'mine', spawnToken: 'mine', childAlive: false }), false)
assert.equal(isForeignBackendToken({ servedToken: 'mine', spawnToken: 'mine', childAlive: true }), false)
})
test('isForeignBackendToken ignores an absent served token', () => {
assert.equal(isForeignBackendToken({ servedToken: null, spawnToken: 'mine', childAlive: false }), false)
assert.equal(isForeignBackendToken({ servedToken: '', spawnToken: 'mine', childAlive: false }), false)
})