diff --git a/.github/workflows/testflight-build.yml b/.github/workflows/testflight-build.yml index ac80e0b0..49741144 100644 --- a/.github/workflows/testflight-build.yml +++ b/.github/workflows/testflight-build.yml @@ -119,6 +119,7 @@ jobs: { echo "ASC_KEY_ID=$ASC_KEY_ID" echo "ASC_ISSUER_ID=$ASC_ISSUER_ID" + echo "ASC_KEY_PATH=$p8_path" } >> "$GITHUB_ENV" - name: Install release helper dependencies diff --git a/scripts/release/attach_build_to_group.py b/scripts/release/attach_build_to_group.py index fcbdb30d..b34f1bf9 100644 --- a/scripts/release/attach_build_to_group.py +++ b/scripts/release/attach_build_to_group.py @@ -9,6 +9,7 @@ import subprocess import sys import time +from pathlib import Path import jwt import requests @@ -26,7 +27,6 @@ class RetriesExhausted(AttachBuildError): """Raised after retry budget is exhausted.""" - def get_asc_secret() -> dict[str, str]: """Fetch ASC API credentials from AWS Secrets Manager.""" result = subprocess.run( @@ -50,6 +50,24 @@ def get_asc_secret() -> dict[str, str]: return json.loads(result.stdout) +def get_asc_credentials() -> tuple[str, str, str]: + """Read ASC credentials from environment first, otherwise from Secrets Manager.""" + key_id = os.getenv("ASC_KEY_ID") + issuer_id = os.getenv("ASC_ISSUER_ID") + private_key = os.getenv("ASC_PRIVATE_KEY") + + if key_id and issuer_id and private_key: + return key_id, issuer_id, private_key + + key_path = os.getenv("ASC_KEY_PATH") + if key_id and issuer_id and key_path: + return key_id, issuer_id, Path(os.path.expanduser(key_path)).read_text(encoding="utf-8") + + secret = get_asc_secret() + private_key = secret.get("private_key") or secret.get("key") + return secret["key_id"], secret["issuer_id"], private_key + + def get_asc_token(key_id: str, issuer_id: str, private_key: str) -> str: """Generate a signed JWT for ASC API authentication.""" now = int(time.time()) @@ -173,13 +191,8 @@ def main(argv: list[str] | None = None) -> int: args = parse_args(argv) bundle_id = args.bundle_id.strip() or None - secret = get_asc_secret() - private_key = secret["private_key"] if "private_key" in secret else secret["key"] - token = get_asc_token( - secret["key_id"], - secret["issuer_id"], - private_key, - ) + key_id, issuer_id, private_key = get_asc_credentials() + token = get_asc_token(key_id, issuer_id, private_key) try: group_id = find_group_id(args.group_name, token, bundle_id=bundle_id) diff --git a/scripts/release/resolve_build_id.py b/scripts/release/resolve_build_id.py index c839bd7a..fe5bf101 100755 --- a/scripts/release/resolve_build_id.py +++ b/scripts/release/resolve_build_id.py @@ -5,29 +5,47 @@ import subprocess import sys import time +from pathlib import Path import jwt import requests + def get_asc_secret(): env = os.environ.copy() env["AWS_PROFILE"] = os.environ.get("AWS_PROFILE", "riddim-agent") res = subprocess.run( [ - "aws", "secretsmanager", "get-secret-value", - "--secret-id", "appstore/connect-api", - "--region", "us-east-1", - "--query", "SecretString", + "aws", "secretsmanager", "get-secret-value", + "--secret-id", "appstore/connect-api", + "--region", "us-east-1", + "--query", "SecretString", "--output", "text" - ], - check=True, - capture_output=True, + ], + check=True, + capture_output=True, text=True, env=env ) secret = json.loads(res.stdout) return secret["key_id"], secret["issuer_id"], secret.get("key") or secret.get("private_key") + +def get_asc_credentials(): + key_id = os.getenv("ASC_KEY_ID") + issuer_id = os.getenv("ASC_ISSUER_ID") + private_key = os.getenv("ASC_PRIVATE_KEY") + + if key_id and issuer_id and private_key: + return key_id, issuer_id, private_key + + key_path = os.getenv("ASC_KEY_PATH") + if key_id and issuer_id and key_path: + return key_id, issuer_id, Path(os.path.expanduser(key_path)).read_text(encoding="utf-8") + + return get_asc_secret() + + def get_token(key_id, issuer_id, key): now = int(time.time()) payload = { @@ -38,6 +56,7 @@ def get_token(key_id, issuer_id, key): } return jwt.encode(payload, key, algorithm="ES256", headers={"kid": key_id}) + def main(): parser = argparse.ArgumentParser() parser.add_argument("--app-id", required=True) @@ -45,7 +64,7 @@ def main(): parser.add_argument("--build-number", required=True) args = parser.parse_args() - key_id, issuer_id, key = get_asc_secret() + key_id, issuer_id, key = get_asc_credentials() token = get_token(key_id, issuer_id, key) headers = {"Authorization": f"Bearer {token}"} diff --git a/scripts/release/wait_for_build_processed.py b/scripts/release/wait_for_build_processed.py index 7169a577..02c10e6f 100644 --- a/scripts/release/wait_for_build_processed.py +++ b/scripts/release/wait_for_build_processed.py @@ -12,6 +12,7 @@ import os import subprocess import sys +from pathlib import Path from typing import Any import jwt @@ -59,6 +60,23 @@ def get_asc_secret() -> dict[str, str]: } +def get_asc_credentials() -> tuple[str, str, str]: + """Read ASC credentials from environment first, otherwise from Secrets Manager.""" + key_id = os.getenv("ASC_KEY_ID") + issuer_id = os.getenv("ASC_ISSUER_ID") + private_key = os.getenv("ASC_PRIVATE_KEY") + + if key_id and issuer_id and private_key: + return key_id, issuer_id, private_key + + key_path = os.getenv("ASC_KEY_PATH") + if key_id and issuer_id and key_path: + return key_id, issuer_id, Path(os.path.expanduser(key_path)).read_text(encoding="utf-8") + + secret = get_asc_secret() + return secret["key_id"], secret["issuer_id"], secret["private_key"] + + def get_asc_token(key_id: str, issuer_id: str, private_key: str) -> str: """Create an App Store Connect API JWT.""" now = int(__import__("time").time()) @@ -198,8 +216,8 @@ def main() -> None: sys.exit(1) try: - secret = get_asc_secret() - token = get_asc_token(secret["key_id"], secret["issuer_id"], secret["private_key"]) + key_id, issuer_id, private_key = get_asc_credentials() + token = get_asc_token(key_id, issuer_id, private_key) status, payload = wait_for_build_processed( args.build_id, token, diff --git a/scripts/runner/fetch_asc_secret.sh b/scripts/runner/fetch_asc_secret.sh index 8b019e74..b0cff7fc 100755 --- a/scripts/runner/fetch_asc_secret.sh +++ b/scripts/runner/fetch_asc_secret.sh @@ -45,6 +45,7 @@ chmod 600 /tmp/asc_api_key.json if [[ -n "${GITHUB_ENV:-}" ]]; then echo "ASC_KEY_ID=${KEY_ID}" >> "$GITHUB_ENV" echo "ASC_ISSUER_ID=${ISSUER_ID}" >> "$GITHUB_ENV" + echo "ASC_KEY_PATH=${P8_PATH}" >> "$GITHUB_ENV" fi echo "fetch_asc_secret: wrote ${P8_PATH} and /tmp/asc_api_key.json"