# /root/backend/scripts/migrate_to_infisical.py # Migrate secrets from docker-compose env block → Infisical # Per v4.0 §T17 # # Usage: # python3 migrate_to_infisical.py --project rmi-backend --env prod # # Reads the running container's env vars and pushes them to Infisical. # After running, remove the env vars from docker-compose.yml and add # the INFISICAL_TOKEN env var instead. import argparse import os import sys import requests # Secrets to migrate — ONLY non-empty values are pushed SECRETS_TO_MIGRATE = [ "OPENROUTER_API_KEY", "DEEPSEEK_API_KEY", "HELIUS_API_KEY", "BIRDEYE_API_KEY", "MORALIS_API_KEY", "GROQ_API_KEY", "SUPABASE_URL", "SUPABASE_KEY", "SUPABASE_SERVICE_KEY", "BOT_TOKEN", "ADMIN_API_KEY", "GHOST_ADMIN_KEY", "ADMIN_IDS", "HUGGINGFACE_TOKEN", "GLITCHTIP_DSN", ] def main(): ap = argparse.ArgumentParser() ap.add_argument("--project", default="rmi-backend") ap.add_argument("--env", default="prod") ap.add_argument("--infisical-url", default="https://infisical.rugmunch.io/api/v3") ap.add_argument("--token", default=os.environ.get("INFISICAL_TOKEN")) ap.add_argument("--dry-run", action="store_true") args = ap.parse_args() if not args.token and not args.dry_run: print("INFISICAL_TOKEN env required (or use --dry-run)") sys.exit(1) # Read current secrets from docker inspect print("Reading secrets from running rmi-backend container...") import subprocess result = subprocess.run( ["docker", "inspect", "rmi-backend", "--format", "{{range .Config.Env}}{{println .}}{{end}}"], capture_output=True, text=True, ) env = {} for line in result.stdout.strip().split("\n"): if "=" in line: k, v = line.split("=", 1) env[k] = v to_migrate = {} for key in SECRETS_TO_MIGRATE: val = env.get(key, "") if val and val not in ("", " ", "\"\""): to_migrate[key] = val masked = val[:2] + "***" + val[-2:] if len(val) > 6 else "***" print(f" {key} = {masked}") print(f"\n{len(to_migrate)} secrets to migrate") if args.dry_run: print("\n[DRY RUN] No secrets pushed. Remove --dry-run to execute.") return # Push to Infisical headers = {"Authorization": f"Bearer {args.token}"} for key, value in to_migrate.items(): resp = requests.post( f"{args.infisical_url}/secrets/{key}", headers=headers, json={ "projectId": args.project, "environment": args.env, "secretValue": value, "type": "shared", }, ) if resp.status_code in (200, 201): print(f" ✓ {key}") else: print(f" ✗ {key}: {resp.status_code} {resp.text[:80]}") print(f"\nMigrated {len(to_migrate)} secrets to Infisical ({args.project}/{args.env})") print("\nNext steps:") print(" 1. Verify in Infisical UI at https://infisical.rugmunch.io") print(" 2. Remove secret env vars from /srv/rugmuncher-backend/docker-compose.yml") print(" 3. Add INFISICAL_TOKEN env var to backend service") print(" 4. Change CMD to: infisical run --token=$INFISICAL_TOKEN --projectId=rmi-backend --env=prod -- python -u main.py") if __name__ == "__main__": main()