This commit is contained in:
2026-03-03 14:39:54 +08:00
parent 6425275d4b
commit 7294e07df7

View File

@@ -72,54 +72,56 @@ class InstantiateConfig(PrintableConfig):
将配置保存到 YAML 文件 将配置保存到 YAML 文件
""" """
def mask_value(key, value): def mask_value(key, value):
""" """
Apply masking if key is secret-like Apply masking if key is secret-like
如果键是敏感的,应用掩码 如果键是敏感的,应用掩码
检查键是否敏感(如包含 "secret""api_key"),如果是,则对值进行掩码处理 检查键是否敏感(如包含 "secret""api_key"),如果是,则对值进行掩码处理
""" """
if isinstance(value, str) and self.is_secrete(key): if isinstance(value, str) and self.is_secrete(str(key)):
sval = str(value) sval = str(value)
return sval[:3] + "*" * (len(sval) - 6) + sval[-3:] return sval[:3] + "*" * (len(sval) - 6) + sval[-3:]
return value return value
def to_masked_serializable(obj): def to_serializable(obj, apply_mask: bool):
""" """
Recursively convert dataclasses and containers to serializable with masked secrets Recursively convert dataclasses and containers to serializable format,
optionally masking secrets.
递归地将数据类和容器转换为可序列化的格式,同时对敏感信息进行掩码处理
递归地将数据类和容器转换为可序列化的格式,可选地对敏感信息进行掩码处理
""" """
if is_dataclass(obj): if is_dataclass(obj):
out = {} out = {}
for k, v in vars(obj).items(): for k, v in vars(obj).items():
if is_dataclass(v) or isinstance(v, (dict, list, tuple)): if is_dataclass(v) or isinstance(v, (dict, list, tuple)):
out[k] = to_masked_serializable(v) out[k] = to_serializable(v, apply_mask)
else: else:
out[k] = mask_value(k, v) out[k] = mask_value(k, v) if apply_mask else v
return out return out
if isinstance(obj, dict): if isinstance(obj, dict):
out = {} out = {}
for k, v in obj.items(): for k, v in obj.items():
if is_dataclass(v) or isinstance(v, (dict, list, tuple)): if is_dataclass(v) or isinstance(v, (dict, list, tuple)):
out[k] = to_masked_serializable(v) out[k] = to_serializable(v, apply_mask)
else: else:
# k might be a non-string; convert to str for is_secrete check consistency
key_str = str(k) key_str = str(k)
out[k] = mask_value(key_str, v) out[k] = mask_value(key_str, v) if apply_mask else v
return out return out
if isinstance(obj, list): if isinstance(obj, list):
return [to_masked_serializable(v) for v in obj] return [to_serializable(v, apply_mask) for v in obj]
if isinstance(obj, tuple): if isinstance(obj, tuple):
return tuple(to_masked_serializable(v) for v in obj) return tuple(to_serializable(v, apply_mask) for v in obj)
return obj return obj
masked = to_masked_serializable(self) # NOTE: we intentionally do NOT mask secrets when saving to disk so that
# configs can be reloaded with real values. Masking is handled in __str__
# for safe logging/printing. If you need a redacted copy, call
# to_serializable(self, apply_mask=True) manually and dump it yourself.
serializable = to_serializable(self, apply_mask=False)
with open(filename, 'w') as f: with open(filename, 'w') as f:
yaml.dump(masked, f) yaml.dump(serializable, f)
logger.info(f"[yellow]config saved to: {filename}[/yellow]") logger.info(f"[yellow]config saved to: {filename}[/yellow]")
def get_name(self): def get_name(self):