Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions apps/desktop/electron/remote-lifecycle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1506,6 +1506,29 @@ test('buildSpawnCommand lockfile publication is POSIX sh (no bash substitution)'
assert.ok(cmd.includes('sed "s/__PID__/${child}/"'), 'pid substitution must use sed')
})

test('buildSpawnCommand does not double-quote the update mutex path', () => {
const cmdAbs = buildSpawnCommand('/x/hermes', 'work', {
hermesHome: '/home/hermes/.hermes',
logPath: spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE),
ownershipId: OWNERSHIP_ID,
lockMetadata: { ownershipId: OWNERSHIP_ID, spawnNonce: SPAWN_NONCE }
})
// Absolute mutexPath is expandRemotePath output ('/home/hermes/.hermes/.hermes-update-in-progress.mutex').
// It must be embedded directly as sys.argv[1] without being wrapped in shq() again,
// which would pass literal quote characters to python and create a directory named `'`.
assert.match(cmdAbs, /python3 -c '[\s\S]+?' '\/home\/hermes\/\.hermes\/\.hermes-update-in-progress\.mutex'/)
assert.doesNotMatch(cmdAbs, /python3 -c '[\s\S]+?' ''\\''/)

const cmdTilde = buildSpawnCommand('/x/hermes', 'work', {
hermesHome: '~/.hermes',
logPath: spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE),
ownershipId: OWNERSHIP_ID,
lockMetadata: { ownershipId: OWNERSHIP_ID, spawnNonce: SPAWN_NONCE }
})
// Tilde mutexPath is expandRemotePath output ("$HOME"'/.hermes/.hermes-update-in-progress.mutex').
assert.match(cmdTilde, /python3 -c '[\s\S]+?' "\$HOME"'\/\.hermes\/\.hermes-update-in-progress\.mutex'/)
})

test('spawnRemoteDashboard removes a token file when upload reporting fails', async () => {
const failure = new Error('channel closed')

Expand Down
5 changes: 3 additions & 2 deletions apps/desktop/electron/remote-lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,8 @@ finally:
// the marker check, spawns the backend, and publishes its initial lockfile.
// Python keeps the descriptor close-on-exec by default and passes it explicitly
// only to the intended outer shell; each detached child closes it before
// execing Hermes.
// execing Hermes. mutexPath is already expandRemotePath() output (shell-quoted
// or "$HOME"'/…' fragment). Embed raw so $HOME expands and quotes are not duplicated.
function withRemoteUpdateMutex(command, mutexPath) {
const script = `
import fcntl,os,subprocess,sys
Expand All @@ -913,7 +914,7 @@ finally:
sys.exit(result.returncode if result is not None else 1)
`.trim()

return `python3 -c ${shq(script)} ${shq(mutexPath)} ${shq(command)}`
return `python3 -c ${shq(script)} ${mutexPath} ${shq(command)}`
}

/**
Expand Down