import { parseEvidence } from "../../domain/evidence.js"; import { expect, it } from "vitest"; import { ElfNotesService } from "./ElfNotesService.js"; import { ELF_NOTES_PROVIDER } from "../../domain/investigationProviders.js"; import type { ElfNotes } from "../../domain/native/elfNotes.js"; import { ok } from "../../domain/result.js"; import { AnalysisCancelledError, AnalysisInputError, AnalysisOutputError, } from "../../domain/analysisErrorCore.js"; const identity = ELF_NOTES_PROVIDER; const report: ElfNotes = { artifact: { path: "/artifacts/app", sha256: "a".repeat(64), bytes: 512, }, format: "elf64", byte_order: "little", machine: 62, type: 3, type_name: "shared", tables: [], entries: [], coverage: { status: "complete", examined_tables: 0, examined_entries: 0 }, limitations: ["No PT_NOTE program header or SHT_NOTE section was declared."], }; it("rejects a relative path and extra arguments before reading", async () => { let calls = 0; const service = new ElfNotesService({ identity, inspect: () => { calls += 1; return Promise.resolve(ok(report)); }, }); const relative = await service.inspect({ path: "app" }); const extra = await service.inspect({ path: report.artifact.path, extra: true, }); expect(relative.ok).toBe(false); expect(extra.ok).toBe(false); if (!relative.ok) expect(relative.error).toBeInstanceOf(AnalysisInputError); if (!extra.ok) expect(extra.error).toBeInstanceOf(AnalysisInputError); expect(calls).toBe(0); }); it("records the selected ELF and an absent note table", async () => { const result = await new ElfNotesService({ identity, inspect: () => Promise.resolve(ok(report)), }).inspect({ path: report.artifact.path }); if (!result.ok) throw result.error; expect(result.value).toMatchObject({ confidence: "observed", subject: { format: "elf", architecture: "x86_64" }, normalized_result: report, }); }); it.each(["examined_tables", "examined_entries"] as const)( "rejects complete provider coverage with inconsistent %s", async (count) => { const result = await new ElfNotesService({ identity, inspect: () => Promise.resolve( ok({ ...report, coverage: { ...report.coverage, [count]: 1 }, }), ), }).inspect({ path: report.artifact.path }); expect(result.ok).toBe(false); if (!result.ok) expect(result.error).toBeInstanceOf(AnalysisOutputError); }, ); it("retains an examined empty table and rejects an uncounted table", async () => { const table = { kind: "program" as const, index: 0, name: null, location: { offset: 128, bytes: 0 }, alignment: 4, }; for (const examinedTables of [0, 1]) { const result = await new ElfNotesService({ identity, inspect: () => Promise.resolve( ok({ ...report, tables: [table], coverage: { ...report.coverage, examined_tables: examinedTables }, }), ), }).inspect({ path: report.artifact.path }); expect(result.ok).toBe(examinedTables === 1); if (result.ok) expect(result.value.normalized_result).toMatchObject({ tables: [table] }); else expect(result.error).toBeInstanceOf(AnalysisOutputError); } }); it("retains a completed observation when the caller cancels as the provider completes", async () => { const controller = new AbortController(); const reason = { request: "late ElfNotes cancellation" }; const service = new ElfNotesService({ identity, inspect: () => { controller.abort(reason); return Promise.resolve(ok(report)); }, }); const result = await service.inspect( { path: report.artifact.path }, { signal: controller.signal }, ); if (result.ok) throw new Error("Expected late cancellation"); expect(result.error).toBeInstanceOf(AnalysisCancelledError); expect(result.error.cause).toBe(reason); expect(parseEvidence(result.error.partialObservation)).toMatchObject({ operation: "inspect_elf_notes", normalized_result: report, }); });