Skip to content

Commit

Permalink
github setup script
Browse files Browse the repository at this point in the history
  • Loading branch information
Laurence Molloy committed Dec 22, 2024
1 parent 87618b9 commit 9694b3d
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 2 deletions.
5 changes: 4 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ REPO_URL = "https://github.com/ACCOUNT_NAME/SignsOfLife.git"
# * Expiration: no expiration (NOTE: security risk if leaked)
# * Description: (whatever you want)
# * Select "Only Select Repositories" and choose SignsOfLife
# * Repository Permissions: Contents (read & write)
# * Repository Permissions: Contents (read & write) - for client operation
# Secrets (read & write) - for github setup script
# Variables (read & write) - for github setup script

# Click on "Generate Token"
GITHUB_TOKEN = # cut and paste your Githiub PErsonal Access Token here

Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pynput
python-dotenv
requests
requests
pynacl
126 changes: 126 additions & 0 deletions setup_scripts/windows/setup_github.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import requests
from base64 import b64encode
from nacl import encoding, public
from dotenv import load_dotenv, dotenv_values
from typing import Dict


# NB: this script requires read & write repository permissions for Secrets
# and Variables to be set for the GitHub Token that is used

# Load .env file
load_dotenv()
env_vars = dotenv_values() # Get env vars as a dictionary

# Remove all GITHUB_* named secrets and variables (these don't get written to repo)
env_vars_filtered = {
key: val for key, val in env_vars.items() if not key.startswith("GITHUB_")
}

# Classify filtered environment vars as secrets or repository variables
sensitive_keywords = {"PASSWORD", "EMAIL", "KEY", "TOKEN", "SECRET"}
secrets = {k: v for k, v in env_vars_filtered.items() if any(word in k for word in sensitive_keywords)}
vars = {k: v for k, v in env_vars_filtered.items() if k not in secrets.keys()}

GITHUB_API_URL = f"https://api.github.com/repos/{vars['REPO_OWNER']}/{vars['REPO_NAME']}"
HEADERS = {
"Authorization": f"Bearer {env_vars['GITHUB_TOKEN']}",
"Accept": "application/vnd.github.v3+json",
"X-GitHub-Api-Version": "2022-11-28"
}


def clear_variables() -> None:
"""Clear all existing repository variables."""
url = f"{GITHUB_API_URL}/actions/variables"
response = requests.get(url, headers=HEADERS)
github_repo_vars = [var['name'] for var in response.json()['variables']]

for var in github_repo_vars:
url = f"{GITHUB_API_URL}/actions/variables/{var}"
response = requests.delete(url, headers=HEADERS)

if response.status_code in [201, 204]:
print(f"Variable '{var}' has been deleted.")
else:
print(f"Failed to delete variable '{var}': {response.json()}")


def clear_secrets() -> None:
"""Clear all existing repository secrets."""
secret_url = f"{GITHUB_API_URL}/actions/secrets"
response = requests.get(secret_url, headers=HEADERS)
github_secrets = [secret['name'] for secret in response.json()['secrets']]

for secret in github_secrets:
secret_url = f"{GITHUB_API_URL}/actions/secrets/{secret}"
response = requests.delete(secret_url, headers=HEADERS)

if response.status_code in [201, 204]:
print(f"Secret '{secret}' has been deleted.")
else:
print(f"Failed to delete secret '{secret}': {response.json()}")


def create_variable(name: str, value: str) -> None:
"""Create a repository variable."""
url = f"{GITHUB_API_URL}/actions/variables"
payload = {"name": name, "value": value}
response = requests.post(url, headers=HEADERS, json=payload)

if response.status_code in [201, 204]:
print(f"Variable '{name}' created.")
else:
print(f"Failed to create variable '{name}': {response.json()}")


def encrypt(public_key: str, secret_value: str) -> str:
"""Encrypt a Unicode string using the public key."""
public_key = public.PublicKey(public_key.encode("utf-8"), encoding.Base64Encoder())
sealed_box = public.SealedBox(public_key)
encrypted = sealed_box.encrypt(secret_value.encode("utf-8"))
return b64encode(encrypted).decode("utf-8")


def create_secret(name: str, value: str) -> None:
"""Create a repository secret."""
# Get public key for encrypting the secret
key_response = requests.get(f"{GITHUB_API_URL}/actions/secrets/public-key", headers=HEADERS)

if key_response.status_code != 200:
print(f"Failed to fetch public key: {key_response.json()}")
return

key = key_response.json()
public_key = key['key']
key_id = key['key_id']

# Create encrypted secret
secret_url = f"{GITHUB_API_URL}/actions/secrets/{name}"
payload = {
"encrypted_value": encrypt(public_key, value),
"key_id": key_id
}
response = requests.put(secret_url, headers=HEADERS, json=payload)

if response.status_code in [201, 204]:
print(f"Secret '{name}' created.")
else:
print(f"Failed to create secret '{name}': {response.json()}")


def main() -> None:
"""Main function to clear and recreate variables and secrets."""
# Clear down & re-create repository variables
clear_variables()
for key, value in vars.items():
create_variable(key, value)

# Clear down & re-create repository secrets
clear_secrets()
for key, value in secrets.items():
create_secret(key, value)


if __name__ == "__main__":
main()

0 comments on commit 9694b3d

Please sign in to comment.