import { beforeEach, describe, expect, it, vi } from "vitest"; import type { SessionMetadata } from "./api"; const { existsMock, readTextFileMock } = vi.hoisted(() => ({ existsMock: vi.fn(), readTextFileMock: vi.fn(), })); vi.mock("@tauri-apps/plugin-fs", () => ({ exists: existsMock, readTextFile: readTextFileMock, })); import { scanSessionForSensitiveData } from "./privacyScan"; function buildMetadata(eventsPath = "/tmp/session/events.ndjson"): SessionMetadata { return { session_id: "session-abc12345", created_at: "1735689600", display: { id: "display-1", resolution: "1920x1080", refresh_rate: 60 }, duration_ms: 1000, event_count: 12, recording_path: "/tmp/session/recording.mp4", events_path: eventsPath, title: "Test Session", thumbnail_path: null, has_terminal: false, git_branch: null, git_commit: null, }; } describe("privacyScan", () => { beforeEach(() => { existsMock.mockReset(); readTextFileMock.mockReset(); existsMock.mockResolvedValue(false); readTextFileMock.mockResolvedValue(""); }); it("detects high-severity secrets from session artifacts", async () => { const metadata = buildMetadata(); existsMock.mockImplementation(async (path: string) => path === metadata.events_path); readTextFileMock.mockResolvedValue( `user typed token sk-abcdefghijklmnopqrstuvwxyz0123456789 in terminal` ); const result = await scanSessionForSensitiveData(metadata); expect(result.highSeverityCount).toBe(1); expect(result.findings[0]?.rule).toBe("OpenAI API key"); expect(result.scannedPaths).toContain(metadata.events_path); }); it("does not produce findings for benign workflow text", async () => { const metadata = buildMetadata(); existsMock.mockImplementation(async (path: string) => path === metadata.events_path); readTextFileMock.mockResolvedValue( "navigate to dashboard and click save. no secrets or tokens in this transcript." ); const result = await scanSessionForSensitiveData(metadata); expect(result.findings).toHaveLength(0); expect(result.highSeverityCount).toBe(0); expect(result.mediumSeverityCount).toBe(0); }); it("flags medium severity token assignments", async () => { const metadata = buildMetadata(); existsMock.mockImplementation(async (path: string) => path === metadata.events_path); readTextFileMock.mockResolvedValue( `config: api_key = "abcDEF1234567890long-value"; continue workflow` ); const result = await scanSessionForSensitiveData(metadata); expect(result.highSeverityCount).toBe(0); expect(result.mediumSeverityCount).toBeGreaterThanOrEqual(1); expect(result.findings.some((finding) => finding.rule === "Token assignment")).toBe(true); }); });