from typing import Dict import ast UNSAFE_FUNCTIONS = {"eval", "exec", "compile", "__import__"} MIN_TASK_SCORE = 0.01 MAX_TASK_SCORE = 0.99 def get_task() -> Dict: return { "id": "medium", "difficulty": "medium", "name": "vuln_patch", "objective": "Remove unsafe calls while preserving function structure.", "description": "Remove unsafe function usage while preserving functionality.", "grader_name": "grade", "score_range": [MIN_TASK_SCORE, MAX_TASK_SCORE], } class UnsafeCallVisitor(ast.NodeVisitor): def __init__(self) -> None: self.unsafe_calls = 0 def visit_Call(self, node: ast.Call) -> None: if isinstance(node.func, ast.Name): if node.func.id in UNSAFE_FUNCTIONS: self.unsafe_calls += 1 self.generic_visit(node) def _has_function_def(tree: ast.AST) -> bool: return any(isinstance(node, ast.FunctionDef) for node in ast.walk(tree)) def grade(candidate_code: str) -> float: """ Score breakdown: - No unsafe calls → +0.7 - Function structure preserved → +0.3 """ try: tree = ast.parse(candidate_code) except SyntaxError: return MIN_TASK_SCORE visitor = UnsafeCallVisitor() visitor.visit(tree) score = 0.0 if visitor.unsafe_calls == 0: score += 0.7 if _has_function_def(tree): score += 0.3 score = round(score, 2) score = max(MIN_TASK_SCORE, min(MAX_TASK_SCORE, score)) return score