diff --git a/project_setup/scripts/terraform-to-secrets b/project_setup/scripts/terraform-to-secrets index 522b43c..fbebf96 100755 --- a/project_setup/scripts/terraform-to-secrets +++ b/project_setup/scripts/terraform-to-secrets @@ -39,6 +39,7 @@ Usage: Options: -d --dry-run Don't create secrets. Just log what would be created. + -e --env=ENVNAME Create secrets in the specified GitHub environment. -h --help Show this message. -l --log-level=LEVEL If specified, then the log level will be set to the specified value. Valid values are "debug", "info", @@ -221,12 +222,20 @@ def encrypt(public_key: str, secret_value: str) -> str: return b64encode(encrypted).decode("utf-8") -def get_public_key(session: requests.Session, repo_name) -> Dict[str, str]: - """Fetch the public key for a repository.""" - logging.info(f"Requesting public key for repository {repo_name}") - response = session.get( - f"https://api.github.com/repos/{repo_name}/actions/secrets/public-key" - ) +def get_public_key(session: requests.Session, repo_name, github_env) -> Dict[str, str]: + """Fetch the public key for a repository or environment.""" + if github_env: + logging.info( + f"Requesting public key for environment {github_env} in {repo_name}" + ) + response = session.get( + f"https://api.github.com/repos/{repo_name}/environments/{github_env}/secrets/public-key" + ) + else: + logging.info(f"Requesting public key for repository {repo_name}") + response = session.get( + f"https://api.github.com/repos/{repo_name}/actions/secrets/public-key" + ) response.raise_for_status() return response.json() @@ -234,15 +243,23 @@ def get_public_key(session: requests.Session, repo_name) -> Dict[str, str]: def set_secret( session: requests.Session, repo_name: str, + github_env: str, secret_name: str, secret_value: str, public_key: Dict[str, str], ) -> None: """Create a secret in a repository.""" - logging.info(f"Creating secret {secret_name}") + if github_env: + logging.info(f"Creating secret {secret_name} in environment {github_env}") + api_url = f"https://api.github.com/repos/{repo_name}/environments/{github_env}/secrets/{secret_name}" + else: + logging.info(f"Creating repository secret {secret_name}") + api_url = ( + f"https://api.github.com/repos/{repo_name}/actions/secrets/{secret_name}" + ) encrypted_secret_value = encrypt(public_key["key"], secret_value) response = session.put( - f"https://api.github.com/repos/{repo_name}/actions/secrets/{secret_name}", + api_url, json={ "encrypted_value": encrypted_secret_value, "key_id": public_key["key_id"], @@ -321,21 +338,37 @@ def create_user_secrets(user_creds: Dict[str, Tuple[str, str]]) -> Dict[str, str def create_all_secrets( - secrets: Dict[str, str], github_token: str, repo_name: str, dry_run: bool = False + secrets: Dict[str, str], + github_env: str, + github_token: str, + repo_name: str, + dry_run: bool = False, ) -> None: """Log into GitHub and create all encrypted secrets.""" logging.info("Creating GitHub API session using personal access token.") session: requests.Session = requests.Session() session.auth = ("", github_token) - # Get the repo's public key to be used to encrypt secrets - public_key: Dict[str, str] = get_public_key(session, repo_name) + # If an environment is specified, verify that it exists + if github_env: + logging.info(f"Checking if environment {github_env} exists") + response = session.get( + f"https://api.github.com/repos/{repo_name}/environments/{github_env}" + ) + if response.status_code != 200: + logging.critical(f"Environment {github_env} not found in {repo_name}.") + raise Exception(f"Environment {github_env} not found in {repo_name}.") + + # Get the repo or environment public key to be used to encrypt secrets + public_key: Dict[str, str] = get_public_key(session, repo_name, github_env) for secret_name, secret_value in secrets.items(): if dry_run: logging.info(f"Would create secret {secret_name}") else: - set_secret(session, repo_name, secret_name, secret_value, public_key) + set_secret( + session, repo_name, github_env, secret_name, secret_value, public_key + ) def main() -> int: @@ -389,6 +422,7 @@ def main() -> int: # Assign validated arguments to variables dry_run: bool = validated_args["--dry-run"] + github_env: str = validated_args["--env"] github_token_to_save: str = validated_args[""] log_level: str = validated_args["--log-level"] repo_name: str = validated_args["--repo"] @@ -444,7 +478,7 @@ def main() -> int: all_secrets.update(user_secrets) # All the ducks are in a row, let's do this thang! - create_all_secrets(all_secrets, github_token, repo_name, dry_run) + create_all_secrets(all_secrets, github_env, github_token, repo_name, dry_run) logging.info("Success!")