Initial upload with full project structure
This commit is contained in:
103
app/src/confgen/formatter.py
Normal file
103
app/src/confgen/formatter.py
Normal file
@@ -0,0 +1,103 @@
|
||||
"""Output formatting with secret masking."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
class OutputFormatter:
|
||||
"""Formatter for configuration output with secret masking."""
|
||||
|
||||
SECRET_PATTERNS = [
|
||||
"SECRET_",
|
||||
"PASSWORD",
|
||||
"API_KEY",
|
||||
"API_SECRET",
|
||||
"CREDENTIAL",
|
||||
"TOKEN",
|
||||
"PRIVATE_KEY",
|
||||
"DB_PASSWORD",
|
||||
"AUTH",
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def format_value(self, value: Any, masked: bool = False) -> str:
|
||||
"""Format a single value for display."""
|
||||
if masked or self._is_secret(str(value)):
|
||||
return "***"
|
||||
return str(value)
|
||||
|
||||
def _is_secret(self, value: str) -> bool:
|
||||
"""Check if a value appears to be a secret."""
|
||||
value_upper = value.upper()
|
||||
return any(pattern in value_upper for pattern in self.SECRET_PATTERNS)
|
||||
|
||||
def mask_content(self, content: str) -> str:
|
||||
"""Mask secret values in content."""
|
||||
import re
|
||||
|
||||
patterns = [
|
||||
(r"{{env\.([A-Z0-9_]+)}}", "***"),
|
||||
(r"{{vault\.([A-Z0-9_]+)}}", "***"),
|
||||
(r"(\b[A-Z0-9_]*SECRET[A-Z0-9_]*\b)", "***"),
|
||||
(r"(\b[A-Z0-9_]*PASSWORD[A-Z0-9_]*\b)", "***"),
|
||||
(r"(\b[A-Z0-9_]*API_KEY[A-Z0-9_]*\b)", "***"),
|
||||
(r"(\b[A-Z0-9_]*TOKEN[A-Z0-9_]*\b)", "***"),
|
||||
]
|
||||
|
||||
for pattern, _ in patterns:
|
||||
content = re.sub(pattern, "***", content, flags=re.IGNORECASE)
|
||||
|
||||
return content
|
||||
|
||||
def format_dict(self, data: dict[str, Any], indent: int = 0) -> str:
|
||||
"""Format a dictionary for display with secret masking."""
|
||||
lines = []
|
||||
prefix = " " * indent
|
||||
|
||||
for key, value in data.items():
|
||||
if isinstance(value, dict):
|
||||
lines.append(f"{prefix}{key}:")
|
||||
lines.append(self.format_dict(value, indent + 1))
|
||||
elif isinstance(value, list):
|
||||
lines.append(f"{prefix}{key}:")
|
||||
for item in value:
|
||||
if isinstance(item, dict):
|
||||
lines.append(f"{prefix} -")
|
||||
lines.append(self.format_dict(item, indent + 2))
|
||||
else:
|
||||
masked = self._is_secret(str(item))
|
||||
lines.append(f"{prefix} - {self.format_value(item, masked)}")
|
||||
else:
|
||||
masked = self._is_secret(key) or self._is_secret(str(value))
|
||||
lines.append(f"{prefix}{key}: {self.format_value(value, masked)}")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
def format_json(self, data: dict[str, Any], indent: int = 2) -> str:
|
||||
"""Format data as JSON with secret masking."""
|
||||
import json
|
||||
|
||||
masked_data = self._mask_dict(data)
|
||||
return json.dumps(masked_data, indent=indent, ensure_ascii=False)
|
||||
|
||||
def _mask_dict(self, data: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Recursively mask secrets in a dictionary."""
|
||||
masked = {}
|
||||
for key, value in data.items():
|
||||
if isinstance(value, dict):
|
||||
masked[key] = self._mask_dict(value)
|
||||
elif isinstance(value, list):
|
||||
masked[key] = [
|
||||
self._mask_dict(item) if isinstance(item, dict) else self._mask_value(item)
|
||||
for item in value
|
||||
]
|
||||
else:
|
||||
masked[key] = self._mask_value(value)
|
||||
return masked
|
||||
|
||||
def _mask_value(self, value: Any) -> Any:
|
||||
"""Mask a single value if it's a secret."""
|
||||
if isinstance(value, str) and self._is_secret(value):
|
||||
return "***"
|
||||
return value
|
||||
Reference in New Issue
Block a user