From 2c33451700ecf19fe0627206ce388ccc33bf1923 Mon Sep 17 00:00:00 2001 From: niveshdandyan Date: Tue, 3 Feb 2026 12:00:13 +0000 Subject: [PATCH] feat: add full event log export for all scan events Add export_full_log() method to FuzzerState that exports a comprehensive log of all events including errors, refusals, and successful outputs. Previously only failures were exported. This change addresses issue #100 by creating a complete audit trail in full_scan_log.csv with event type, module, prompt, status code, content, and refused flag columns. Co-Authored-By: Nivesh Dandyan --- agentic_security/probe_actor/fuzzer.py | 2 ++ agentic_security/probe_actor/state.py | 42 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/agentic_security/probe_actor/fuzzer.py b/agentic_security/probe_actor/fuzzer.py index 60b3a39..7254fc8 100644 --- a/agentic_security/probe_actor/fuzzer.py +++ b/agentic_security/probe_actor/fuzzer.py @@ -423,6 +423,7 @@ async def perform_single_shot_scan( yield ScanResult.status_msg("Scan completed.") fuzzer_state.export_failures("failures.csv") + fuzzer_state.export_full_log("full_scan_log.csv") async def perform_many_shot_scan( @@ -558,6 +559,7 @@ async def perform_many_shot_scan( yield ScanResult.status_msg("Scan completed.") fuzzer_state.export_failures("failures.csv") + fuzzer_state.export_full_log("full_scan_log.csv") def scan_router( diff --git a/agentic_security/probe_actor/state.py b/agentic_security/probe_actor/state.py index 8fba317..a92a49e 100644 --- a/agentic_security/probe_actor/state.py +++ b/agentic_security/probe_actor/state.py @@ -45,3 +45,45 @@ def export_failures(self, filename: str = "failures.csv"): failure_data, columns=["module", "prompt", "status_code", "content"] ) df.to_csv(filename, index=False) + + def export_full_log(self, filename: str = "full_scan_log.csv"): + """Export a complete log of all events (errors, refusals, and successful outputs)""" + log_data = [] + + # Add errors + for module_name, prompt, status_code, error_msg in self.errors: + log_data.append({ + "event_type": "error", + "module": module_name, + "prompt": prompt, + "status_code": status_code, + "content": error_msg, + "refused": None, + }) + + # Add refusals + for module_name, prompt, status_code, response_text in self.refusals: + log_data.append({ + "event_type": "refusal", + "module": module_name, + "prompt": prompt, + "status_code": status_code, + "content": response_text, + "refused": True, + }) + + # Add all outputs (including successful ones) + for module_name, prompt, response_text, refused in self.outputs: + # Skip if already logged as refusal to avoid duplicates + if not refused: + log_data.append({ + "event_type": "success", + "module": module_name, + "prompt": prompt, + "status_code": 200, + "content": response_text, + "refused": False, + }) + + df = pd.DataFrame(log_data) + df.to_csv(filename, index=False)