Skip to content

Instantly share code, notes, and snippets.

@pgmac
Last active May 3, 2026 19:55
Show Gist options
  • Select an option

  • Save pgmac/e6f1ddf1eb4519f5967423d52dcea30f to your computer and use it in GitHub Desktop.

Select an option

Save pgmac/e6f1ddf1eb4519f5967423d52dcea30f to your computer and use it in GitHub Desktop.
Adding the applications secrets to it's repository [install]
#!/usr/bin/env python3
"""Script to add secrets to a GitHub repository."""
import argparse
import subprocess
import sys
from pathlib import Path
def run_cmd(cmd: list[str], capture: bool = True) -> subprocess.CompletedProcess:
return subprocess.run(cmd, capture_output=capture, text=True)
def get_current_repo() -> str | None:
result = run_cmd(["gh", "repo", "view", "--json", "nameWithOwner", "-q", ".nameWithOwner"])
if result.returncode == 0:
return result.stdout.strip()
return None
def list_org_secrets(org: str) -> list[str]:
result = run_cmd(["gh", "secret", "list", "--org", org])
if result.returncode != 0:
print(f"Error listing org secrets: {result.stderr}", file=sys.stderr)
return []
lines = result.stdout.strip().split("\n")
return [line.split()[0] for line in lines if line.strip()]
def list_repo_secrets(repo: str) -> list[str]:
result = run_cmd(["gh", "secret", "list", "-R", repo])
if result.returncode != 0:
print(f"Error listing repo secrets: {result.stderr}", file=sys.stderr)
return []
lines = result.stdout.strip().split("\n")
return [line.split()[0] for line in lines if line.strip()]
def add_secret(repo: str, name: str, value: str) -> bool:
result = run_cmd(["gh", "secret", "set", name, "-b", value, "-R", repo])
if result.returncode != 0:
print(f"Error setting secret {name}: {result.stderr}", file=sys.stderr)
return False
print(f"Added secret: {name}")
return True
def parse_tfvars(path: Path) -> dict[str, str]:
secrets = {}
content = path.read_text()
for line in content.split("\n"):
line = line.strip()
if not line or line.startswith("#"):
continue
if "=" in line:
key, value = line.split("=", 1)
key = key.strip()
value = value.strip().strip('"').strip("'")
if key and value:
secrets[key] = value
return secrets
def parse_env(path: Path) -> dict[str, str]:
secrets = {}
content = path.read_text()
for line in content.split("\n"):
line = line.strip()
if not line or line.startswith("#"):
continue
if "=" in line:
key, value = line.split("=", 1)
key = key.strip()
value = value.strip().strip('"').strip("'")
if key and value:
secrets[key] = value
return secrets
def select_secrets(secrets: dict[str, str], prompt: str) -> list[tuple[str, str]]:
print(f"\n{prompt}")
for i, key in enumerate(secrets.keys(), 1):
print(f" {i}. {key}")
print(" 0. None")
print(" a. All")
choice = input("Select (comma-separated for multiple): ").strip()
if choice == "0":
return []
if choice.lower() == "a":
return list(secrets.items())
selected = []
for part in choice.split(","):
idx = int(part.strip()) - 1
if 0 <= idx < len(secrets):
key = list(secrets.keys())[idx]
selected.append((key, secrets[key]))
return selected
def main():
parser = argparse.ArgumentParser(description="Add secrets to a GitHub repository")
parser.add_argument("-R", "--repo", help="Repository (owner/repo), defaults to current repo")
parser.add_argument("--org", default="pgmac-net", help="Organization to copy secrets from")
parser.add_argument("--copy-org", action="store_true", help="Copy secrets from org (disabled by default)")
parser.add_argument("--skip-tfvars", action="store_true", help="Skip terraform.tfvars")
parser.add_argument("--skip-env", action="store_true", help="Skip .env files")
args = parser.parse_args()
repo = args.repo or get_current_repo()
if not repo:
print("Error: Not in a git repo or --repo not specified", file=sys.stderr)
sys.exit(1)
print(f"Target repository: {repo}")
existing_secrets = list_repo_secrets(repo)
if args.copy_org:
print(f"\nFetching org secrets from {args.org}...")
org_secrets = list_org_secrets(args.org)
if org_secrets:
print(f"Org secrets: {', '.join(org_secrets)}")
choice = input("Select secrets to copy (comma-separated), or Enter for all: ").strip()
if choice:
selected = []
for part in choice.split(","):
idx = int(part.strip()) - 1
if 0 <= idx < len(org_secrets):
selected.append(org_secrets[idx])
else:
selected = org_secrets
for name in selected:
if name in existing_secrets:
print(f"Skipping {name} (already exists)")
continue
result = run_cmd(["gh", "secret", "list", "--org", args.org, "-q", f".[] | .[] | select(.key == \"{name}\") | .value"])
value = result.stdout.strip()
if value:
add_secret(repo, name, value)
else:
print("No org secrets found")
if not args.skip_tfvars:
tfvars_path = Path("terraform.tfvars")
if tfvars_path.exists():
print(f"\nProcessing {tfvars_path}...")
secrets = parse_tfvars(tfvars_path)
for name, value in secrets.items():
secret_name = f"TF_VAR_{name}"
if secret_name in existing_secrets:
print(f"Skipping {secret_name} (already exists)")
continue
add_secret(repo, secret_name, value)
if not args.skip_env:
env_files = list(Path(".").glob(".env*")) + list(Path(".").glob("*.env"))
for env_path in env_files:
if env_path.is_file():
print(f"\nProcessing {env_path}...")
secrets = parse_env(env_path)
selected = select_secrets(secrets, f"Select secrets from {env_path}:")
for name, value in selected:
if name in existing_secrets:
print(f"Skipping {name} (already exists)")
continue
add_secret(repo, name, value)
print("\nDone!")
if __name__ == "__main__":
main()
@pgmac
Copy link
Copy Markdown
Author

pgmac commented May 3, 2026

This is a script I quickly vibed up to add the secrets used in .env and in 1erraform.tfvars as Actions secrets in the associated GitHub repo.
It's really just a wrapper around gh secret to help simplify/automate the process.

@pgmac
Copy link
Copy Markdown
Author

pgmac commented May 3, 2026

The [install] marker is something I'm trying with a script to identify and install gist scripts in my home directory.
Not sure how that'll go, or if I'll keep it.
Github doesn't expose which gist's I've starred via the API, so I'm using this as a workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment