fix(cli): require an absolute path when setting a project up on an SSH host

Routing --host ssh:* to the remote registration made relative paths newly
reachable there, and they were resolved against the client cwd — registering a
path that names the wrong machine.

Refs #11163
This commit is contained in:
Neil
2026-09-02 16:20:33 -07:00
parent 69a502d01c
commit f7fb1a64fc
2 changed files with 38 additions and 3 deletions
+7 -3
View File
@@ -10,7 +10,7 @@ import type {
ProjectHostSetupUpdateArgs,
ProjectHostSetupUpdateResult
} from '../../shared/project-types'
import type { ExecutionHostId } from '../../shared/execution-host'
import { getSshTargetIdForExecutionHost, type ExecutionHostId } from '../../shared/execution-host'
import type { RepoKind } from '../../shared/repo-types'
import type { CommandHandler, HandlerContext } from '../dispatch'
import {
@@ -111,10 +111,14 @@ export const PROJECT_HANDLERS: Record<string, CommandHandler> = {
},
'project setup-existing-folder': async ({ flags, client, cwd, json }) => {
const rawPath = getRequiredStringFlag(flags, 'path')
const hostId = getRequiredHostId(flags)
// An SSH host's filesystem is not the CLI's, so resolving a relative path against the client
// cwd would register a path that names the wrong machine.
const pathIsOffClient = client.isRemote || getSshTargetIdForExecutionHost(hostId) !== null
const args: ProjectHostSetupExistingFolderArgs = {
projectId: getRequiredStringFlag(flags, 'project'),
hostId: getRequiredHostId(flags),
path: resolveRepoPathArgument(rawPath, cwd, client.isRemote, 'Remote project setup'),
hostId,
path: resolveRepoPathArgument(rawPath, cwd, pathIsOffClient, 'Remote project setup'),
kind: getOptionalRepoKind(flags),
displayName: getOptionalStringFlag(flags, 'display-name')
}
+31
View File
@@ -481,6 +481,37 @@ describe('orca cli worktree awareness', () => {
process.exitCode = priorExitCode
})
it('rejects SSH project setup relative paths, which name the client filesystem', async () => {
// A local CLI reaching an `ssh:*` host is still off-client: resolving `./orca` against the
// CLI cwd would register a path that exists on the wrong machine.
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const errSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
const priorExitCode = process.exitCode
await main(
[
'project',
'setup-existing-folder',
'--project',
'github:stablyai/orca',
'--host',
'ssh:openclaw',
'--path',
'./orca',
'--json'
],
'/tmp/repo'
)
expect(callMock).not.toHaveBeenCalled()
expect([...logSpy.mock.calls, ...errSpy.mock.calls].flat().join('\n')).toContain(
'Remote project setup requires --path to be an absolute path on the remote server.'
)
expect(process.exitCode).toBe(1)
process.exitCode = priorExitCode
})
it('rejects remote repo.add relative paths instead of resolving against client cwd', async () => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const errSpy = vi.spyOn(console, 'error').mockImplementation(() => {})