Skip to content

Commit f91cb17

Browse files
committed
Restore token-based auth helpers for Secret and Parameter Manager
Both integration helpers advertised an auth_token constructor path, but the implementation instantiated google.auth.credentials.Credentials directly. That base class is abstract, so callers hit a TypeError before any request could be made. This patch switches both helpers to a concrete OAuth2 Credentials object and adds regression coverage that exercises the real constructor path. The SecretManager helper also now rejects service_account_json + auth_token up front so its behavior matches its own documented contract. Constraint: Keep the change narrow to the validated auth helper regressions Rejected: Leave the existing mocked constructor tests in place | they masked the real runtime failure Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep token-path tests using the real credentials class so abstract-constructor regressions do not reappear Tested: .venv/bin/pytest tests/unittests/integrations/secret_manager/test_secret_client.py tests/unittests/integrations/parameter_manager/test_parameter_client.py -q Not-tested: Full repo test suite; lint tooling was not installed in the local venv
1 parent e3060ca commit f91cb17

4 files changed

Lines changed: 48 additions & 64 deletions

File tree

src/google/adk/integrations/parameter_manager/parameter_client.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@
1919
from typing import Optional
2020

2121
from google.api_core.gapic_v1 import client_info
22-
import google.auth
2322
from google.auth import default as default_service_credential
24-
import google.auth.transport.requests
2523
from google.cloud import parametermanager_v1
24+
from google.oauth2 import credentials as user_credentials
2625
from google.oauth2 import service_account
2726

