mirror of
https://github.com/stablyai/orca.git
synced 2026-09-21 16:02:20 +00:00
* Widen Windows shim ratchet to detect package bin spawns Follow local program expressions into node_modules/.bin while preserving the existing literal check, roots, and allow-list. Document static-analysis limits and cover unsafe and resolver-based invocations. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(scripts): fold dot segments before matching node_modules/.bin The predicate joins call arguments textually, so a literal '..' segment hid a path that resolves into node_modules/.bin at runtime. Folds '.' and '..' (and Windows separators) first. A '..' that genuinely escapes .bin still does not match. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * style(scripts): use .at(-1) in the dot-segment fold oxlint's prefer-at rule; the repo-wide lint gate is an error, not a warning. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
71 lines
2.6 KiB
JavaScript
71 lines
2.6 KiB
JavaScript
import { describe, expect, it } from 'vitest'
|
|
import { hasNodeModulesBinSpawn } from './windows-bin-spawn-predicate.mjs'
|
|
|
|
describe('node_modules bin spawn predicate', () => {
|
|
it.each(['spawn', 'spawnSync', 'execFile', 'execFileSync'])(
|
|
'catches %s through local aliases',
|
|
(method) => {
|
|
expect(
|
|
hasNodeModulesBinSpawn(`
|
|
const bin = path.join(root, 'node_modules', '.bin', 'oxfmt')
|
|
const program = bin
|
|
cp.${method}(program, ['--write', file])
|
|
`)
|
|
).toBe(true)
|
|
}
|
|
)
|
|
|
|
it.each([
|
|
"path.resolve(root, 'node_modules/.bin/oxfmt')",
|
|
'`' + '${root}/node_modules/.bin/oxfmt' + '`',
|
|
"root + '/node_modules/' + '.bin/oxfmt'",
|
|
"'C:\\\\repo\\\\node_modules\\\\.bin\\\\oxfmt'",
|
|
"enabled ? 'node_modules/.bin/oxfmt' : 'oxfmt'"
|
|
])('catches the path expression %s', (expression) => {
|
|
expect(hasNodeModulesBinSpawn(`execFileSync(${expression}, [])`)).toBe(true)
|
|
})
|
|
|
|
it.each([
|
|
"// spawnSync('node_modules/.bin/oxfmt', [])",
|
|
'const example = "spawnSync(\'node_modules/.bin/oxfmt\', [])"',
|
|
"const bin = path.join(root, 'node_modules', '.bin', 'oxfmt'); existsSync(bin)",
|
|
"spawnSync(process.execPath, ['node_modules/.bin/oxfmt'])",
|
|
"spawnSync('node_modules/.binary/oxfmt', [])",
|
|
"spawnSync('other_node_modules/.bin/oxfmt', [])",
|
|
`const invocation = resolveOxcCliInvocation('oxfmt', 'oxfmt', root)
|
|
execFileSync(invocation.command, [...invocation.prefixArgs, '--write', file])`,
|
|
'const a = b; const b = a; spawnSync(a, [])'
|
|
])('does not flag non-program paths or safe invocations: %s', (contents) => {
|
|
expect(hasNodeModulesBinSpawn(contents)).toBe(false)
|
|
})
|
|
|
|
it('folds dot segments, so a .. detour into node_modules/.bin is still caught', () => {
|
|
expect(
|
|
hasNodeModulesBinSpawn(
|
|
"import { execFileSync } from 'node:child_process'\n" +
|
|
"import path from 'node:path'\n" +
|
|
"execFileSync(path.join(root, 'node_modules', 'tools', '..', '.bin', 'oxfmt'), [])\n"
|
|
)
|
|
).toBe(true)
|
|
})
|
|
|
|
it('folds Windows-separator dot segments too', () => {
|
|
expect(
|
|
hasNodeModulesBinSpawn(
|
|
"import { execFileSync } from 'node:child_process'\n" +
|
|
"execFileSync('root\\\\node_modules\\\\tools\\\\..\\\\.bin\\\\oxfmt', [])\n"
|
|
)
|
|
).toBe(true)
|
|
})
|
|
|
|
it('does not fold a .. back into .bin when it escapes the directory', () => {
|
|
expect(
|
|
hasNodeModulesBinSpawn(
|
|
"import { execFileSync } from 'node:child_process'\n" +
|
|
"import path from 'node:path'\n" +
|
|
"execFileSync(path.join(root, 'node_modules', '.bin', '..', 'oxfmt', 'cli.js'), [])\n"
|
|
)
|
|
).toBe(false)
|
|
})
|
|
})
|