44import re
55import os
66from datetime import datetime
7-
8- # ============================================================
9- # 🚀 LOGGING SETUP - Human Readable Session Logs
10- # ============================================================
7+ from agent_cache import NegativeCache
118
129LOG_DIR = "/home/bigkali/security-agent/logs"
1310os .makedirs (LOG_DIR , exist_ok = True )
@@ -67,10 +64,6 @@ def setup_logger():
6764log .info (f"[START] SECURITY AGENT SESSION { SESSION_ID } " )
6865log .info (f"[FILE] Log file: { LOG_FILE } " )
6966
70- # ============================================================
71- # ⚙️ CONFIG
72- # ============================================================
73-
7467OLLAMA_URL = "http://192.168.0.39:1234/v1/chat/completions"
7568MCP_URL = "http://localhost:8000"
7669
@@ -115,11 +108,6 @@ def setup_logger():
115108NO explanations. NO markdown. ONLY JSON."""
116109
117110
118- # ============================================================
119- # 🤖 MODEL + TOOL EXECUTION
120- # ============================================================
121-
122-
123111class AgentMemory :
124112 def __init__ (self ):
125113 self .open_ports = []
@@ -222,10 +210,6 @@ def execute_step(step):
222210 log .error (f"[ERROR] 😭🔥 { tool } exception: { e } " )
223211 return "" , False
224212
225- # ============================================================
226- # 🔍 RECON + ⚔️ ATTACK
227- # ============================================================
228-
229213def run_recon (target , memory ):
230214 log .info (f"[SCAN] Starting recon on { target } " )
231215 goal = f"Scan { target } with masscan then nmap to find all open ports and services. JSON only."
@@ -240,7 +224,7 @@ def run_recon(target, memory):
240224 else :
241225 log .warning (f"[SCAN] 😤💀 No ports found in output" )
242226
243- def run_attack_loop (target , memory ):
227+ def run_attack_loop (target , memory , cache = None ):
244228 log .info (f"[ATTACK] Starting attack loop on { target } " )
245229 while memory .has_untried_ports ():
246230 port = memory .next_untried_port ()
@@ -254,10 +238,21 @@ def run_attack_loop(target, memory):
254238 continue
255239 success = False
256240 for step in chain :
241+ # ── Negative cache gate ──────────────────────────────
242+ if cache and not cache .should_attempt (step ):
243+ log .warning (f"[MEMORY] 🚫 Skipping permanently blocked step: { step .get ('tool' )} " )
244+ continue
245+ # ────────────────────────────────────────────────────
257246 output , ok = execute_step (step )
258247 if ok and output and any (x in output .lower () for x in ["password" , "login" , "session" , "shell" , "success" , "found" , "valid" ]):
259248 success = True
249+ if cache :
250+ cache .record_success (step )
260251 memory .add_finding (port , step .get ("tool" ), output [:2000 ])
252+ elif not ok :
253+ if cache :
254+ reason = f"tool={ step .get ('tool' )} port={ port } output_empty={ not bool (output )} "
255+ cache .record_failure (step , reason = reason )
261256 memory .mark_tried (port , success = success )
262257 log .info (f"[ATTACK] Attack loop complete" )
263258 summary = memory .summary ()
@@ -269,24 +264,27 @@ def run_attack_loop(target, memory):
269264
270265def run_full_engagement (target ):
271266 memory = AgentMemory ()
267+ cache = NegativeCache ()
272268 log .info (f"[ENGAGE] 💣 Full engagement started on { target } " )
273269 run_recon (target , memory )
274270 if memory .open_ports :
275- run_attack_loop (target , memory )
271+ run_attack_loop (target , memory , cache )
276272 else :
277273 log .warning (f"[FAIL] 😤💀 No open ports found — aborting engagement" )
278274 return memory
279275
280- # ============================================================
281- # 🎯 MAIN
282- # ============================================================
283-
284- def execute_chain (chain ):
276+ def execute_chain (chain , cache = None ):
285277 for i , step in enumerate (chain , 1 ):
286278 log .info (f"[CHAIN] 🔗 Step { i } of { len (chain )} : { step .get ('tool' )} " )
287- execute_step (step )
279+ if cache and not cache .should_attempt (step ):
280+ log .warning (f"[MEMORY] 🚫 Skipping permanently blocked step: { step .get ('tool' )} " )
281+ continue
282+ output , ok = execute_step (step )
283+ if not ok and cache :
284+ cache .record_failure (step , reason = f"manual chain failure, step { i } " )
288285
289286def main ():
287+ cache = NegativeCache ()
290288 log .info ("[START] 🚀 AUTONOMOUS SECURITY AGENT ONLINE" )
291289 print ("=" * 60 )
292290 print ("⚔️ AUTONOMOUS SECURITY AGENT" )
@@ -303,7 +301,6 @@ def main():
303301 goal = input (">>> " ).strip ()
304302 if goal .lower () == "exit" :
305303 log .info ("[START] Agent shutdown. Goodbye! 👋" )
306-
307304 break
308305 if not goal :
309306 continue
@@ -316,7 +313,7 @@ def main():
316313 data = call_model (goal )
317314 chain = data .get ("chain" , [])
318315 if chain :
319- execute_chain (chain )
316+ execute_chain (chain , cache = cache )
320317 else :
321318 log .warning ("[FAIL] 😤💀 No tool chain generated" )
322319 except KeyboardInterrupt :
@@ -330,8 +327,3 @@ def main():
330327
331328if __name__ == "__main__" :
332329 main ()
333-
334- # ============================================================
335- # 🧠 AGENT MEMORY
336- # ============================================================
337-
0 commit comments