2827
from ... import version
@@ -81,15 +80,7 @@ def __init__(
8180
except json.JSONDecodeError as e:
8281
raise ValueError(f"Invalid service account JSON: {e}") from e
8382
elif auth_token:
84-
credentials = google.auth.credentials.Credentials(
85-
token=auth_token,
86-
refresh_token=None,
87-
token_uri=None,
88-
client_id=None,
89-
client_secret=None,
90-
)
91-
request = google.auth.transport.requests.Request()
92-
credentials.refresh(request)
83+
credentials = user_credentials.Credentials(token=auth_token)
9384
else:
9485
try:
9586
credentials, _ = default_service_credential(

src/google/adk/integrations/secret_manager/secret_client.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@
1919
from typing import Optional
2020

2121
from google.api_core.gapic_v1 import client_info
22-
import google.auth
2322
from google.auth import default as default_service_credential
24-
import google.auth.transport.requests
2523
from google.cloud import secretmanager
24+
from google.oauth2 import credentials as user_credentials
2625
from google.oauth2 import service_account
2726

2827
from ... import version
@@ -65,6 +64,12 @@ def __init__(
6564
is not valid JSON.
6665
google.auth.exceptions.GoogleAuthError: If authentication fails.
6766
"""
67+
if service_account_json and auth_token:
68+
raise ValueError(
69+
"Must provide either 'service_account_json' or 'auth_token', not"
70+
" both."
71+
)
72+
6873
if service_account_json:
6974
try:
7075
credentials = service_account.Credentials.from_service_account_info(
@@ -73,15 +78,7 @@ def __init__(
7378
except json.JSONDecodeError as e:
7479
raise ValueError(f"Invalid service account JSON: {e}") from e
7580
elif auth_token:
76-
credentials = google.auth.credentials.Credentials(
77-
token=auth_token,
78-
refresh_token=None,
79-
token_uri=None,
80-
client_id=None,
81-
client_secret=None,
82-
)
83-
request = google.auth.transport.requests.Request()
84-
credentials.refresh(request)
81+
credentials = user_credentials.Credentials(token=auth_token)
8582
else:
8683
try:
8784
credentials, _ = default_service_credential(

tests/unittests/integrations/parameter_manager/test_parameter_client.py

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from google.adk.integrations.parameter_manager.parameter_client import ParameterManagerClient
2222
from google.adk.integrations.parameter_manager.parameter_client import USER_AGENT
2323
from google.api_core.gapic_v1 import client_info
24+
from google.oauth2.credentials import Credentials
2425
import pytest
2526

2627

@@ -92,28 +93,19 @@ def test_init_with_service_account_json(
9293
@patch("google.cloud.parametermanager_v1.ParameterManagerClient")
9394
def test_init_with_auth_token(self, mock_pm_client_class):
9495
"""Test initialization with auth token."""
95-
# Setup
9696
auth_token = "test-token"
97-
mock_credentials = MagicMock()
9897

99-
with (
100-
patch("google.auth.credentials.Credentials") as mock_credentials_class,
101-
patch("google.auth.transport.requests.Request") as mock_request,
102-
):
103-
mock_credentials_class.return_value = mock_credentials
104-
105-
# Execute
106-
client = ParameterManagerClient(auth_token=auth_token)
107-
108-
# Verify
109-
mock_credentials.refresh.assert_called_once()
110-
mock_pm_client_class.assert_called_once()
111-
call_kwargs = mock_pm_client_class.call_args.kwargs
112-
assert call_kwargs["credentials"] == mock_credentials
113-
assert call_kwargs["client_options"] is None
114-
assert call_kwargs["client_info"].user_agent == USER_AGENT
115-
assert client._credentials == mock_credentials
116-
assert client._client == mock_pm_client_class.return_value
98+
client = ParameterManagerClient(auth_token=auth_token)
99+
100+
mock_pm_client_class.assert_called_once()
101+
call_kwargs = mock_pm_client_class.call_args.kwargs
102+
assert isinstance(call_kwargs["credentials"], Credentials)
103+
assert call_kwargs["credentials"].token == auth_token
104+
assert call_kwargs["client_options"] is None
105+
assert call_kwargs["client_info"].user_agent == USER_AGENT
106+
assert isinstance(client._credentials, Credentials)
107+
assert client._credentials.token == auth_token
108+
assert client._client == mock_pm_client_class.return_value
117109

118110
@patch("google.cloud.parametermanager_v1.ParameterManagerClient")
119111
@patch(

tests/unittests/integrations/secret_manager/test_secret_client.py

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from google.adk.integrations.secret_manager.secret_client import SecretManagerClient
2222
from google.adk.integrations.secret_manager.secret_client import USER_AGENT
2323
from google.api_core.gapic_v1 import client_info
24+
from google.oauth2.credentials import Credentials
2425
import pytest
2526

2627
import google
@@ -94,30 +95,19 @@ def test_init_with_service_account_json(
9495
@patch("google.cloud.secretmanager.SecretManagerServiceClient")
9596
def test_init_with_auth_token(self, mock_secret_manager_client):
9697
"""Test initialization with auth token."""
97-
# Setup
9898
auth_token = "test-token"
99-
mock_credentials = MagicMock()
10099

101-
# Mock the entire credentials creation process
102-
with (
103-
patch("google.auth.credentials.Credentials") as mock_credentials_class,
104-
patch("google.auth.transport.requests.Request") as mock_request,
105-
):
106-
# Configure the mock to return our mock_credentials when instantiated
107-
mock_credentials_class.return_value = mock_credentials
108-
109-
# Execute
110-
client = SecretManagerClient(auth_token=auth_token)
111-
112-
# Verify
113-
mock_credentials.refresh.assert_called_once()
114-
mock_secret_manager_client.assert_called_once()
115-
call_kwargs = mock_secret_manager_client.call_args.kwargs
116-
assert call_kwargs["credentials"] == mock_credentials
117-
assert call_kwargs["client_options"] is None
118-
assert call_kwargs["client_info"].user_agent == USER_AGENT
119-
assert client._credentials == mock_credentials
120-
assert client._client == mock_secret_manager_client.return_value
100+
client = SecretManagerClient(auth_token=auth_token)
101+
102+
mock_secret_manager_client.assert_called_once()
103+
call_kwargs = mock_secret_manager_client.call_args.kwargs
104+
assert isinstance(call_kwargs["credentials"], Credentials)
105+
assert call_kwargs["credentials"].token == auth_token
106+
assert call_kwargs["client_options"] is None
107+
assert call_kwargs["client_info"].user_agent == USER_AGENT
108+
assert isinstance(client._credentials, Credentials)
109+
assert client._credentials.token == auth_token
110+
assert client._client == mock_secret_manager_client.return_value
121111

122112
@patch("google.cloud.secretmanager.SecretManagerServiceClient")
123113
@patch(
@@ -170,6 +160,20 @@ def test_init_with_invalid_service_account_json(self):
170160
with pytest.raises(ValueError, match="Invalid service account JSON"):
171161
SecretManagerClient(service_account_json="invalid-json")
172162

163+
def test_init_with_both_service_account_json_and_auth_token(self):
164+
"""Test initialization rejects conflicting credential inputs."""
165+
with pytest.raises(
166+
ValueError,
167+
match=(
168+
"Must provide either 'service_account_json' or 'auth_token', not"
169+
" both."
170+
),
171+
):
172+
SecretManagerClient(
173+
service_account_json=json.dumps({"type": "service_account"}),
174+
auth_token="test-token",
175+
)
176+
173177
@patch("google.cloud.secretmanager.SecretManagerServiceClient")
174178
@patch(
175179
"google.adk.integrations.secret_manager.secret_client.default_service_credential"

0 commit comments

Comments
 (0)