rugmuncher-backend / backend /scripts /migrate_to_infisical.py
Crypto Rug Muncher
feat(t17+t21+t45): Infisical + integration tests + backup verification
4295a74
Raw
History Blame Contribute Delete
3.41 kB
# /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()