Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ async def run_async(
'message': 'Needs your authorization to access your data.',
}

# The access token added below must stay out of this log line and out of
# the caller's args, which are also handed to after-tool callbacks and
# recorded on the tool span.
logger.info('Running tool: %s with args: %s', self.name, args)
args = args.copy()

# Attach parameters from auth into main parameters list
if auth_result.auth_credential:
# Attach parameters from auth into main parameters list
Expand All @@ -192,7 +198,6 @@ async def run_async(
args['entity'] = self._entity
args['operation'] = self._operation
args['action'] = self._action
logger.info('Running tool: %s with args: %s', self.name, args)
return await self._rest_api_tool.call(args=args, tool_context=tool_context)

def __str__(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -548,8 +548,11 @@ async def call(
"message": "Needs your authorization to access your data.",
}

# Attach parameters from auth into main parameters list
api_params, api_args = self._operation_parser.get_parameters().copy(), args
# Work on a copy of args: the caller's dict is also handed to after-tool
# callbacks and recorded on the tool span, so the defaults and auth
# parameters added below must not land in it.
api_params = self._operation_parser.get_parameters().copy()
api_args = args.copy()

# Add any required arguments that are missing and have defaults:
for api_param in api_params:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,43 @@ async def test_run_with_auth_async(
assert result == {"status": "success", "data": "mock_data"}


@pytest.mark.asyncio
async def test_run_with_auth_async_keeps_token_out_of_caller_args_and_logs(
integration_tool_with_auth, mock_rest_api_tool, caplog
):
"""The caller's args also feed after-tool callbacks and the tool span."""
input_args = {"user_id": "user123"}

with mock.patch.object(
ToolAuthHandler, "from_tool_context", autospec=True
) as mock_from_tool_context:
mock_from_tool_context.return_value.prepare_auth_credentials = (
mock.AsyncMock(
return_value=AuthPreparationResult(
state="done",
auth_credential=AuthCredential(
auth_type=AuthCredentialTypes.HTTP,
http=HttpAuth(
scheme="bearer",
credentials=HttpCredentials(token="secret-token"),
),
),
)
)
)
with caplog.at_level("INFO"):
await integration_tool_with_auth.run_async(
args=input_args, tool_context={}
)

assert input_args == {"user_id": "user123"}
sent_args = mock_rest_api_tool.call.call_args.kwargs["args"]
assert sent_args["dynamic_auth_config"] == {
"oauth2_auth_code_flow.access_token": "secret-token"
}
assert "secret-token" not in caplog.text


class TestIntegrationConnectorToolWithJsonSchema:

def test_get_declaration_with_json_schema_feature_enabled(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,42 @@ async def test_call_success(
# Check the result
assert result == {"result": "success"}

@patch(
"google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool._request"
)
@pytest.mark.asyncio
async def test_call_does_not_add_auth_params_to_caller_args(
self,
mock_request,
mock_tool_context,
sample_endpoint,
sample_operation,
):
"""The caller's args also feed after-tool callbacks and the tool span."""
mock_response = MagicMock()
mock_response.json.return_value = {"result": "success"}
mock_request.return_value = mock_response
auth_scheme, auth_credential = token_to_scheme_credential(
"apikey", "header", "X-API-Key", "secret-api-key"
)
tool = RestApiTool(
name="test_tool",
description="Test Tool",
endpoint=sample_endpoint,
operation=sample_operation,
auth_scheme=auth_scheme,
auth_credential=auth_credential,
)
args = {"testBodyParam": "value"}

await tool.call(args=args, tool_context=mock_tool_context)

assert args == {"testBodyParam": "value"}
assert (
mock_request.call_args.kwargs["headers"]["X-API-Key"]
== "secret-api-key"
)

@patch(
"google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool._request"
)
Expand Down
Loading