Initial upload: Code Privacy Shield v0.1.0
Some checks failed
CI / test (push) Has been cancelled

This commit is contained in:
2026-02-02 20:50:57 +00:00
parent fa7cff98de
commit 662baeb13c

View File

@@ -0,0 +1,217 @@
import copy
import os
from pathlib import Path
from typing import Any, Dict, List, Optional
import toml
class Config:
DEFAULT_CONFIG = {
"general": {
"preview_mode": False,
"quiet_mode": False,
"preserve_structure": True,
"recursive": True,
},
"redaction": {
"default_replacement": "" * 8,
"preserve_length": False,
"categories": {
"api_keys": True,
"pii": True,
"database": True,
"env_var": True,
"ip": True,
"authorization": True,
},
},
"custom_patterns": [],
"exclude_patterns": [
"*.pyc",
"__pycache__",
".git",
".svn",
".hg",
"node_modules",
".env",
"*.egg-info",
"dist",
"build",
],
"output": {
"format": "text",
"show_line_numbers": False,
"color_output": True,
},
}
def __init__(self, config_path: Optional[str] = None):
self.config_path = config_path
self.config: Dict[str, Any] = copy.deepcopy(self.DEFAULT_CONFIG)
@classmethod
def get_default_config_path(cls) -> Path:
return Path.home() / ".config" / "cps" / "config.toml"
@classmethod
def get_project_config_path(cls) -> Path:
return Path(".cps.toml")
@classmethod
def get_local_config_path(cls) -> Path:
return Path(".cps")
def load(self, path: Optional[str] = None) -> bool:
path = path or self.config_path
if path:
return self._load_from_file(path)
loaded_any = False
project_path = self.get_project_config_path()
if project_path.exists():
loaded_any = self._load_from_file(str(project_path)) or loaded_any
default_path = self.get_default_config_path()
if default_path.exists():
loaded_any = self._load_from_file(str(default_path)) or loaded_any
return loaded_any
def _load_from_file(self, path: str) -> bool:
try:
file_path = Path(path)
if not file_path.exists():
return False
content = file_path.read_text()
loaded_config = toml.loads(content)
self._merge_config(self.config, loaded_config)
return True
except (toml.TomlDecodeError, IOError, PermissionError):
return False
def _merge_config(self, base: Dict[str, Any], override: Dict[str, Any]) -> None:
for key, value in override.items():
if key in base and isinstance(base[key], dict) and isinstance(value, dict):
self._merge_config(base[key], value)
else:
base[key] = value
def get(self, key: str, default: Any = None) -> Any:
keys = key.split(".")
value = self.config
for k in keys:
if isinstance(value, dict) and k in value:
value = value[k]
else:
return default
return value
def set(self, key: str, value: Any) -> None:
keys = key.split(".")
config = self.config
for k in keys[:-1]:
if k not in config:
config[k] = {}
config = config[k]
config[keys[-1]] = value
def get_redaction_categories(self) -> Dict[str, bool]:
return self.config.get("redaction", {}).get("categories", {})
def get_exclude_patterns(self) -> List[str]:
return self.config.get("exclude_patterns", [])
def get_custom_patterns(self) -> List[Dict[str, str]]:
return self.config.get("custom_patterns", [])
def is_category_enabled(self, category: str) -> bool:
categories = self.get_redaction_categories()
return categories.get(category, True)
def is_preview_mode(self) -> bool:
return self.config.get("general", {}).get("preview_mode", False)
def is_quiet_mode(self) -> bool:
return self.config.get("general", {}).get("quiet_mode", False)
def should_preserve_structure(self) -> bool:
return self.config.get("general", {}).get("preserve_structure", True)
def should_recursive(self) -> bool:
return self.config.get("general", {}).get("recursive", True)
def get_output_format(self) -> str:
return self.config.get("output", {}).get("format", "text")
def save(self, path: Optional[str] = None) -> bool:
path = path or self.config_path
if not path:
return False
try:
content = toml.dumps(self.config)
Path(path).write_text(content)
return True
except (IOError, PermissionError):
return False
def reset_to_default(self) -> None:
self.config = copy.deepcopy(self.DEFAULT_CONFIG)
@classmethod
def create_example_config(cls, path: str) -> bool:
example = {
"general": {
"preview_mode": False,
"quiet_mode": False,
"preserve_structure": True,
"recursive": True,
},
"redaction": {
"default_replacement": "" * 8,
"preserve_length": False,
"categories": {
"api_keys": True,
"pii": True,
"database": True,
"env_var": True,
"ip": True,
"authorization": True,
},
},
"custom_patterns": [
{
"name": "Internal API",
"pattern": r"(?i)(internal[_-]?api[_-]?key['\"]?\s*[:=]\s*['\"]?)([a-zA-Z0-9_-]{16,})",
"category": "internal",
},
],
"exclude_patterns": [
"*.pyc",
"__pycache__",
".git",
".svn",
"node_modules",
".env",
"dist",
"build",
],
"output": {
"format": "text",
"show_line_numbers": False,
"color_output": True,
},
}
try:
Path(path).write_text(toml.dumps(example))
return True
except (IOError, PermissionError):
return False