1616
1717from __future__ import annotations
1818
19+ import logging
1920import os
2021from pathlib import Path
21- from unittest . mock import Mock
22+ from unittest import mock
2223
2324from google .adk .artifacts .file_artifact_service import FileArtifactService
2425from google .adk .artifacts .in_memory_artifact_service import InMemoryArtifactService
26+ from google .adk .cli .service_registry import ServiceRegistry
2527from google .adk .cli .utils .local_storage import PerAgentDatabaseSessionService
2628import google .adk .cli .utils .service_factory as service_factory
2729from google .adk .memory .in_memory_memory_service import InMemoryMemoryService
3133
3234
3335def test_create_session_service_uses_registry (tmp_path : Path , monkeypatch ):
34- registry = Mock ( )
36+ registry = mock . create_autospec ( ServiceRegistry , instance = True , spec_set = True )
3537 expected = object ()
3638 registry .create_session_service .return_value = expected
3739 monkeypatch .setattr (service_factory , "get_service_registry" , lambda : registry )
@@ -48,6 +50,87 @@ def test_create_session_service_uses_registry(tmp_path: Path, monkeypatch):
4850 )
4951
5052
53+ def test_create_session_service_logs_redacted_uri (
54+ tmp_path : Path ,
55+ monkeypatch : pytest .MonkeyPatch ,
56+ caplog : pytest .LogCaptureFixture ,
57+ ) -> None :
58+ registry = mock .create_autospec (ServiceRegistry , instance = True , spec_set = True )
59+ registry .create_session_service .return_value = object ()
60+ monkeypatch .setattr (service_factory , "get_service_registry" , lambda : registry )
61+
62+ session_service_uri = (
63+ "postgresql://user:supersecret@localhost:5432/dbname?sslmode=require"
64+ )
65+ caplog .set_level (logging .INFO , logger = service_factory .logger .name )
66+
67+ service_factory .create_session_service_from_options (
68+ base_dir = tmp_path ,
69+ session_service_uri = session_service_uri ,
70+ )
71+
72+ assert "supersecret" not in caplog .text
73+ assert "sslmode=require" not in caplog .text
74+ assert "localhost:5432" in caplog .text
75+
76+
77+ def test_redact_uri_for_log_removes_credentials_with_at_in_password () -> None :
78+ uri = "postgresql://user:super@secret@localhost:5432/dbname"
79+
80+ assert (
81+ service_factory ._redact_uri_for_log (uri )
82+ == "postgresql://localhost:5432/dbname"
83+ )
84+
85+
86+ def test_redact_uri_for_log_preserves_host_when_no_credentials () -> None :
87+ uri = "postgresql://localhost:5432/dbname?sslmode=require&password=secret"
88+
89+ redacted = service_factory ._redact_uri_for_log (uri )
90+
91+ assert redacted .startswith ("postgresql://localhost:5432/dbname?" )
92+ assert "require" not in redacted
93+ assert "secret" not in redacted
94+ assert "sslmode=<redacted>" in redacted
95+ assert "password=<redacted>" in redacted
96+
97+
98+ def test_redact_uri_for_log_redacts_when_parse_qsl_fails (
99+ monkeypatch : pytest .MonkeyPatch ,
100+ ) -> None :
101+ def _raise_value_error (* _args , ** _kwargs ):
102+ raise ValueError ("bad query" )
103+
104+ monkeypatch .setattr (service_factory , "parse_qsl" , _raise_value_error )
105+
106+ uri = "postgresql://user:pass@localhost:5432/dbname?sslmode=require"
107+ redacted = service_factory ._redact_uri_for_log (uri )
108+
109+ assert "pass" not in redacted
110+ assert "require" not in redacted
111+ assert redacted .endswith ("?<redacted>" )
112+
113+
114+ def test_redact_uri_for_log_escapes_crlf () -> None :
115+ uri = (
116+ "postgresql://user:pass@localhost:5432/dbname\r INJECT\n INJECT"
117+ "?sslmode=require"
118+ )
119+
120+ redacted = service_factory ._redact_uri_for_log (uri )
121+
122+ assert "\r " not in redacted
123+ assert "\n " not in redacted
124+ assert "\\ rINJECT\\ nINJECT" in redacted
125+
126+
127+ def test_redact_uri_for_log_returns_scheme_missing_without_separator () -> None :
128+ assert (
129+ service_factory ._redact_uri_for_log ("user:pass@localhost:5432/dbname" )
130+ == "<scheme-missing>"
131+ )
132+
133+
51134@pytest .mark .asyncio
52135async def test_create_session_service_defaults_to_per_agent_sqlite (
53136 tmp_path : Path ,
@@ -88,7 +171,7 @@ async def test_create_session_service_respects_app_name_mapping(
88171def test_create_session_service_fallbacks_to_database (
89172 tmp_path : Path , monkeypatch
90173):
91- registry = Mock ( )
174+ registry = mock . create_autospec ( ServiceRegistry , instance = True , spec_set = True )
92175 registry .create_session_service .return_value = None
93176 monkeypatch .setattr (service_factory , "get_service_registry" , lambda : registry )
94177
@@ -109,7 +192,7 @@ def test_create_session_service_fallbacks_to_database(
109192
110193
111194def test_create_artifact_service_uses_registry (tmp_path : Path , monkeypatch ):
112- registry = Mock ( )
195+ registry = mock . create_autospec ( ServiceRegistry , instance = True , spec_set = True )
113196 expected = object ()
114197 registry .create_artifact_service .return_value = expected
115198 monkeypatch .setattr (service_factory , "get_service_registry" , lambda : registry )
@@ -129,7 +212,7 @@ def test_create_artifact_service_uses_registry(tmp_path: Path, monkeypatch):
129212def test_create_artifact_service_raises_on_unknown_scheme_when_strict (
130213 tmp_path : Path , monkeypatch
131214):
132- registry = Mock ( )
215+ registry = mock . create_autospec ( ServiceRegistry , instance = True , spec_set = True )
133216 registry .create_artifact_service .return_value = None
134217 monkeypatch .setattr (service_factory , "get_service_registry" , lambda : registry )
135218
@@ -142,7 +225,7 @@ def test_create_artifact_service_raises_on_unknown_scheme_when_strict(
142225
143226
144227def test_create_memory_service_uses_registry (tmp_path : Path , monkeypatch ):
145- registry = Mock ( )
228+ registry = mock . create_autospec ( ServiceRegistry , instance = True , spec_set = True )
146229 expected = object ()
147230 registry .create_memory_service .return_value = expected
148231 monkeypatch .setattr (service_factory , "get_service_registry" , lambda : registry )
@@ -170,7 +253,7 @@ def test_create_memory_service_defaults_to_in_memory(tmp_path: Path):
170253def test_create_memory_service_raises_on_unknown_scheme (
171254 tmp_path : Path , monkeypatch
172255):
173- registry = Mock ( )
256+ registry = mock . create_autospec ( ServiceRegistry , instance = True , spec_set = True )
174257 registry .create_memory_service .return_value = None
175258 monkeypatch .setattr (service_factory , "get_service_registry" , lambda : registry )
176259
0 commit comments