/** * Performance Test: Secret Scanner Throughput * * Benchmarks the secret scanner's ability to scan content * at scale without degrading performance. * * Covers issue #229 (ORCH-128) */ import { describe, it, expect, beforeEach, vi } from "vitest"; import { SecretScannerService } from "../../src/git/secret-scanner.service"; import { ConfigService } from "@nestjs/config"; describe("Performance: Secret Scanner", () => { let scanner: SecretScannerService; const mockConfigService = { get: vi.fn((_key: string, defaultValue?: unknown) => defaultValue), }; beforeEach(() => { scanner = new SecretScannerService(mockConfigService as unknown as ConfigService); }); describe("Content scanning throughput", () => { it("should scan 1000 lines of clean code in under 50ms", () => { const lines = Array.from( { length: 1000 }, (_, i) => `const value${String(i)} = computeResult(${String(i)}, "param-${String(i)}");` ); const content = lines.join("\n"); const start = performance.now(); const result = scanner.scanContent(content, "test-file.ts"); const duration = performance.now() - start; expect(duration).toBeLessThan(50); expect(result.matches).toHaveLength(0); }); it("should scan 100 files worth of content in under 500ms", () => { const fileContent = Array.from( { length: 100 }, (_, i) => `export function handler${String(i)}(): string { return "result-${String(i)}"; }` ).join("\n"); const start = performance.now(); for (let i = 0; i < 100; i++) { scanner.scanContent(fileContent, `file-${String(i)}.ts`); } const duration = performance.now() - start; expect(duration).toBeLessThan(500); }); it("should detect secrets in large content without performance regression", () => { // Mix clean code with embedded secrets const lines: string[] = []; for (let i = 0; i < 500; i++) { lines.push(`const config${String(i)} = { host: "localhost", port: ${String(3000 + i)} };`); } // Insert a secret at line 250 lines[250] = 'const apiKey = "AKIA1234567890ABCDEF"; // AWS access key'; const content = lines.join("\n"); const start = performance.now(); const result = scanner.scanContent(content, "config.ts"); const duration = performance.now() - start; expect(duration).toBeLessThan(100); expect(result.matches.length).toBeGreaterThan(0); }); it("should handle content with many false-positive patterns efficiently", () => { // Content with many patterns that look like secrets but are placeholders const lines = Array.from( { length: 200 }, (_, i) => `const example_key_${String(i)} = "test-xxxx-example-${String(i)}";` ); const content = lines.join("\n"); const start = performance.now(); const result = scanner.scanContent(content, "examples.ts"); const duration = performance.now() - start; expect(duration).toBeLessThan(100); // Placeholders should be whitelisted expect(result.matches).toHaveLength(0); }); }); describe("Pattern matching scalability", () => { it("should maintain consistent scan time regardless of content position", () => { const baseContent = Array.from( { length: 1000 }, (_, i) => `const x${String(i)} = ${String(i)};` ); // Secret at start const contentStart = ['const key = "AKIA1234567890ABCDEF";', ...baseContent].join("\n"); // Secret at end const contentEnd = [...baseContent, 'const key = "AKIA1234567890ABCDEF";'].join("\n"); const startTime1 = performance.now(); scanner.scanContent(contentStart, "start.ts"); const duration1 = performance.now() - startTime1; const startTime2 = performance.now(); scanner.scanContent(contentEnd, "end.ts"); const duration2 = performance.now() - startTime2; // Both should complete quickly expect(duration1).toBeLessThan(100); expect(duration2).toBeLessThan(100); // Both should complete within a reasonable ratio (allowing for sub-ms noise) const ratio = Math.max(duration1, duration2) / Math.max(0.1, Math.min(duration1, duration2)); expect(ratio).toBeLessThan(10); }); }); });