@@ -2113,6 +2113,93 @@ def test_builder_save_rejects_nested_args_key(builder_test_client, tmp_path):
21132113 assert "args" in response .json ()["detail" ]
21142114
21152115
2116+ def test_builder_save_rejects_dotted_tool_name (builder_test_client , tmp_path ):
2117+ """Uploading YAML with a dotted tool name is rejected (import prevention)."""
2118+ yaml_with_dotted_tool = b"""\
2119+ name: my_agent
2120+ tools:
2121+ - name: os.system
2122+ """
2123+ response = builder_test_client .post (
2124+ "/builder/save?tmp=true" ,
2125+ files = [(
2126+ "files" ,
2127+ ("app/root_agent.yaml" , yaml_with_dotted_tool , "application/x-yaml" ),
2128+ )],
2129+ )
2130+ assert response .status_code == 400
2131+ assert "os.system" in response .json ()["detail" ]
2132+ assert not (tmp_path / "app" / "tmp" / "app" / "root_agent.yaml" ).exists ()
2133+
2134+
2135+ def test_builder_save_rejects_dotted_agent_class (builder_test_client , tmp_path ):
2136+ """Uploading YAML with a dotted agent_class is rejected."""
2137+ yaml_with_dotted_class = b"""\
2138+ agent_class: evil.module.MyAgent
2139+ name: my_agent
2140+ """
2141+ response = builder_test_client .post (
2142+ "/builder/save?tmp=true" ,
2143+ files = [(
2144+ "files" ,
2145+ ("app/root_agent.yaml" , yaml_with_dotted_class , "application/x-yaml" ),
2146+ )],
2147+ )
2148+ assert response .status_code == 400
2149+ assert "evil.module.MyAgent" in response .json ()["detail" ]
2150+
2151+
2152+ def test_builder_save_rejects_dotted_code_ref (builder_test_client , tmp_path ):
2153+ """Uploading YAML with a dotted code reference is rejected."""
2154+ yaml_with_dotted_code = b"""\
2155+ name: my_agent
2156+ sub_agents:
2157+ - code: evil.module.my_agent
2158+ """
2159+ response = builder_test_client .post (
2160+ "/builder/save?tmp=true" ,
2161+ files = [(
2162+ "files" ,
2163+ ("app/root_agent.yaml" , yaml_with_dotted_code , "application/x-yaml" ),
2164+ )],
2165+ )
2166+ assert response .status_code == 400
2167+ assert "evil.module.my_agent" in response .json ()["detail" ]
2168+
2169+
2170+ def test_builder_save_allows_simple_tool_name (builder_test_client , tmp_path ):
2171+ """Uploading YAML with a simple (non-dotted) tool name is allowed."""
2172+ yaml_with_simple_tool = b"""\
2173+ name: my_agent
2174+ tools:
2175+ - name: google_search
2176+ """
2177+ response = builder_test_client .post (
2178+ "/builder/save?tmp=true" ,
2179+ files = [(
2180+ "files" ,
2181+ ("app/root_agent.yaml" , yaml_with_simple_tool , "application/x-yaml" ),
2182+ )],
2183+ )
2184+ assert response .status_code == 200
2185+
2186+
2187+ def test_builder_save_allows_simple_agent_class (builder_test_client , tmp_path ):
2188+ """Uploading YAML with a simple agent_class (e.g. LlmAgent) is allowed."""
2189+ yaml_with_simple_class = b"""\
2190+ agent_class: LlmAgent
2191+ name: my_agent
2192+ """
2193+ response = builder_test_client .post (
2194+ "/builder/save?tmp=true" ,
2195+ files = [(
2196+ "files" ,
2197+ ("app/root_agent.yaml" , yaml_with_simple_class , "application/x-yaml" ),
2198+ )],
2199+ )
2200+ assert response .status_code == 200
2201+
2202+
21162203def test_builder_get_rejects_non_yaml_file_paths (builder_test_client , tmp_path ):
21172204 """GET /builder/app/{app_name}?file_path=... rejects non-YAML extensions."""
21182205 app_root = tmp_path / "app"
0 commit comments