From c14a28b093ee75f0aa23da203bef0df8e3380335 Mon Sep 17 00:00:00 2001 From: Daniel Bedeleanu Date: Thu, 23 Apr 2026 14:45:07 +0300 Subject: [PATCH 1/2] fix(08): fix AI key status detection and enable saving to secrets.yaml --- .standalone.pid | 6 +- backend/config_manager.py | 72 ++++++++++++++++++ backend/routers/admin/ai_config.py | 15 +++- backups/ainventory_2026-04-23_14-04-08.tar.gz | Bin 0 -> 28954 bytes 4 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 backups/ainventory_2026-04-23_14-04-08.tar.gz diff --git a/.standalone.pid b/.standalone.pid index b304e3f4..1b6c76f2 100644 --- a/.standalone.pid +++ b/.standalone.pid @@ -1,3 +1,3 @@ -826698 -826699 -826713 +830554 +830555 +830569 diff --git a/backend/config_manager.py b/backend/config_manager.py index 3bf27119..b9a7194d 100644 --- a/backend/config_manager.py +++ b/backend/config_manager.py @@ -72,6 +72,74 @@ class ConfigManager: except Exception: return False + @staticmethod + def get_secrets_path(): + """Returns the absolute path to secrets.yaml.""" + base_dir = os.path.dirname(os.path.abspath(__file__)) + project_root = os.path.dirname(base_dir) + return os.path.join(project_root, "config", "secrets.yaml") + + @staticmethod + def update_secrets(updates: dict) -> dict: + """Update secrets.yaml with new values (flattened structure).""" + path = ConfigManager.get_secrets_path() + + current_secrets = {} + if os.path.exists(path): + try: + with open(path, 'r', encoding='utf-8') as f: + current_secrets = yaml.safe_load(f) or {} + except Exception as e: + log.error(f"❌ Failed to read {path}: {e}") + + # Update flattened secrets + current_secrets.update(updates) + + try: + with open(path, 'w', encoding='utf-8') as f: + # Header for clarity + f.write("# TFM aInventory - Managed Secrets (Updated via Admin UI)\n") + yaml.dump(current_secrets, f, default_flow_style=False, sort_keys=True) + log.info(f"✅ Updated {path} with new secrets.") + + # Reload the global config + load_config() + return get_config() + except Exception as e: + log.error(f"❌ Failed to write {path}: {e}") + raise + + @staticmethod + def update_keys(updates: dict) -> dict: + """ + Intelligent key update: routes sensitive AI keys to secrets.yaml + and others to backend.yaml. + """ + secrets_updates = {} + backend_updates = {} + + sensitive_keys = ["GEMINI_API_KEY", "CLAUDE_API_KEY", "JWT_SECRET_KEY", "LDAP_PASSWORD"] + + for key, val in updates.items(): + if key in sensitive_keys: + secrets_updates[key] = val + else: + # Non-sensitive or complex nested settings + backend_updates[key] = val + + if secrets_updates: + ConfigManager.update_secrets(secrets_updates) + + if backend_updates: + ConfigManager.update_config(backend_updates) + + return get_config() + + @staticmethod + def get_config() -> dict: + """Return the current global configuration.""" + return get_config() + @staticmethod def get_masked_key(key_name: str): """Returns a masked version of a configuration value or env var.""" @@ -113,6 +181,10 @@ def update_config(updates: dict) -> dict: """Update backend.yaml with new values and return updated config.""" return ConfigManager.update_config(updates) +def get_config() -> dict: + """Return the current global configuration.""" + return ConfigManager.get_config() + def validate_config_file() -> bool: """Validate backend.yaml syntax and required fields.""" return ConfigManager.validate_config_file() diff --git a/backend/routers/admin/ai_config.py b/backend/routers/admin/ai_config.py index a32242bc..59978e30 100644 --- a/backend/routers/admin/ai_config.py +++ b/backend/routers/admin/ai_config.py @@ -67,8 +67,11 @@ def get_ai_config( current_admin: auth.TokenData = Depends(auth.get_current_admin) ): """Check AI provider status and active provider.""" - gemini_key = os.environ.get("GEMINI_API_KEY") - claude_key = os.environ.get("CLAUDE_API_KEY") + config = ConfigManager.get_config() # Alias for config_loader.get_config + ai_config = config.get("ai", {}) + + gemini_key = ai_config.get("gemini_api_key") + claude_key = ai_config.get("claude_api_key") provider_setting = db.query(models.SystemSetting).filter(models.SystemSetting.key == "ai_provider").first() active_provider = provider_setting.value if provider_setting else "gemini" @@ -112,10 +115,14 @@ def update_ai_keys( if updates: ConfigManager.update_keys(updates) + # Re-load config to return accurate status + config = ConfigManager.get_config() + ai_cfg = config.get("ai", {}) + return { "status": "success", - "gemini_configured": bool(os.environ.get("GEMINI_API_KEY")), - "claude_configured": bool(os.environ.get("CLAUDE_API_KEY")) + "gemini_configured": bool(ai_cfg.get("gemini_api_key")), + "claude_configured": bool(ai_cfg.get("claude_api_key")) } diff --git a/backups/ainventory_2026-04-23_14-04-08.tar.gz b/backups/ainventory_2026-04-23_14-04-08.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..9b830debcdc21d5b115f0dd679e4754f941cc739 GIT binary patch literal 28954 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 O#R6=!T3(&Mef2+O5D^;y literal 0 HcmV?d00001 From 9afe33538493506a2cad013cf92756169a861670 Mon Sep 17 00:00:00 2001 From: Daniel Bedeleanu Date: Thu, 23 Apr 2026 14:45:07 +0300 Subject: [PATCH 2/2] Build [v1.14.12] --- frontend/VERSION.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/VERSION.json b/frontend/VERSION.json index 6b8417df..25ea6ab1 100644 --- a/frontend/VERSION.json +++ b/frontend/VERSION.json @@ -1,6 +1,6 @@ { - "version": "1.14.11", - "last_build": "2026-04-23-1404", + "version": "1.14.12", + "last_build": "2026-04-23-1445", "codename": "ConfigCore", - "commit": "e5a24df1" + "commit": "c14a28b0" } \ No newline at end of file