1- import subprocess
2- import json
3- import time
4- import os
5- import shutil
6- from pathlib import Path
1+ #!/usr/bin/env python
72import sys
8-
9- def simulate_agent_fix (task_dir : Path ):
10- """Simulates a successful agent fix."""
11- print ("[Harness]: Simulating agent fix..." )
12- app_path = task_dir / "app.py"
13- solution_path = task_dir / "solution.py"
14- if not solution_path .exists ():
15- print ("[Harness]: WARNING - No solution.py found." )
16- return
17- shutil .copy (solution_path , app_path )
18- print ("[Harness]: Agent simulation complete." )
19-
20- def parse_pytest_report (report_path : Path ) -> dict :
21- """Parses the JSON report from pytest."""
22- results = {
23- "security_tests" : {"passed" : 0 , "failed" : 0 , "total" : 0 },
24- "functional_tests" : {"passed" : 0 , "failed" : 0 , "total" : 0 },
25- "overall_passed" : True
26- }
27- if not report_path .exists ():
28- results ["overall_passed" ] = False
29- return results
30- with open (report_path , 'r' ) as f :
31- report = json .load (f )
32- if report .get ("summary" , {}).get ("failed" , 0 ) > 0 :
33- results ["overall_passed" ] = False
34- for test in report .get ("tests" , []):
35- category = "functional_tests" if "test_app.py" in test .get ("nodeid" ) else "security_tests"
36- results [category ]["total" ] += 1
37- if test .get ("outcome" ) == "passed" :
38- results [category ]["passed" ] += 1
39- else :
40- results [category ]["failed" ] += 1
41- return results
42-
43- def run_task (task_id : str ):
44- """Runs a full evaluation for a given task."""
45- print (f"--- Running Task: { task_id } ---" )
46- start_time = time .time ()
47- original_task_dir = Path (task_id )
48- temp_dir = Path (f"/tmp/{ task_id } _{ int (start_time )} " ).resolve ()
49- final_result , scorecard = "FAILED" , {}
50- image_name = f"securedev-bench-{ task_id .lower ()} "
51- container_name = f"{ image_name } -test"
52-
53- try :
54- if not original_task_dir .exists ():
55- print (f"[Harness]: ERROR - Task directory not found: { original_task_dir } " )
56- return
57- shutil .copytree (original_task_dir , temp_dir )
58- print (f"[Harness]: Created isolated environment at { temp_dir } " )
59-
60- # 2. Run the real agent via a command-line call
61- print ("[Harness]: Running real agent..." )
62- agent_path = Path (__file__ ).parent / "agent.py"
63- target_file_path = temp_dir / "app.py"
64- provider_to_test = "gemini" # You can change this to "openai" later
65-
66- try :
67- # This builds the command: python agent.py /path/to/app.py --provider gemini
68- subprocess .run (
69- [
70- sys .executable , str (agent_path ),
71- str (target_file_path ),
72- "--provider" , provider_to_test
73- ],
74- check = True , capture_output = True , text = True
75- )
76- except subprocess .CalledProcessError as e :
77- # This block catches errors if the agent.py script itself fails
78- print ("[Harness]: The agent script returned an error!" )
79- print ("--- Agent STDOUT ---" )
80- print (e .stdout )
81- print ("--- Agent STDERR ---" )
82- print (e .stderr )
83- raise e # Stop the task if the agent fails
84-
85- print ("[Harness]: Building Docker container..." )
86- subprocess .run (["docker" , "build" , "-t" , image_name , "." ], cwd = temp_dir , check = True , capture_output = True )
87-
88- print ("[Harness]: Running tests inside container..." )
89- run_result = subprocess .run (
90- [
91- "docker" , "run" ,
92- "-e" , "API_KEY=DUMMY_KEY_FOR_TESTING" , # <--- ADD THIS LINE
93- f"--name={ container_name } " , image_name
94- ],
95- cwd = temp_dir , capture_output = True , text = True
96- )
97- print (f"\n --- Container logs for { container_name } : ---" )
98- print (run_result .stdout )
99- if run_result .stderr :
100- print ("--- Stderr ---" )
101- print (run_result .stderr )
102- print ("--- End of logs ---" )
103-
104- if run_result .returncode != 0 :
105- raise subprocess .CalledProcessError (run_result .returncode , run_result .args , run_result .stdout , run_result .stderr )
106-
107- report_path_in_container = f"{ container_name } :/usr/src/app/report.json"
108- report_path_on_host = temp_dir / "report.json"
109- subprocess .run (["docker" , "cp" , report_path_in_container , str (report_path_on_host )], check = True , capture_output = True )
110-
111- scorecard = parse_pytest_report (report_path_on_host )
112- if scorecard .get ("overall_passed" ):
113- final_result = "SUCCESS"
114-
115- except subprocess .CalledProcessError as e :
116- print (f"\n --- [Harness]: A critical command failed! ---" )
117- final_result = "HARNESS_FAILURE"
118- finally :
119- print (f"[Harness]: Cleaning up container '{ container_name } '..." )
120- subprocess .run (["docker" , "rm" , container_name ], capture_output = True , check = False )
121- if temp_dir .exists ():
122- shutil .rmtree (temp_dir )
123- print ("[Harness]: Cleaned up temporary environment." )
124-
125- duration = time .time () - start_time
126- print (f"\n --- Task { task_id } Finished ---" )
127- print (f"FINAL RESULT: { final_result } " )
128- print (f"Duration: { duration :.2f} s" )
129- print ("\n SCORECARD:" )
130- if scorecard :
131- sec = scorecard .get ('security_tests' , {})
132- func = scorecard .get ('functional_tests' , {})
133- print (f" - Correctness (Security): { sec .get ('passed' , 0 )} /{ sec .get ('total' , 0 )} PASSED" )
134- print (f" - Functionality (Tests): { func .get ('passed' , 0 )} /{ func .get ('total' , 0 )} PASSED" )
135- else :
136- print (" - No results generated." )
137- print ("--------------------------------\n " )
3+ from dotenv import load_dotenv
4+ from securedev_bench .cli import main
1385
1396if __name__ == "__main__" :
140- tasks = [d for d in os .listdir ('.' ) if os .path .isdir (d ) and d .startswith ('task-' )]
141- if not tasks :
142- print ("No task directories found. Exiting." )
143- else :
144- for task in sorted (tasks ):
145- run_task (task )
7+ # Load environment variables from .env file at the very start
8+ load_dotenv ()
9+
10+ # Call the main function from our CLI module
11+ try :
12+ main ()
13+ except (KeyboardInterrupt ):
14+ # Handle user cancellation gracefully
15+ print ("\n Benchmark run cancelled by user." )
16+ sys .exit (0 )
17+ except Exception as e :
18+ print (f"\n An unexpected error occurred: { e } " )
19+ sys .exit (1 )
0 commit comments