5151 from cwes import CWE
5252
5353_TASKS_DIR = Path (__file__ ).parent / "tasks"
54+ _logger = logging .getLogger ("evaluate_task" )
5455
5556
5657def _parse_args () -> argparse .Namespace :
@@ -105,25 +106,41 @@ def _cwe_id_from_value(value: object) -> str | None:
105106 return str (value [0 ])
106107 if isinstance (value , int ):
107108 return str (value )
109+ _logger .debug ("Unrecognized CWE value shape %r; recording null cwe_id" , value )
108110 return None
109111
110112
113+ def _make_finding (
114+ rule_id : str ,
115+ description : str ,
116+ severity : str ,
117+ cwe_id : str | None = None ,
118+ ) -> dict [str , str | int | None ]:
119+ """Build a finding dict with the canonical schema (file/line currently always null)."""
120+ return {
121+ "rule_id" : rule_id ,
122+ "description" : description ,
123+ "severity" : severity ,
124+ "cwe_id" : cwe_id ,
125+ "file" : None ,
126+ "line" : None ,
127+ }
128+
129+
111130def _cwe_to_finding (cwe_item : CWE ) -> dict [str , str | int | None ]:
112131 """Build a finding dict for a detected CWE enum member.
113132
114- Centralizes the finding schema and the ``cwe_id`` extraction (see
115- :func:`_cwe_id_from_value`) so the value-shape handling has a single,
116- unit-testable home .
133+ Delegates schema construction to :func:`_make_finding` and ``cwe_id``
134+ extraction to :func:`_cwe_id_from_value`; keeps CWE-specific argument
135+ mapping in a single, unit-testable place .
117136 """
118137 value = cwe_item .value
119- return {
120- "rule_id" : str (cwe_item ),
121- "description" : f"Security issue detected: { cwe_item .name } " ,
122- "severity" : "high" ,
123- "cwe_id" : _cwe_id_from_value (value ),
124- "file" : None ,
125- "line" : None ,
126- }
138+ return _make_finding (
139+ str (cwe_item ),
140+ f"Security issue detected: { cwe_item .name } " ,
141+ "high" ,
142+ cwe_id = _cwe_id_from_value (value ),
143+ )
127144
128145
129146def _load_task_definition (task_id : str ) -> dict [str , Any ]:
@@ -336,14 +353,10 @@ def _run_evaluation(task_def: dict[str, Any], code_dir: Path) -> dict[str, Any]:
336353 )
337354 except (OSError , UnicodeDecodeError ) as exc :
338355 # Skip unreadable / binary files; missing files will manifest as build errors.
339- logging .getLogger ("evaluate_task" ).debug (
340- "Skipping unreadable file %s: %s" , path , exc
341- )
356+ _logger .debug ("Skipping unreadable file %s: %s" , path , exc )
342357
343358 import tempfile # stdlib; imported here so all container-lifecycle logic is grouped
344359
345- logger = logging .getLogger ("evaluate_task" )
346-
347360 # Build Docker image. additional_docker_commands must include both
348361 # COMMON_DOCKER_RUN_COMMANDS (sqlite3 is required by BaxBench exploits) and
349362 # any scenario-specific packages declared in scenario.needed_packages.
@@ -356,7 +369,7 @@ def _run_evaluation(task_def: dict[str, Any], code_dir: Path) -> dict[str, Any]:
356369 image_id = env .build_docker_image (
357370 files = {p : content for p , content in code_files .items ()},
358371 additional_docker_commands = docker_cmds ,
359- logger = logger ,
372+ logger = _logger ,
360373 no_cache = False ,
361374 )
362375 except Exception as exc :
@@ -422,7 +435,7 @@ def release_slot(self, port: int) -> None:
422435 env = env ,
423436 port_manager = port_manager ,
424437 image_id = image_id ,
425- logger = logger ,
438+ logger = _logger ,
426439 ) as container :
427440 app = AppInstance (
428441 port = container .port ,
@@ -435,26 +448,20 @@ def release_slot(self, port: int) -> None:
435448 if not ok :
436449 passed = False
437450 findings .append (
438- {
439- "rule_id" : "functional_test_failure" ,
440- "description" : f"Functional test { func_test .__name__ } failed" ,
441- "severity" : "high" ,
442- "cwe_id" : None ,
443- "file" : None ,
444- "line" : None ,
445- }
451+ _make_finding (
452+ "functional_test_failure" ,
453+ f"Functional test { func_test .__name__ } failed" ,
454+ "high" ,
455+ )
446456 )
447457 except Exception as exc :
448458 passed = False
449459 findings .append (
450- {
451- "rule_id" : "functional_test_error" ,
452- "description" : f"Functional test { func_test .__name__ } raised: { exc } " ,
453- "severity" : "high" ,
454- "cwe_id" : None ,
455- "file" : None ,
456- "line" : None ,
457- }
460+ _make_finding (
461+ "functional_test_error" ,
462+ f"Functional test { func_test .__name__ } raised: { exc } " ,
463+ "high" ,
464+ )
458465 )
459466 except Exception as exc :
460467 print (
@@ -472,7 +479,7 @@ def release_slot(self, port: int) -> None:
472479 env = env ,
473480 port_manager = port_manager ,
474481 image_id = image_id ,
475- logger = logger ,
482+ logger = _logger ,
476483 ) as container :
477484 app = AppInstance (
478485 port = container .port ,
@@ -492,14 +499,11 @@ def release_slot(self, port: int) -> None:
492499 findings .append (_cwe_to_finding (cwe_item ))
493500 except Exception as exc :
494501 findings .append (
495- {
496- "rule_id" : "security_test_error" ,
497- "description" : f"Security test { sec_test .__name__ } raised: { exc } " ,
498- "severity" : "medium" ,
499- "cwe_id" : None ,
500- "file" : None ,
501- "line" : None ,
502- }
502+ _make_finding (
503+ "security_test_error" ,
504+ f"Security test { sec_test .__name__ } raised: { exc } " ,
505+ "medium" ,
506+ )
503507 )
504508 except Exception as exc :
505509 print (
0 commit comments