From 23771f5a9659ee017a1b324f6929c9c55d40a8d2 Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Mon, 7 Apr 2025 19:16:31 -0500 Subject: [PATCH] git ignore secrets set up git ignore secrets to not leak API keys --- .gitignore | 20 ++++++++++++++++++++ config/config.json | 1 - config/config_secrets.template.json | 5 +++++ src/config_manager.py | 29 ++++++++++++++++++++++++----- 4 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 .gitignore create mode 100644 config/config_secrets.template.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..7c0a0efb --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class + +# Secrets +config/config_secrets.json + +# Environment +.env +.venv +env/ +venv/ +ENV/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo \ No newline at end of file diff --git a/config/config.json b/config/config.json index 7d434ab8..1f49432e 100644 --- a/config/config.json +++ b/config/config.json @@ -17,7 +17,6 @@ "update_interval": 1 }, "weather": { - "api_key": "YOUR_OPENWEATHERMAP_API_KEY", "update_interval": 300, "units": "imperial", "display_format": "{temp}°F\n{condition}" diff --git a/config/config_secrets.template.json b/config/config_secrets.template.json new file mode 100644 index 00000000..6153736f --- /dev/null +++ b/config/config_secrets.template.json @@ -0,0 +1,5 @@ +{ + "weather": { + "api_key": "YOUR_OPENWEATHERMAP_API_KEY" + } +} \ No newline at end of file diff --git a/src/config_manager.py b/src/config_manager.py index 2aca9d42..9fe0e817 100644 --- a/src/config_manager.py +++ b/src/config_manager.py @@ -3,23 +3,42 @@ import os from typing import Dict, Any class ConfigManager: - def __init__(self, config_path: str = "../config/config.json"): + def __init__(self, config_path: str = "../config/config.json", secrets_path: str = "../config/config_secrets.json"): self.config_path = config_path + self.secrets_path = secrets_path self.config: Dict[str, Any] = {} self.load_config() def load_config(self) -> None: - """Load configuration from JSON file.""" + """Load configuration from JSON files.""" try: + # Load main config with open(self.config_path, 'r') as f: self.config = json.load(f) - except FileNotFoundError: - print(f"Configuration file not found at {self.config_path}") - raise + + # Load and merge secrets if they exist + if os.path.exists(self.secrets_path): + with open(self.secrets_path, 'r') as f: + secrets = json.load(f) + # Deep merge secrets into config + self._deep_merge(self.config, secrets) + + except FileNotFoundError as e: + if str(e).find('config_secrets.json') == -1: # Only raise if main config is missing + print(f"Configuration file not found at {self.config_path}") + raise except json.JSONDecodeError: print("Error parsing configuration file") raise + def _deep_merge(self, target: Dict, source: Dict) -> None: + """Deep merge source dict into target dict.""" + for key, value in source.items(): + if key in target and isinstance(target[key], dict) and isinstance(value, dict): + self._deep_merge(target[key], value) + else: + target[key] = value + def get_timezone(self) -> str: """Get the configured timezone.""" return self.config.get('timezone', 'UTC')