mirror of
https://github.com/stablyai/orca.git
synced 2026-10-29 16:17:51 +00:00
* fix(ssh): stop SFTP stream errors crashing main and bound the relay socket path
inside the protocol parser. Every transfer removed its listener on settle, so a
STATUS reply that arrived late - the normal case behind a jump host that chroots
its SFTP subsystem - threw synchronously out of Socket.emit('data') and killed
the main process. Keep one durable listener per stream, and report a sandboxed
SFTP namespace with an actionable message instead of a bare 'file does not
exist'.
104 macOS) and bind failed with a bare 'listen EINVAL'. Fall back to a per-uid
base whose length does not depend on $HOME, keeping the hashed socket name
intact.
* fix(ssh): validate the short socket dir before mutating it
* fix(ssh): keep the SFTP session guarded, scope the relocated socket, narrow the chroot verdict
Three review findings.
The CLI-launcher install ran writeStringViaSftp in a loop over a bare conn.sftp().
That helper removes its own session 'error' listener at each settle, so between
files and after the last one the emitter carried none -- and ssh2 raises a late
STATUS reply synchronously out of Protocol.parse, which is the uncaught exception
that kills main (#15479). The inline loop it replaced leaked one listener per file
and covered this by accident. Extract writeStringsViaSftp, which owns the session
latch, and share that latch with runSftpFallbackTransfer.
SSH_FX_PERMISSION_DENIED is a mode/ownership refusal on a path the subsystem can
see, not evidence of a chroot; sftp-namespace-resolution already treats only
NO_SUCH_FILE as conclusive. Narrow the predicate to code 2 so a read-only home
stops being reported as a bastion misconfiguration.
The relocated socket had no version dimension. relaySocketNameForInstanceId hashes
the target, not the build, and under $HOME the enclosing relay-<fullVersion> dir
supplied the rest -- so the short form made the path stable across updates. The
next build would bind the path the previous relay still holds, the handshake would
mismatch, and a relay holding live work would raise RelayEndpointHeldError with no
way through. Add a hashed version segment under the short base, mirroring the
relay-*/<sock> shape so one pattern serves both, and teach the superseded sweep and
force-stop about that base. The relocated tree now also gets reclaimed: nothing
else walks it.
* fix(i18n): restore the activity-options key the rebase dropped
* fix(i18n): union en.json with main so the rebase cannot drop keys
43 lines
1.8 KiB
TypeScript
43 lines
1.8 KiB
TypeScript
import type { SshConnection } from './ssh-connection'
|
|
import { shellEscape } from './ssh-connection-utils'
|
|
import { execCommand } from './ssh-relay-deploy-helpers'
|
|
import { relaySocketNameForInstanceId } from './ssh-relay-instance-id'
|
|
import { SHORT_RELAY_SOCKET_DIR_PREFIX } from './relay-socket-path-limit'
|
|
|
|
export async function forceStopRelayForTarget(
|
|
conn: SshConnection,
|
|
relayInstanceId: string
|
|
): Promise<void> {
|
|
const sockName = relaySocketNameForInstanceId(relayInstanceId)
|
|
const escapedSockName = shellEscape(sockName)
|
|
const script = [
|
|
`sock_name=${escapedSockName}`,
|
|
'base="${HOME}/.orca-remote"',
|
|
// Why: a long $HOME moves the socket to the sun_path-safe short base (#10726); reset must reach it there too.
|
|
`short_base="${SHORT_RELAY_SOCKET_DIR_PREFIX}$(id -u 2>/dev/null)"`,
|
|
'if [ -d "$base" ] || [ -d "$short_base" ]; then',
|
|
' for sock in "$base"/relay-*/"$sock_name" "$base"/"$sock_name" "$short_base"/relay-*/"$sock_name"; do',
|
|
' [ -S "$sock" ] || continue',
|
|
' pid=""',
|
|
// Why: lsof ORs selectors by default; -a prevents reset from targeting
|
|
// every Unix-socket holder instead of only the per-relay socket (#8762).
|
|
' if command -v lsof >/dev/null 2>&1; then',
|
|
' pid=$(lsof -t -a -U "$sock" 2>/dev/null | tr "\\n" " ")',
|
|
' fi',
|
|
' if [ -z "$pid" ] && command -v pgrep >/dev/null 2>&1; then',
|
|
' pid=$(pgrep -f "$sock_name" 2>/dev/null | ' +
|
|
'awk -v self="$$" -v parent="$PPID" \'$1 != self && $1 != parent\' | tr "\\n" " ")',
|
|
' fi',
|
|
' if [ -n "$pid" ]; then',
|
|
' kill -TERM $pid 2>/dev/null || true',
|
|
' sleep 0.2',
|
|
' kill -KILL $pid 2>/dev/null || true',
|
|
' fi',
|
|
' rm -f "$sock"',
|
|
' done',
|
|
'fi'
|
|
].join('\n')
|
|
|
|
await execCommand(conn, script)
|
|
}
|