4242@register_tool_filter ("tool_safety_guard" )
4343class ToolSafetyFilter (BaseFilter ):
4444 """Filter that scans script-like tool arguments before execution."""
45-
4645 def __init__ (
47- self ,
48- policy_path : Optional [str ] = None ,
49- policy : Optional [SafetyPolicy ] = None ,
50- scanner : Optional [SafetyScanner ] = None ,
46+ self ,
47+ policy_path : Optional [str ] = None ,
48+ policy : Optional [SafetyPolicy ] = None ,
49+ scanner : Optional [SafetyScanner ] = None ,
5150 ) -> None :
5251 super ().__init__ ()
5352 self .policy = policy or load_policy (policy_path )
@@ -82,33 +81,38 @@ class SafetyGuardedCodeExecutor(BaseCodeExecutor):
8281 policy : SafetyPolicy = Field (default_factory = SafetyPolicy )
8382
8483 def __init__ (
85- self ,
86- * ,
87- delegate : BaseCodeExecutor ,
88- policy_path : Optional [str ] = None ,
89- policy : Optional [SafetyPolicy ] = None ,
90- ** data : Any ,
84+ self ,
85+ * ,
86+ delegate : BaseCodeExecutor ,
87+ policy_path : Optional [str ] = None ,
88+ policy : Optional [SafetyPolicy ] = None ,
89+ ** data : Any ,
9190 ) -> None :
9291 effective_policy = policy or load_policy (policy_path )
9392 data .setdefault ("optimize_data_file" , delegate .optimize_data_file )
9493 data .setdefault ("stateful" , delegate .stateful )
9594 data .setdefault ("error_retry_attempts" , delegate .error_retry_attempts )
96- data .setdefault ("execute_once_per_invocation" , delegate .execute_once_per_invocation )
97- data .setdefault ("code_block_delimiters" , delegate .code_block_delimiters )
98- data .setdefault ("execution_result_delimiters" , delegate .execution_result_delimiters )
95+ data .setdefault ("execute_once_per_invocation" ,
96+ delegate .execute_once_per_invocation )
97+ data .setdefault ("code_block_delimiters" ,
98+ delegate .code_block_delimiters )
99+ data .setdefault ("execution_result_delimiters" ,
100+ delegate .execution_result_delimiters )
99101 data .setdefault ("workspace_runtime" , delegate .workspace_runtime )
100102 data .setdefault ("ignore_codes" , delegate .ignore_codes )
101103 super ().__init__ (delegate = delegate , policy = effective_policy , ** data )
102104
103105 async def execute_code (
104- self ,
105- invocation_context : InvocationContext ,
106- code_execution_input : CodeExecutionInput ,
106+ self ,
107+ invocation_context : InvocationContext ,
108+ code_execution_input : CodeExecutionInput ,
107109 ) -> CodeExecutionResult :
108110 scanner = SafetyScanner (self .policy )
109111 blocks = code_execution_input .code_blocks
110112 if not blocks and code_execution_input .code :
111- blocks = [CodeBlock (language = "python" , code = code_execution_input .code )]
113+ blocks = [
114+ CodeBlock (language = "python" , code = code_execution_input .code )
115+ ]
112116
113117 for block in blocks :
114118 report = scanner .scan (
@@ -120,12 +124,15 @@ async def execute_code(
120124 _set_span_attributes (report )
121125 _write_audit_event (self .policy , report )
122126 if report .blocked :
123- return create_code_execution_result (stderr = _blocked_message (report ))
127+ return create_code_execution_result (
128+ stderr = _blocked_message (report ))
124129
125- return await self .delegate .execute_code (invocation_context , code_execution_input )
130+ return await self .delegate .execute_code (invocation_context ,
131+ code_execution_input )
126132
127133
128- def _extract_scan_target (req : Any ) -> tuple [str , ScriptLanguage , str , dict [str , Any ] | None ]:
134+ def _extract_scan_target (
135+ req : Any ) -> tuple [str , ScriptLanguage , str , dict [str , Any ] | None ]:
129136 if not isinstance (req , dict ):
130137 return str (req or "" ), ScriptLanguage .UNKNOWN , "" , None
131138
@@ -142,7 +149,9 @@ def _extract_scan_target(req: Any) -> tuple[str, ScriptLanguage, str, dict[str,
142149 if not content :
143150 text_parts = []
144151 for key , value in req .items ():
145- if isinstance (value , str ) and any (token in key .lower () for token in ("command" , "script" , "code" )):
152+ if isinstance (value , str ) and any (
153+ token in key .lower ()
154+ for token in ("command" , "script" , "code" )):
146155 text_parts .append (value )
147156 content = "\n " .join (text_parts )
148157
@@ -171,7 +180,8 @@ def _extract_scan_target(req: Any) -> tuple[str, ScriptLanguage, str, dict[str,
171180def _metadata_from_request (req : Any , source : str ) -> dict [str , Any ]:
172181 metadata : dict [str , Any ] = {"source" : source }
173182 if isinstance (req , dict ):
174- for key in ("timeout" , "timeout_seconds" , "max_output_bytes" , "max_output_size" , "output_limit" ):
183+ for key in ("timeout" , "timeout_seconds" , "max_output_bytes" ,
184+ "max_output_size" , "output_limit" ):
175185 if key in req :
176186 metadata [key ] = req [key ]
177187 return metadata
@@ -186,7 +196,9 @@ def _set_span_attributes(report: SafetyReport) -> None:
186196 span .set_attribute ("tool.safety.redacted" , report .redacted )
187197
188198
189- def _write_audit_event (policy : SafetyPolicy , report : SafetyReport , cwd : str = "" ) -> None :
199+ def _write_audit_event (policy : SafetyPolicy ,
200+ report : SafetyReport ,
201+ cwd : str = "" ) -> None :
190202 if not policy .audit_log_path :
191203 return
192204 event = SafetyAuditEvent (
@@ -204,7 +216,9 @@ def _write_audit_event(policy: SafetyPolicy, report: SafetyReport, cwd: str = ""
204216 path = Path (policy .audit_log_path ).expanduser ()
205217 path .parent .mkdir (parents = True , exist_ok = True )
206218 with path .open ("a" , encoding = "utf-8" ) as file :
207- file .write (json .dumps (event .model_dump (mode = "json" ), ensure_ascii = False ) + "\n " )
219+ file .write (
220+ json .dumps (event .model_dump (mode = "json" ), ensure_ascii = False ) +
221+ "\n " )
208222
209223
210224def _blocked_response (report : SafetyReport ) -> dict [str , Any ]:
0 commit comments