diff --git a/api/core/tools/custom_tool/tool.py b/api/core/tools/custom_tool/tool.py index 3edb04d7b94..8a5d59656e6 100644 --- a/api/core/tools/custom_tool/tool.py +++ b/api/core/tools/custom_tool/tool.py @@ -102,16 +102,17 @@ class ApiTool(Tool): elif not isinstance(credentials["api_key_value"], str): raise ToolProviderCredentialValidationError("api_key_value must be a string") + api_key_value = credentials["api_key_value"] if "api_key_header_prefix" in credentials: api_key_header_prefix = credentials["api_key_header_prefix"] - if api_key_header_prefix == "basic" and credentials["api_key_value"]: - credentials["api_key_value"] = f"Basic {credentials['api_key_value']}" - elif api_key_header_prefix == "bearer" and credentials["api_key_value"]: - credentials["api_key_value"] = f"Bearer {credentials['api_key_value']}" + if api_key_header_prefix == "basic" and api_key_value: + api_key_value = f"Basic {api_key_value}" + elif api_key_header_prefix == "bearer" and api_key_value: + api_key_value = f"Bearer {api_key_value}" elif api_key_header_prefix == "custom": pass - headers[api_key_header] = credentials["api_key_value"] + headers[api_key_header] = api_key_value elif credentials["auth_type"] == "api_key_query": # For query parameter authentication, we don't add anything to headers diff --git a/api/tests/unit_tests/core/tools/test_custom_tool.py b/api/tests/unit_tests/core/tools/test_custom_tool.py index f525baeaf23..c6df7ab34eb 100644 --- a/api/tests/unit_tests/core/tools/test_custom_tool.py +++ b/api/tests/unit_tests/core/tools/test_custom_tool.py @@ -91,6 +91,33 @@ def test_assembling_request_auth_header_assembly(): assert tool.assembling_request(parameters={}) == {} +def test_assembling_request_auth_header_prefix_no_accumulation(): + """Regression test for #35974: calling assembling_request multiple times + must not accumulate Bearer/Basic prefixes on the stored credential.""" + tool = _build_tool() + tool.runtime.credentials = { + "auth_type": "api_key_header", + "api_key_header_prefix": "bearer", + "api_key_value": "my-token", + } + + # Call 3 times — header must always be "Bearer my-token", never accumulate + for _ in range(3): + headers = tool.assembling_request(parameters={}) + assert headers["Authorization"] == "Bearer my-token" + + # Verify the stored credential was NOT mutated + assert tool.runtime.credentials["api_key_value"] == "my-token" + + # Same for "basic" prefix + tool.runtime.credentials["api_key_header_prefix"] = "basic" + tool.runtime.credentials["api_key_value"] = "abc" + for _ in range(3): + headers = tool.assembling_request(parameters={}) + assert headers["Authorization"] == "Basic abc" + assert tool.runtime.credentials["api_key_value"] == "abc" + + def test_assembling_request_runtime_auth_errors(): tool = _build_tool()