mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-08-28 05:25:25 +00:00
Some checks are pending
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Gitleaks / gitleaks (push) Waiting to run
Publish / Classify release event (push) Waiting to run
Publish / RC guard (marker + release-PR skip) (push) Blocked by required conditions
Publish / ci (push) Blocked by required conditions
Publish / Publish to npm (push) Blocked by required conditions
Publish / Build & Push RC Docker images (push) Blocked by required conditions
Scorecard / Scorecard analysis (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-cli) (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-web) (push) Waiting to run
104 lines
4.1 KiB
TypeScript
104 lines
4.1 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { spawn } from 'node:child_process';
|
|
import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { composeWin32Command } from '../../src/core/embeddings/runtime-install.js';
|
|
|
|
/**
|
|
* Real-spawn round-trip proving the on-demand npm install delivers its args to
|
|
* the child process intact — including shell-dangerous ones — on EVERY platform,
|
|
* via the exact mechanism `installEmbeddingRuntime` uses for that platform (#2372):
|
|
*
|
|
* - **win32**: `composeWin32Command` + `spawn(string, {shell:true})`, exercising
|
|
* the full `cmd.exe /c` → `.cmd %*` re-parse → node argv chain (the npm.cmd /
|
|
* BatBadBut surface). The pure `quoteWin32Arg` tests only check the string
|
|
* against our *model* of cmd.exe; this checks it against real cmd.exe.
|
|
* - **linux/macos**: the array form `spawn(cmd, args)` with **no shell**, so the
|
|
* args reach the child through `execve` untouched — no quoting, no shell to
|
|
* inject through. This also guards against a regression to `shell:true` on
|
|
* POSIX (which would let `a&b` split).
|
|
*
|
|
* Runs on all three platforms: the full ubuntu suite covers Linux, and the
|
|
* cross-platform runner (scripts/cross-platform-tests.ts) covers windows + macos.
|
|
*/
|
|
|
|
interface CaptureOpts {
|
|
command: string;
|
|
args?: string[];
|
|
commandLine?: string;
|
|
cwd: string;
|
|
shell: boolean;
|
|
}
|
|
|
|
const capture = (opts: CaptureOpts): Promise<string[]> =>
|
|
new Promise<string[]>((resolve, reject) => {
|
|
const child = opts.shell
|
|
? spawn(opts.commandLine as string, {
|
|
cwd: opts.cwd,
|
|
shell: true,
|
|
windowsHide: true,
|
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
})
|
|
: spawn(opts.command, opts.args as string[], {
|
|
cwd: opts.cwd,
|
|
windowsHide: true,
|
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
});
|
|
let out = '';
|
|
let err = '';
|
|
child.stdout?.on('data', (c: Buffer) => (out += c.toString()));
|
|
child.stderr?.on('data', (c: Buffer) => (err += c.toString()));
|
|
child.on('error', reject);
|
|
child.on('close', (code) =>
|
|
code === 0 ? resolve(JSON.parse(out) as string[]) : reject(new Error(`exit ${code}: ${err}`)),
|
|
);
|
|
});
|
|
|
|
/** Spawn an argv-echo the SAME way installEmbeddingRuntime spawns npm on this platform. */
|
|
async function roundTrip(intended: string[]): Promise<string[]> {
|
|
const dir = mkdtempSync(join(tmpdir(), 'gnx-argv-'));
|
|
try {
|
|
writeFileSync(
|
|
join(dir, 'echo-argv.mjs'),
|
|
'process.stdout.write(JSON.stringify(process.argv.slice(2)))',
|
|
);
|
|
if (process.platform === 'win32') {
|
|
// A .cmd shim forwarding %* to node — the same node+%* shape npm.cmd uses,
|
|
// so the batch re-parse layer is genuinely exercised.
|
|
writeFileSync(join(dir, 'echo.cmd'), '@node "%~dp0echo-argv.mjs" %*\r\n');
|
|
return await capture({
|
|
command: 'echo.cmd',
|
|
commandLine: composeWin32Command('echo.cmd', intended),
|
|
cwd: dir,
|
|
shell: true,
|
|
});
|
|
}
|
|
// POSIX: array form, no shell — args reach execve untouched.
|
|
return await capture({
|
|
command: process.execPath,
|
|
args: [join(dir, 'echo-argv.mjs'), ...intended],
|
|
cwd: dir,
|
|
shell: false,
|
|
});
|
|
} finally {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
}
|
|
|
|
describe('embedding-install arg delivery — real spawn round-trip (#2372)', () => {
|
|
it('adversarial args reach the spawned child intact on this platform', async () => {
|
|
// Every class the install spawn must pass through safely — dangerous under
|
|
// BOTH cmd.exe and sh, so surviving intact proves injection-safety on each.
|
|
// (The documented ceilings %VAR% / delayed-! are excluded — no arg-passing
|
|
// scheme neutralizes them.)
|
|
const intended = [
|
|
'--prefix',
|
|
'C:\\Users\\John Doe\\.gitnexus\\embedding-runtime', // whitespace (+ backslashes)
|
|
'@huggingface/transformers@^4.1.0', // caret in a semver range
|
|
'C:\\Users\\John Doe\\rt\\', // trailing backslash + whitespace
|
|
'a&b|c<d>e(f)', // shell metacharacters
|
|
];
|
|
expect(await roundTrip(intended)).toEqual(intended);
|
|
}, 30_000);
|
|
});
|