新增了包括密钥加解密、配置健康检查、原子写入、审计、解析器以及 scrubber 在内的完整 secrets 模块,实现了明文密钥检测替换、密钥引用解析和配置安全校验能力
105 lines
3.3 KiB
Python
105 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
import copy
|
|
import hashlib
|
|
import json
|
|
import logging
|
|
from collections.abc import Callable
|
|
from dataclasses import dataclass, field
|
|
from datetime import UTC, datetime
|
|
from enum import StrEnum
|
|
from typing import Any
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class ConfigHealthStatus(StrEnum):
|
|
HEALTHY = "healthy"
|
|
SUSPECT = "suspect"
|
|
BROKEN = "broken"
|
|
|
|
|
|
@dataclass
|
|
class ConfigHealth:
|
|
status: ConfigHealthStatus = ConfigHealthStatus.HEALTHY
|
|
last_known_good: str | None = None
|
|
last_promoted_good: str | None = None
|
|
last_checked_at: datetime | None = None
|
|
issues: list[str] = field(default_factory=list)
|
|
revision: int = 0
|
|
last_known_good_config: dict[str, Any] | None = None
|
|
|
|
@staticmethod
|
|
def compute_fingerprint(config: dict[str, Any]) -> str:
|
|
raw = json.dumps(config, sort_keys=True, default=str, ensure_ascii=False)
|
|
return hashlib.sha256(raw.encode()).hexdigest()[:12]
|
|
|
|
def promote(self, config: dict[str, Any]) -> None:
|
|
fingerprint = self.compute_fingerprint(config)
|
|
self.last_known_good = fingerprint
|
|
self.last_promoted_good = fingerprint
|
|
self.last_known_good_config = copy.deepcopy(config)
|
|
self.revision += 1
|
|
self.last_checked_at = datetime.now(UTC)
|
|
self.status = ConfigHealthStatus.HEALTHY
|
|
self.issues.clear()
|
|
|
|
def mark_suspect(self, reason: str) -> None:
|
|
self.status = ConfigHealthStatus.SUSPECT
|
|
self.issues.append(reason)
|
|
self.last_checked_at = datetime.now(UTC)
|
|
|
|
def mark_broken(self, reason: str) -> None:
|
|
self.status = ConfigHealthStatus.BROKEN
|
|
self.issues.append(reason)
|
|
self.last_checked_at = datetime.now(UTC)
|
|
|
|
def can_auto_recover(self) -> bool:
|
|
return (
|
|
self.last_known_good is not None
|
|
and self.last_known_good_config is not None
|
|
and self.status
|
|
in (
|
|
ConfigHealthStatus.SUSPECT,
|
|
ConfigHealthStatus.BROKEN,
|
|
)
|
|
)
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return {
|
|
"status": self.status.value,
|
|
"last_known_good": self.last_known_good,
|
|
"last_promoted_good": self.last_promoted_good,
|
|
"last_checked_at": self.last_checked_at.isoformat() if self.last_checked_at else None,
|
|
"issues": self.issues,
|
|
"revision": self.revision,
|
|
"has_last_known_good_config": self.last_known_good_config is not None,
|
|
}
|
|
|
|
|
|
def track_config_health(
|
|
health: ConfigHealth,
|
|
config: dict[str, Any],
|
|
validate_fn: Callable[[dict[str, Any]], list[str]] | None = None,
|
|
) -> ConfigHealth:
|
|
fingerprint = ConfigHealth.compute_fingerprint(config)
|
|
|
|
if fingerprint == health.last_known_good:
|
|
return health
|
|
|
|
health.last_checked_at = datetime.now(UTC)
|
|
|
|
issues = validate_fn(config) if validate_fn else []
|
|
if issues:
|
|
health.mark_suspect(f"Validation issues: {'; '.join(issues)}")
|
|
else:
|
|
if health.status in (ConfigHealthStatus.SUSPECT, ConfigHealthStatus.BROKEN):
|
|
health.promote(config)
|
|
else:
|
|
health.status = ConfigHealthStatus.HEALTHY
|
|
health.last_known_good = fingerprint
|
|
health.last_known_good_config = copy.deepcopy(config)
|
|
health.revision += 1
|
|
|
|
return health
|