import { expect } from 'bun:test'; import { analyzeCommand } from '../src/core/analyze.ts'; import { loadConfig } from '../src/core/config.ts'; import type { AnalyzeOptions, Config } from '../src/types.ts'; function envTruthy(name: string): boolean { const val = process.env[name]; return val === '1' || val === 'true' || val === 'yes'; } // Default empty config for tests that don't specify a cwd // This prevents loading the project's .safety-net.json const DEFAULT_TEST_CONFIG: Config = { version: 1, rules: [] }; function getOptionsFromEnv(cwd?: string, config?: Config): AnalyzeOptions { // If no cwd specified, use empty config to avoid loading project's config const effectiveConfig = config ?? (cwd ? loadConfig(cwd) : DEFAULT_TEST_CONFIG); return { cwd, config: effectiveConfig, strict: envTruthy('SAFETY_NET_STRICT'), paranoidRm: envTruthy('SAFETY_NET_PARANOID') || envTruthy('SAFETY_NET_PARANOID_RM'), paranoidInterpreters: envTruthy('SAFETY_NET_PARANOID') || envTruthy('SAFETY_NET_PARANOID_INTERPRETERS'), }; } export function assertBlocked(command: string, reasonContains: string, cwd?: string): void { const options = getOptionsFromEnv(cwd); const result = analyzeCommand(command, options); expect(result).not.toBeNull(); expect(result?.reason).toContain(reasonContains); } export function assertAllowed(command: string, cwd?: string): void { const options = getOptionsFromEnv(cwd); const result = analyzeCommand(command, options); expect(result).toBeNull(); } export function runGuard(command: string, cwd?: string, config?: Config): string | null { const options = getOptionsFromEnv(cwd, config); return analyzeCommand(command, options)?.reason ?? null; } export function withEnv(env: Record, fn: () => T): T { const original: Record = {}; for (const key of Object.keys(env)) { original[key] = process.env[key]; process.env[key] = env[key]; } try { return fn(); } finally { for (const key of Object.keys(env)) { if (original[key] === undefined) { delete process.env[key]; } else { process.env[key] = original[key]; } } } }