2121
2222T = TypeVar ("T" )
2323
24+ SENSITIVE_FIELDS = {
25+ "runtime_envs" ,
26+ "runtime_apikey_name" ,
27+ "runtime_apikey" ,
28+ "runtime_jwt_discovery_url" ,
29+ "runtime_jwt_allowed_clients" ,
30+ }
31+
32+
33+ def _get_safe_value (field_name : str , value : Any ) -> Any :
34+ if field_name in SENSITIVE_FIELDS :
35+ return "******"
36+ return value
37+
38+
39+ def _sanitize_dict (data : Dict [str , Any ]) -> Dict [str , Any ]:
40+ """Sanitize sensitive fields in a dictionary."""
41+ if not isinstance (data , dict ):
42+ return data
43+ return {k : _get_safe_value (k , v ) for k , v in data .items ()}
44+
45+
46+ def _sanitize_diff (diff : Dict [str , Any ]) -> Dict [str , Any ]:
47+ """Sanitize sensitive fields in a diff dictionary."""
48+ if not isinstance (diff , dict ):
49+ return diff
50+ sanitized = {}
51+ for k , v in diff .items ():
52+ if k in SENSITIVE_FIELDS :
53+ sanitized [k ] = ("******" , "******" )
54+ else :
55+ sanitized [k ] = v
56+ return sanitized
57+
2458
2559class DataclassSerializer :
2660 @staticmethod
@@ -50,7 +84,7 @@ def from_dict(cls: Type[T], data: Dict[str, Any]) -> T:
5084 logger .debug (
5185 "[DataclassSerializer] source=local field=%s value=%r" ,
5286 field_name ,
53- kwargs [field_name ],
87+ _get_safe_value ( field_name , kwargs [field_name ]) ,
5488 )
5589 else :
5690 # Try aliases (backward compatibility)
@@ -65,7 +99,7 @@ def from_dict(cls: Type[T], data: Dict[str, Any]) -> T:
6599 "[DataclassSerializer] source=alias(%s) -> local field=%s value=%r" ,
66100 alias ,
67101 field_name ,
68- kwargs [field_name ],
102+ _get_safe_value ( field_name , kwargs [field_name ]) ,
69103 )
70104 break
71105
@@ -77,15 +111,15 @@ def from_dict(cls: Type[T], data: Dict[str, Any]) -> T:
77111 logger .debug (
78112 "[DataclassSerializer] source=default_factory field=%s value=%r" ,
79113 field_name ,
80- kwargs [field_name ],
114+ _get_safe_value ( field_name , kwargs [field_name ]) ,
81115 )
82116 elif field .default is not MISSING :
83117 kwargs [field_name ] = field .default
84118 _sources [field_name ] = "default"
85119 logger .debug (
86120 "[DataclassSerializer] source=default field=%s value=%r" ,
87121 field_name ,
88- kwargs [field_name ],
122+ _get_safe_value ( field_name , kwargs [field_name ]) ,
89123 )
90124 else :
91125 kwargs [field_name ] = None
@@ -157,7 +191,11 @@ def from_dict(cls: Type[T], data: Dict[str, Any], skip_render: bool = False) ->
157191 from .global_config import apply_global_config_defaults
158192
159193 before = instance .to_dict ()
160- logger .debug ("from_dict: before globals for %s -> %r" , cls .__name__ , before )
194+ logger .debug (
195+ "from_dict: before globals for %s -> %r" ,
196+ cls .__name__ ,
197+ _sanitize_dict (before ),
198+ )
161199 instance = apply_global_config_defaults (instance , data )
162200 after = instance .to_dict ()
163201 if before != after :
@@ -169,7 +207,7 @@ def from_dict(cls: Type[T], data: Dict[str, Any], skip_render: bool = False) ->
169207 logger .debug (
170208 "from_dict: applied global defaults for %s; changes=%r" ,
171209 cls .__name__ ,
172- diff ,
210+ _sanitize_diff ( diff ) ,
173211 )
174212 else :
175213 logger .debug (
@@ -254,7 +292,7 @@ def _render_template_fields(self):
254292 "[%s] [template] start field render check: name=%s, value=%r, has_placeholders=%s" ,
255293 cfg_name ,
256294 field_info .name ,
257- field_value ,
295+ _get_safe_value ( field_info . name , field_value ) ,
258296 (
259297 isinstance (field_value , str )
260298 and ("{{" in field_value and "}}" in field_value )
@@ -269,7 +307,7 @@ def _render_template_fields(self):
269307 "[%s] [template] field %s is Auto/empty -> using default_template=%r" ,
270308 cfg_name ,
271309 field_info .name ,
272- default_template ,
310+ _get_safe_value ( field_info . name , default_template ) ,
273311 )
274312 field_value = default_template
275313 self ._template_originals [field_info .name ] = default_template
@@ -300,17 +338,20 @@ def _render_template_fields(self):
300338 "[%s] [template] save original template for %s: %r" ,
301339 cfg_name ,
302340 field_info .name ,
303- field_value ,
341+ _get_safe_value ( field_info . name , field_value ) ,
304342 )
305343
306344 try :
307- rendered = render_template (field_value )
345+ is_sensitive = field_info .name in SENSITIVE_FIELDS
346+ rendered = render_template (
347+ field_value , sensitive = is_sensitive
348+ )
308349 logger .debug (
309350 "[%s] [template] rendered field %s: %r -> %r" ,
310351 cfg_name ,
311352 field_info .name ,
312- field_value ,
313- rendered ,
353+ _get_safe_value ( field_info . name , field_value ) ,
354+ _get_safe_value ( field_info . name , rendered ) ,
314355 )
315356 # Fail if unresolved placeholders remain
316357 if "{{" in str (rendered ) and "}}" in str (rendered ):
@@ -356,7 +397,9 @@ def _render_template_fields(self):
356397 "[%s] [template] field %s is not marked for rendering, value: %r" ,
357398 cfg_name ,
358399 field_info .name ,
359- getattr (self , field_info .name ),
400+ _get_safe_value (
401+ field_info .name , getattr (self , field_info .name )
402+ ),
360403 )
361404 except ImportError :
362405 # If template utils are not available, no-op
0 commit comments