/** * A1 regression: command injection fix — execFileSync, not execSync * Verifies CMakeConfigurator, CppBuilder, CppcheckRunner use execFileSync. */ import { describe, it, expect } from 'bun:test' import { readFileSync } from 'fs' import { join } from 'path' const SRC_ROOT = join(import.meta.dir, '..', 'src') function reads_file(relative: string): string { return readFileSync(join(SRC_ROOT, relative), 'utf-8') } describe('A1: Command injection fix', () => { it('CMakeConfigurator uses execFileSync, not execSync', () => { const src = reads_file('build/CMakeConfigurator.ts') expect(src).toContain('execFileSync') expect(src).not.toMatch(/\bexecSync\s*\(/) }) it('CppBuilder uses execFileSync, not execSync', () => { const src = reads_file('build/CppBuilder.ts') expect(src).toContain('execFileSync') expect(src).not.toMatch(/\bexecSync\s*\(/) }) it('CppcheckRunner uses execFileSync, not execSync', () => { const src = reads_file('analysis/CppcheckRunner.ts') expect(src).toContain('execFileSync') expect(src).not.toMatch(/\bexecSync\s*\(/) }) it('CMakeConfigurator passes args as array to execFileSync', () => { const src = reads_file('build/CMakeConfigurator.ts') expect(src).toMatch(/execFileSync\s*\(\s*'cmake'/) expect(src).not.toMatch(/execFileSync\s*\(\s*'cmake'\s*,\s*[`'"]/) }) it('CppBuilder passes args as array to execFileSync', () => { const src = reads_file('build/CppBuilder.ts') expect(src).toMatch(/execFileSync\s*\(\s*'cmake'/) expect(src).not.toMatch(/execFileSync\s*\(\s*'cmake'\s*,\s*[`'"]/) }) })