|
import json |
|
from argparse import ArgumentError, ArgumentParser |
|
from base64 import b64encode |
|
from os import environ |
|
from typing import TypedDict |
|
|
|
import requests |
|
from nacl import public, encoding |
|
|
|
|
|
def encrypt(public_key_for_repo: str, secret_value_input: str) -> str: |
|
"""Encrypt a Unicode string using the public key.""" |
|
sealed_box = public.SealedBox(public.PublicKey(public_key_for_repo.encode("utf-8"), encoding.Base64Encoder())) |
|
encrypted = sealed_box.encrypt(secret_value_input.encode("utf-8")) |
|
return b64encode(encrypted).decode("utf-8") |
|
|
|
|
|
def get_public_key(gh_base_url: str, gh_owner: str, gh_repo: str, gh_auth_token: str) -> (str, str): |
|
public_key_endpoint: str = f"{gh_base_url}/{gh_owner}/{gh_repo}/actions/secrets/public-key" |
|
headers: TypedDict[str, str] = {"Authorization": f"Bearer {gh_auth_token}"} |
|
response = requests.get(url=public_key_endpoint, headers=headers) |
|
if response.status_code != 200: |
|
raise IOError(f"Could not get public key for repository {gh_owner}/{gh_repo}. The Response code was {response.status_code}") |
|
|
|
public_key_json = response.json() |
|
return public_key_json['key_id'], public_key_json['key'] |
|
|
|
|
|
def show_all_secrets(gh_base_url: str, gh_owner: str, gh_repo: str, gh_auth_token: str): |
|
get_secrets_url = f"{gh_base_url}/{gh_owner}/{gh_repo}/actions/secrets" |
|
headers: TypedDict[str, str] = {"Authorization": f"Bearer {gh_auth_token}"} |
|
get_all_secrets_response = requests.get(url=get_secrets_url, headers=headers) |
|
if get_all_secrets_response.status_code != 200: |
|
raise IOError(f"Could not get all existing secrets for repository {gh_owner}/{gh_repo}. The Response code was {get_all_secrets_response.status_code}") |
|
|
|
print(json.dumps(get_all_secrets_response.json(), indent=4, sort_keys=True)) |
|
|
|
|
|
def set_secret(gh_base_url: str, gh_owner: str, gh_repo: str, gh_auth_token: str, public_key_id: str, secret_key: str, encrypted_secret_value: str): |
|
secret_creation_url = f"{gh_base_url}/{gh_owner}/{gh_repo}/actions/secrets/{secret_key}" |
|
secret_creation_body = {"key_id": public_key_id, "encrypted_value": encrypted_secret_value} |
|
headers: TypedDict[str, str] = {"Authorization": f"Bearer {gh_auth_token}", "Content-Type": "application/json"} |
|
|
|
secret_creation_response = requests.put(url=secret_creation_url, json=secret_creation_body, headers=headers) |
|
if secret_creation_response.status_code == 201 or secret_creation_response.status_code == 204: |
|
print("--Secret Created / Updated!--") |
|
else: |
|
print(f"-- Error creating / updating github secret, the reason was : {secret_creation_response.reason}") |
|
|
|
|
|
# Press the green button in the gutter to run the script. |
|
if __name__ == '__main__': |
|
parser = ArgumentParser(description="A Python 3 script to create Github Secrets. Expects GITHUB_AUTHORIZATION_TOKEN env variable with value authorization token with repo permissions.") |
|
# parser.add_argument("-v", "--verbosity", dest="verbose", help="increase output verbosity", action="store_true") # TODO: Add this for logging later |
|
parser.add_argument("-o", "--owner", dest="owner", help="The Owner of the repository.", required=True) |
|
parser.add_argument("-r", "--repo", dest="repo", help="The name of the repository for which we would like to create the secret", required=True) |
|
parser.add_argument("--github-api-base-url", dest="github_api_url", help="Base endpoint for github api", default="https://api.github.com/repos") |
|
parser.add_argument("-l", "--only_list", dest="only_list", help="Only List Secrets, do not update anything", action="store_true") |
|
args = parser.parse_args() |
|
|
|
github_authorization_token = environ.get('GITHUB_AUTHORIZATION_TOKEN') |
|
if github_authorization_token is None or len(github_authorization_token) == 0: |
|
raise ArgumentError(argument=None, message="Missing Environment variable GITHUB_AUTHORIZATION_TOKEN") |
|
|
|
if not args.only_list: |
|
secret_key_environment_variable_name = 'SECRET_KEY_NAME' |
|
secret_key_input = str(environ.get(secret_key_environment_variable_name)).upper() |
|
if secret_key_input is None or len(secret_key_input) == 0: |
|
raise ArgumentError(argument=None, message=f"Missing environment variable with key {secret_key_environment_variable_name}. It will be the Key to create the secret.") |
|
|
|
secret_value = environ.get('SECRET_VALUE') |
|
if secret_value is None or len(secret_value) == 0: |
|
raise ArgumentError(argument=None, message=f"Missing environment variable with key SECRET_VALUE. It will be the Key to create the secret.") |
|
|
|
key_id, public_key = get_public_key(args.github_api_url, args.owner, args.repo, github_authorization_token) |
|
encrypted_secret: str = encrypt(public_key_for_repo=public_key, secret_value_input=secret_value) |
|
set_secret(gh_base_url=args.github_api_url, gh_owner=args.owner, gh_repo=args.repo, gh_auth_token=github_authorization_token, public_key_id=key_id, secret_key=secret_key_input, encrypted_secret_value=encrypted_secret) |
|
show_all_secrets(gh_base_url=args.github_api_url, gh_owner=args.owner, gh_repo=args.repo, gh_auth_token=github_authorization_token) |