#!/usr/bin/env python3 """ Simple API Key Manager - Consolidate keys without encryption Quick solution to organize scattered API keys """ import os import json from pathlib import Path from typing import Dict, List, Optional from datetime import datetime import argparse from collections import defaultdict class SimpleKeyManager: """Simple key management without encryption""" def __init__(self): self.workspace_root = Path(__file__).parent.parent.parent.parent self.keys_file = self.workspace_root / "config" / "consolidated_keys.json" self.keys_file.parent.mkdir(parents=True, exist_ok=True) def scan_all_projects(self) -> Dict[str, Dict[str, str]]: """Scan all projects for .env files""" projects = { "root": self.workspace_root, "trax": self.workspace_root / "apps" / "trax", "youtube-summarizer": self.workspace_root / "apps" / "youtube-summarizer", "pdf-translator": self.workspace_root / "pdf-translator", "directus-mcp": self.workspace_root / "tools" / "directus-mcp-server", } all_keys = defaultdict(dict) for project_name, project_path in projects.items(): env_file = project_path / ".env" if env_file.exists(): with open(env_file, 'r') as f: for line in f: line = line.strip() if line and not line.startswith('#'): if '=' in line: key, value = line.split('=', 1) key = key.strip() value = value.strip().strip('"').strip("'") all_keys[key][project_name] = value return dict(all_keys) def consolidate(self): """Consolidate all keys and save to JSON""" keys = self.scan_all_projects() # Organize by category categorized = { "ai": {}, "services": {}, "database": {}, "settings": {}, "custom": {} } ai_prefixes = ["ANTHROPIC", "DEEPSEEK", "OPENAI", "PERPLEXITY", "OPENROUTER", "GOOGLE_API", "XAI", "MISTRAL", "QWEN", "DASHSCOPE", "MODEL_STUDIO"] service_prefixes = ["SLACK", "GITHUB", "GITEA", "YOUTUBE", "DIRECTUS", "MICROSOFT"] db_prefixes = ["DATABASE", "REDIS", "POSTGRES"] for key_name, values in keys.items(): # Pick the most common value or the one from root if "root" in values: final_value = values["root"] else: # Use the most frequent value final_value = max(values.values(), key=lambda x: list(values.values()).count(x)) # Categorize if any(key_name.startswith(prefix) for prefix in ai_prefixes): categorized["ai"][key_name] = final_value elif any(key_name.startswith(prefix) for prefix in service_prefixes): categorized["services"][key_name] = final_value elif any(key_name.startswith(prefix) for prefix in db_prefixes): categorized["database"][key_name] = final_value elif any(keyword in key_name for keyword in ["JWT", "SECRET", "TOKEN", "KEY"]): categorized["settings"][key_name] = final_value else: categorized["custom"][key_name] = final_value # Save to JSON output = { "consolidated_at": datetime.now().isoformat(), "total_keys": sum(len(cat) for cat in categorized.values()), "keys": categorized } with open(self.keys_file, 'w') as f: json.dump(output, f, indent=2) return output def export_to_env(self, output_file: Path, filter_category: Optional[str] = None): """Export consolidated keys to .env format""" if not self.keys_file.exists(): print("❌ No consolidated keys found. Run consolidate first.") return with open(self.keys_file, 'r') as f: data = json.load(f) with open(output_file, 'w') as f: f.write(f"# Consolidated API Keys\n") f.write(f"# Generated: {datetime.now().isoformat()}\n\n") for category, keys in data["keys"].items(): if filter_category and category != filter_category: continue f.write(f"# {category.upper()} KEYS\n") for key_name, value in sorted(keys.items()): f.write(f"{key_name}={value}\n") f.write("\n") print(f"✅ Exported to {output_file}") def report(self): """Generate a summary report""" keys = self.scan_all_projects() print("\n" + "=" * 60) print("API KEY CONSOLIDATION REPORT") print("=" * 60) # Count keys by project project_counts = defaultdict(int) for key_name, values in keys.items(): for project in values.keys(): project_counts[project] += 1 print("\nKeys per project:") for project, count in sorted(project_counts.items()): print(f" • {project}: {count} keys") # Find conflicts conflicts = [] for key_name, values in keys.items(): unique_values = set(values.values()) if len(unique_values) > 1: conflicts.append(key_name) if conflicts: print(f"\n⚠️ {len(conflicts)} keys with conflicting values:") for key in conflicts[:10]: # Show first 10 print(f" • {key}") print(f"\nTotal unique keys: {len(keys)}") print("=" * 60) def main(): parser = argparse.ArgumentParser(description="Simple API Key Manager") subparsers = parser.add_subparsers(dest='command', help='Commands') # Consolidate command cons_parser = subparsers.add_parser('consolidate', help='Consolidate all keys') # Export command export_parser = subparsers.add_parser('export', help='Export to .env') export_parser.add_argument('file', help='Output file path') export_parser.add_argument('--category', help='Filter by category') # Report command report_parser = subparsers.add_parser('report', help='Show summary report') args = parser.parse_args() manager = SimpleKeyManager() if args.command == 'consolidate': result = manager.consolidate() print(f"✅ Consolidated {result['total_keys']} keys to {manager.keys_file}") print("\nKeys by category:") for cat, keys in result["keys"].items(): print(f" • {cat}: {len(keys)} keys") elif args.command == 'export': manager.export_to_env(Path(args.file), args.category) elif args.command == 'report': manager.report() else: # Default: consolidate and report manager.report() print("\nConsolidating keys...") result = manager.consolidate() print(f"\n✅ Saved to: {manager.keys_file}") print("\nNext steps:") print(f"1. Review: cat {manager.keys_file}") print(f"2. Export: python3 {__file__} export .env") print(f"3. Copy to projects as needed") if __name__ == "__main__": main()