mirror of
https://github.com/stablyai/orca.git
synced 2026-10-22 08:03:37 +00:00
fix(terminal): harden shim tombstone path lookup
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
const SHELL_DOLLAR = '$'
|
||||
|
||||
const POSIX_TOMBSTONE = String.raw`#!/usr/bin/env bash
|
||||
set -u
|
||||
|
||||
command_name="__ORCA_COMMAND__"
|
||||
wrapper_dir="$(cd -- "$(dirname -- "${SHELL_DOLLAR}{BASH_SOURCE[0]}")" && pwd)"
|
||||
legacy_wrapper_dir="${SHELL_DOLLAR}{ORCA_ATTRIBUTION_SHIM_DIR:-}"
|
||||
cleaned_path="${SHELL_DOLLAR}{PATH:-}"
|
||||
|
||||
filter_path() {
|
||||
local legacy_target="$legacy_wrapper_dir"
|
||||
while [[ "$legacy_target" != "/" && "$legacy_target" == */ ]]; do
|
||||
legacy_target="${SHELL_DOLLAR}{legacy_target%/}"
|
||||
done
|
||||
local remaining="$cleaned_path"
|
||||
local filtered_path=""
|
||||
local separator=""
|
||||
path_entry_kept=0
|
||||
local entry normalized candidate has_more
|
||||
while true; do
|
||||
if [[ "$remaining" == *:* ]]; then
|
||||
entry="${SHELL_DOLLAR}{remaining%%:*}"
|
||||
remaining="${SHELL_DOLLAR}{remaining#*:}"
|
||||
has_more=1
|
||||
else
|
||||
entry="$remaining"
|
||||
has_more=0
|
||||
fi
|
||||
normalized="$entry"
|
||||
while [[ "$normalized" != "/" && "$normalized" == */ ]]; do
|
||||
normalized="${SHELL_DOLLAR}{normalized%/}"
|
||||
done
|
||||
candidate="${SHELL_DOLLAR}{entry:-.}"
|
||||
if [[ -n "$legacy_target" && "$normalized" == "$legacy_target" ]]; then
|
||||
:
|
||||
elif [[ "$candidate" -ef "$wrapper_dir" ]]; then
|
||||
:
|
||||
else
|
||||
filtered_path+="$separator$entry"
|
||||
separator=":"
|
||||
path_entry_kept=1
|
||||
fi
|
||||
[[ "$has_more" == 1 ]] || break
|
||||
done
|
||||
cleaned_path="$filtered_path"
|
||||
}
|
||||
|
||||
filter_path
|
||||
unset ORCA_ENABLE_GIT_ATTRIBUTION ORCA_GIT_COMMIT_TRAILER ORCA_GH_PR_FOOTER
|
||||
unset ORCA_GH_ISSUE_FOOTER ORCA_ATTRIBUTION_SHIM_DIR ORCA_REAL_GIT ORCA_REAL_GH ORCA_ATTRIBUTION_BYPASS
|
||||
|
||||
real_command=""
|
||||
if [[ "$path_entry_kept" == 1 ]]; then
|
||||
real_command="$(PATH="$cleaned_path" type -P "$command_name" || true)"
|
||||
fi
|
||||
if [[ -n "$real_command" && "$real_command" -ef "${SHELL_DOLLAR}{BASH_SOURCE[0]}" ]]; then
|
||||
real_command=""
|
||||
fi
|
||||
if [[ -z "$real_command" ]]; then
|
||||
printf 'Orca compatibility wrapper could not locate %s on PATH.\n' "$command_name" >&2
|
||||
exit 127
|
||||
fi
|
||||
PATH="$cleaned_path" exec "$real_command" "$@"
|
||||
`
|
||||
|
||||
export function renderLegacyTerminalPosixTombstone(command: 'git' | 'gh'): string {
|
||||
return POSIX_TOMBSTONE.replaceAll('__ORCA_COMMAND__', command)
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
mkdirSync,
|
||||
mkdtempSync,
|
||||
readFileSync,
|
||||
rmSync,
|
||||
statSync,
|
||||
writeFileSync
|
||||
} from 'node:fs'
|
||||
@@ -22,16 +23,27 @@ const itOnPosix = process.platform === 'win32' ? it.skip : it
|
||||
const itOnPosixNonRoot = process.platform === 'win32' || process.getuid?.() === 0 ? it.skip : it
|
||||
|
||||
describe('legacy terminal shim neutralization', () => {
|
||||
const tempRoots: string[] = []
|
||||
|
||||
const makeUserDataDir = (): string => {
|
||||
const userData = mkdtempSync(join(tmpdir(), 'orca-legacy-shim-'))
|
||||
tempRoots.push(userData)
|
||||
return userData
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
__resetLegacyTerminalShimNeutralizationForTests()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers()
|
||||
for (const tempRoot of tempRoots.splice(0)) {
|
||||
rmSync(tempRoot, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('atomically replaces the legacy command paths with executable tombstones', () => {
|
||||
const userData = mkdtempSync(join(tmpdir(), 'orca-legacy-shim-'))
|
||||
const userData = makeUserDataDir()
|
||||
const legacyRoot = join(userData, 'orca-terminal-attribution')
|
||||
const posixDir = join(legacyRoot, 'posix')
|
||||
const win32Dir = join(legacyRoot, 'win32')
|
||||
@@ -58,7 +70,7 @@ describe('legacy terminal shim neutralization', () => {
|
||||
})
|
||||
|
||||
it('rejects stale Windows real-command paths inside the wrapper directory', () => {
|
||||
const userData = mkdtempSync(join(tmpdir(), 'orca-legacy-shim-'))
|
||||
const userData = makeUserDataDir()
|
||||
const win32Dir = join(userData, 'orca-terminal-attribution', 'win32')
|
||||
|
||||
neutralizeLegacyTerminalShimDir(userData)
|
||||
@@ -76,7 +88,7 @@ describe('legacy terminal shim neutralization', () => {
|
||||
})
|
||||
|
||||
it('removes every Windows PATH occurrence of both captured wrapper directories', () => {
|
||||
const userData = mkdtempSync(join(tmpdir(), 'orca-legacy-shim-'))
|
||||
const userData = makeUserDataDir()
|
||||
const win32Dir = join(userData, 'orca-terminal-attribution', 'win32')
|
||||
|
||||
neutralizeLegacyTerminalShimDir(userData)
|
||||
@@ -100,7 +112,7 @@ describe('legacy terminal shim neutralization', () => {
|
||||
})
|
||||
|
||||
it('does not throw when the legacy directory is absent', () => {
|
||||
const userData = mkdtempSync(join(tmpdir(), 'orca-legacy-shim-'))
|
||||
const userData = makeUserDataDir()
|
||||
|
||||
expect(() => neutralizeLegacyTerminalShimDir(userData)).not.toThrow()
|
||||
expect(existsSync(join(userData, 'orca-terminal-attribution', 'posix', 'git'))).toBe(true)
|
||||
@@ -108,7 +120,7 @@ describe('legacy terminal shim neutralization', () => {
|
||||
|
||||
itOnPosixNonRoot('retries a startup failure in-process and latches after success', async () => {
|
||||
vi.useFakeTimers()
|
||||
const userData = mkdtempSync(join(tmpdir(), 'orca-legacy-shim-'))
|
||||
const userData = makeUserDataDir()
|
||||
const posixDir = join(userData, 'orca-terminal-attribution', 'posix')
|
||||
const gitWrapper = join(posixDir, 'git')
|
||||
mkdirSync(posixDir, { recursive: true })
|
||||
@@ -133,8 +145,8 @@ describe('legacy terminal shim neutralization', () => {
|
||||
}
|
||||
})
|
||||
|
||||
itOnPosix('keeps a real Bash command hash working as an inert pass-through', async () => {
|
||||
const userData = mkdtempSync(join(tmpdir(), 'orca-legacy-shim-'))
|
||||
itOnPosix('keeps a real Bash command hash working with trailing PATH separators', async () => {
|
||||
const userData = makeUserDataDir()
|
||||
const shimDir = join(userData, 'orca-terminal-attribution', 'posix')
|
||||
const shimGit = join(shimDir, 'git')
|
||||
const realBin = join(userData, 'real-bin')
|
||||
@@ -148,12 +160,13 @@ describe('legacy terminal shim neutralization', () => {
|
||||
{ mode: 0o755 }
|
||||
)
|
||||
const child = spawn('bash', ['--noprofile', '--norc'], {
|
||||
cwd: shimDir,
|
||||
env: {
|
||||
...process.env,
|
||||
PATH: `${shimDir}:${realBin}:${process.env.PATH ?? ''}`,
|
||||
PATH: `${shimDir}//::${realBin}:${process.env.PATH ?? ''}`,
|
||||
ORCA_ENABLE_GIT_ATTRIBUTION: '1',
|
||||
ORCA_GIT_COMMIT_TRAILER: 'Co-authored-by: Orca <help@stably.ai>',
|
||||
ORCA_ATTRIBUTION_SHIM_DIR: shimDir
|
||||
ORCA_ATTRIBUTION_SHIM_DIR: ''
|
||||
},
|
||||
stdio: ['pipe', 'pipe', 'pipe']
|
||||
})
|
||||
@@ -168,14 +181,23 @@ describe('legacy terminal shim neutralization', () => {
|
||||
stderr += chunk
|
||||
})
|
||||
const ready = waitForOutput(child.stdout, '__ORCA_HASH_READY__\n')
|
||||
const closed = new Promise<number | null>((resolve) => child.once('close', resolve))
|
||||
child.stdin.write(`hash -p ${quoteBash(shimGit)} git\nprintf '__ORCA_HASH_READY__\\n'\n`)
|
||||
|
||||
await ready
|
||||
try {
|
||||
await ready
|
||||
} catch (error) {
|
||||
child.kill('SIGKILL')
|
||||
throw error
|
||||
}
|
||||
neutralizeLegacyTerminalShimDir(userData)
|
||||
const closed = waitForChildClose(child, 2_000)
|
||||
child.stdin.end("printf 'stdin payload\\n' | git commit -m 'subject with spaces'; exit $?\n")
|
||||
|
||||
expect(await closed).toBe(23)
|
||||
try {
|
||||
expect(await closed).toBe(23)
|
||||
} finally {
|
||||
child.kill('SIGKILL')
|
||||
}
|
||||
expect(stdout).toContain('arg=<commit>\narg=<-m>\narg=<subject with spaces>\nstdin payload\n')
|
||||
expect(stdout).not.toContain('Co-authored-by: Orca')
|
||||
expect(stderr).toBe('fixture stderr\n')
|
||||
@@ -303,3 +325,19 @@ function waitForOutput(stream: NodeJS.ReadableStream, marker: string): Promise<v
|
||||
stream.on('end', onEnd)
|
||||
})
|
||||
}
|
||||
|
||||
function waitForChildClose(
|
||||
child: ReturnType<typeof spawn>,
|
||||
timeoutMs: number
|
||||
): Promise<number | null> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
child.kill('SIGKILL')
|
||||
reject(new Error(`Bash did not exit within ${timeoutMs}ms`))
|
||||
}, timeoutMs)
|
||||
child.once('close', (exitCode) => {
|
||||
clearTimeout(timeout)
|
||||
resolve(exitCode)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import {
|
||||
LEGACY_TERMINAL_ATTRIBUTION_BYPASS_ENV_KEY,
|
||||
LEGACY_TERMINAL_ATTRIBUTION_ENABLE_ENV_KEY
|
||||
} from '../../shared/legacy-terminal-attribution-env'
|
||||
import { renderLegacyTerminalPosixTombstone } from './legacy-terminal-posix-tombstone'
|
||||
|
||||
const LEGACY_SHIM_ROOT_DIR = 'orca-terminal-attribution'
|
||||
const LEGACY_SHIM_VERSION = '7'
|
||||
const NEUTRALIZATION_RETRY_DELAYS_MS = [1_000, 5_000, 15_000, 30_000]
|
||||
const SHELL_DOLLAR = '$'
|
||||
export const LEGACY_TERMINAL_SHIM_ENV_KEYS = [
|
||||
'ORCA_ENABLE_GIT_ATTRIBUTION',
|
||||
'ORCA_GIT_COMMIT_TRAILER',
|
||||
@@ -23,43 +23,6 @@ export const LEGACY_TERMINAL_SHIM_REMOTE_ENV_KEYS = [
|
||||
LEGACY_TERMINAL_ATTRIBUTION_ENABLE_ENV_KEY
|
||||
] as const
|
||||
|
||||
const POSIX_PASSTHROUGH_WRAPPER = String.raw`#!/usr/bin/env bash
|
||||
set -u
|
||||
|
||||
command_name="__ORCA_COMMAND__"
|
||||
wrapper_dir="$(cd -- "$(dirname -- "${SHELL_DOLLAR}{BASH_SOURCE[0]}")" && pwd)"
|
||||
legacy_wrapper_dir="${SHELL_DOLLAR}{ORCA_ATTRIBUTION_SHIM_DIR:-}"
|
||||
cleaned_path="${SHELL_DOLLAR}{PATH:-}"
|
||||
|
||||
remove_path_entry() {
|
||||
local entry="$1"
|
||||
[[ -n "$entry" ]] || return
|
||||
while [[ "$cleaned_path" == "$entry" || "$cleaned_path" == "$entry":* || "$cleaned_path" == *:"$entry" || "$cleaned_path" == *:"$entry":* ]]; do
|
||||
if [[ "$cleaned_path" == "$entry" ]]; then
|
||||
cleaned_path=""
|
||||
elif [[ "$cleaned_path" == "$entry":* ]]; then
|
||||
cleaned_path="${SHELL_DOLLAR}{cleaned_path#"$entry":}"
|
||||
elif [[ "$cleaned_path" == *:"$entry" ]]; then
|
||||
cleaned_path="${SHELL_DOLLAR}{cleaned_path%:"$entry"}"
|
||||
else
|
||||
cleaned_path="${SHELL_DOLLAR}{cleaned_path//:"$entry":/:}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
remove_path_entry "$legacy_wrapper_dir"
|
||||
remove_path_entry "$wrapper_dir"
|
||||
unset ORCA_ENABLE_GIT_ATTRIBUTION ORCA_GIT_COMMIT_TRAILER ORCA_GH_PR_FOOTER
|
||||
unset ORCA_GH_ISSUE_FOOTER ORCA_ATTRIBUTION_SHIM_DIR ORCA_REAL_GIT ORCA_REAL_GH ORCA_ATTRIBUTION_BYPASS
|
||||
|
||||
real_command="$(PATH="$cleaned_path" type -P "$command_name" || true)"
|
||||
if [[ -z "$real_command" ]]; then
|
||||
printf 'Orca compatibility wrapper could not locate %s on PATH.\n' "$command_name" >&2
|
||||
exit 127
|
||||
fi
|
||||
PATH="$cleaned_path" exec "$real_command" "$@"
|
||||
`
|
||||
|
||||
const WIN32_PASSTHROUGH_WRAPPER = String.raw`@echo off
|
||||
setlocal
|
||||
set "orca_real=%ORCA_REAL___ORCA_UPPER_COMMAND__%"
|
||||
@@ -179,13 +142,9 @@ function writeNeutralWrappers(rootDir: string): void {
|
||||
const win32Dir = join(rootDir, 'win32')
|
||||
mkdirSync(posixDir, { recursive: true })
|
||||
mkdirSync(win32Dir, { recursive: true })
|
||||
for (const command of ['git', 'gh']) {
|
||||
for (const command of ['git', 'gh'] as const) {
|
||||
const upperCommand = command.toUpperCase()
|
||||
writeFileAtomically(
|
||||
join(posixDir, command),
|
||||
POSIX_PASSTHROUGH_WRAPPER.replaceAll('__ORCA_COMMAND__', command),
|
||||
0o755
|
||||
)
|
||||
writeFileAtomically(join(posixDir, command), renderLegacyTerminalPosixTombstone(command), 0o755)
|
||||
writeFileAtomically(
|
||||
join(win32Dir, `${command}.cmd`),
|
||||
renderWindowsWrapper(WIN32_PASSTHROUGH_WRAPPER, command, upperCommand),
|
||||
|
||||
Reference in New Issue
Block a user