|
39 | 39 |
|
40 | 40 | Options: |
41 | 41 | -d --dry-run Don't create secrets. Just log what would be created. |
| 42 | + -e --env=ENVNAME Create secrets in the specified GitHub environment. |
42 | 43 | -h --help Show this message. |
43 | 44 | -l --log-level=LEVEL If specified, then the log level will be set to |
44 | 45 | the specified value. Valid values are "debug", "info", |
@@ -221,28 +222,44 @@ def encrypt(public_key: str, secret_value: str) -> str: |
221 | 222 | return b64encode(encrypted).decode("utf-8") |
222 | 223 |
|
223 | 224 |
|
224 | | -def get_public_key(session: requests.Session, repo_name) -> Dict[str, str]: |
225 | | - """Fetch the public key for a repository.""" |
226 | | - logging.info(f"Requesting public key for repository {repo_name}") |
227 | | - response = session.get( |
228 | | - f"https://api.github.com/repos/{repo_name}/actions/secrets/public-key" |
229 | | - ) |
| 225 | +def get_public_key(session: requests.Session, repo_name, github_env) -> Dict[str, str]: |
| 226 | + """Fetch the public key for a repository or environment.""" |
| 227 | + if github_env: |
| 228 | + logging.info( |
| 229 | + f"Requesting public key for environment {github_env} in {repo_name}" |
| 230 | + ) |
| 231 | + response = session.get( |
| 232 | + f"https://api.github.com/repos/{repo_name}/environments/{github_env}/secrets/public-key" |
| 233 | + ) |
| 234 | + else: |
| 235 | + logging.info(f"Requesting public key for repository {repo_name}") |
| 236 | + response = session.get( |
| 237 | + f"https://api.github.com/repos/{repo_name}/actions/secrets/public-key" |
| 238 | + ) |
230 | 239 | response.raise_for_status() |
231 | 240 | return response.json() |
232 | 241 |
|
233 | 242 |
|
234 | 243 | def set_secret( |
235 | 244 | session: requests.Session, |
236 | 245 | repo_name: str, |
| 246 | + github_env: str, |
237 | 247 | secret_name: str, |
238 | 248 | secret_value: str, |
239 | 249 | public_key: Dict[str, str], |
240 | 250 | ) -> None: |
241 | | - """Create a secret in a repository.""" |
242 | | - logging.info(f"Creating secret {secret_name}") |
| 251 | + """Create a secret in a repository or environment.""" |
| 252 | + if github_env: |
| 253 | + logging.info(f"Creating secret {secret_name} in environment {github_env}") |
| 254 | + api_url = f"https://api.github.com/repos/{repo_name}/environments/{github_env}/secrets/{secret_name}" |
| 255 | + else: |
| 256 | + logging.info(f"Creating repository secret {secret_name}") |
| 257 | + api_url = ( |
| 258 | + f"https://api.github.com/repos/{repo_name}/actions/secrets/{secret_name}" |
| 259 | + ) |
243 | 260 | encrypted_secret_value = encrypt(public_key["key"], secret_value) |
244 | 261 | response = session.put( |
245 | | - f"https://api.github.com/repos/{repo_name}/actions/secrets/{secret_name}", |
| 262 | + api_url, |
246 | 263 | json={ |
247 | 264 | "encrypted_value": encrypted_secret_value, |
248 | 265 | "key_id": public_key["key_id"], |
@@ -321,21 +338,37 @@ def create_user_secrets(user_creds: Dict[str, Tuple[str, str]]) -> Dict[str, str |
321 | 338 |
|
322 | 339 |
|
323 | 340 | def create_all_secrets( |
324 | | - secrets: Dict[str, str], github_token: str, repo_name: str, dry_run: bool = False |
| 341 | + secrets: Dict[str, str], |
| 342 | + github_env: str, |
| 343 | + github_token: str, |
| 344 | + repo_name: str, |
| 345 | + dry_run: bool = False, |
325 | 346 | ) -> None: |
326 | 347 | """Log into GitHub and create all encrypted secrets.""" |
327 | 348 | logging.info("Creating GitHub API session using personal access token.") |
328 | 349 | session: requests.Session = requests.Session() |
329 | 350 | session.auth = ("", github_token) |
330 | 351 |
|
331 | | - # Get the repo's public key to be used to encrypt secrets |
332 | | - public_key: Dict[str, str] = get_public_key(session, repo_name) |
| 352 | + # If an environment is specified, verify that it exists |
| 353 | + if github_env: |
| 354 | + logging.info(f"Checking if environment {github_env} exists") |
| 355 | + response = session.get( |
| 356 | + f"https://api.github.com/repos/{repo_name}/environments/{github_env}" |
| 357 | + ) |
| 358 | + if response.status_code != 200: |
| 359 | + logging.critical(f"Environment {github_env} not found in {repo_name}.") |
| 360 | + raise Exception(f"Environment {github_env} not found in {repo_name}.") |
| 361 | + |
| 362 | + # Get the repo or environment public key to be used to encrypt secrets |
| 363 | + public_key: Dict[str, str] = get_public_key(session, repo_name, github_env) |
333 | 364 |
|
334 | 365 | for secret_name, secret_value in secrets.items(): |
335 | 366 | if dry_run: |
336 | 367 | logging.info(f"Would create secret {secret_name}") |
337 | 368 | else: |
338 | | - set_secret(session, repo_name, secret_name, secret_value, public_key) |
| 369 | + set_secret( |
| 370 | + session, repo_name, github_env, secret_name, secret_value, public_key |
| 371 | + ) |
339 | 372 |
|
340 | 373 |
|
341 | 374 | def main() -> int: |
@@ -389,6 +422,7 @@ def main() -> int: |
389 | 422 |
|
390 | 423 | # Assign validated arguments to variables |
391 | 424 | dry_run: bool = validated_args["--dry-run"] |
| 425 | + github_env: str = validated_args["--env"] |
392 | 426 | github_token_to_save: str = validated_args["<github-personal-access-token>"] |
393 | 427 | log_level: str = validated_args["--log-level"] |
394 | 428 | repo_name: str = validated_args["--repo"] |
@@ -444,7 +478,7 @@ def main() -> int: |
444 | 478 | all_secrets.update(user_secrets) |
445 | 479 |
|
446 | 480 | # All the ducks are in a row, let's do this thang! |
447 | | - create_all_secrets(all_secrets, github_token, repo_name, dry_run) |
| 481 | + create_all_secrets(all_secrets, github_env, github_token, repo_name, dry_run) |
448 | 482 |
|
449 | 483 | logging.info("Success!") |
450 | 484 |
|
|
0 commit comments