name: Decrypt Release Secrets
description: Decrypts age-sealed Burrow release secrets and exports CI paths/env.
inputs:
  root:
    description: Repository root
    required: false
    default: .
runs:
  using: composite
  steps:
    - shell: bash
      run: |
        set -euo pipefail

        ROOT_INPUT='${{ inputs.root }}'
        ROOT="$(cd "$ROOT_INPUT" && pwd)"

        resolve_nix_bin() {
          local candidate
          for candidate in \
            "${NIX_BIN:-}" \
            "$(command -v nix 2>/dev/null || true)" \
            /nix/var/nix/profiles/default/bin/nix \
            "${HOME:-}/.nix-profile/bin/nix" \
            "${HOME:-}/.local/state/nix/profile/bin/nix" \
            /Users/runner/.nix-profile/bin/nix \
            /Users/runner/.local/state/nix/profile/bin/nix \
            /home/runner/.nix-profile/bin/nix \
            /home/runner/.local/state/nix/profile/bin/nix \
            ; do
            if [[ -n "$candidate" && -x "$candidate" ]]; then
              printf '%s\n' "$candidate"
              return 0
            fi
          done
          return 1
        }

        resolve_decrypt_tool() {
          local candidate
          for candidate in \
            "${AGE_BIN:-}" \
            "$(command -v age 2>/dev/null || true)" \
            /opt/homebrew/bin/age \
            /usr/local/bin/age \
            /usr/bin/age \
            /run/current-system/sw/bin/age \
            /etc/profiles/per-user/runner/bin/age \
            "${HOME:-}/.nix-profile/bin/age" \
            "${HOME:-}/.local/state/nix/profile/bin/age" \
            /Users/runner/.nix-profile/bin/age \
            /Users/runner/.local/state/nix/profile/bin/age \
            /home/runner/.nix-profile/bin/age \
            /home/runner/.local/state/nix/profile/bin/age \
            ; do
            if [[ -n "$candidate" && -x "$candidate" ]]; then
              printf 'age:%s\n' "$candidate"
              return 0
            fi
          done
          for candidate in \
            "${AGENIX_BIN:-}" \
            "$(command -v agenix 2>/dev/null || true)" \
            ; do
            if [[ -n "$candidate" && -x "$candidate" ]]; then
              printf 'agenix:%s\n' "$candidate"
              return 0
            fi
          done
          local nix_bin
          nix_bin="$(resolve_nix_bin || true)"
          if [[ -n "$nix_bin" ]]; then
            local built
            built="$("$nix_bin" --extra-experimental-features 'nix-command flakes' build --no-link "$ROOT#age" --print-out-paths 2>/dev/null | tail -n 1 || true)"
            if [[ -n "$built" && -x "$built/bin/age" ]]; then
              printf 'age:%s\n' "$built/bin/age"
              return 0
            fi
            built="$("$nix_bin" --extra-experimental-features 'nix-command flakes' build --no-link "$ROOT#agenix" --print-out-paths 2>/dev/null | tail -n 1 || true)"
            if [[ -n "$built" && -x "$built/bin/agenix" ]]; then
              printf 'agenix:%s\n' "$built/bin/agenix"
              return 0
            fi
          fi
          echo "::error ::age or agenix is required to decrypt release secrets but neither is available." >&2
          exit 1
        }

        decrypt_tool="$(resolve_decrypt_tool)"
        decrypt_kind="${decrypt_tool%%:*}"
        decrypt_bin="${decrypt_tool#*:}"
        KEY="${AGE_IDENTITY_PATH:-}"
        if [[ -z "$KEY" || ! -s "$KEY" ]]; then
          echo "::error ::Missing age identity. Run Scripts/resolve-age-identity.sh before this action." >&2
          exit 1
        fi

        decrypt_age_file() {
          local file_path="$1"
          if [[ "$decrypt_kind" == "agenix" ]]; then
            local agenix_path="$file_path"
            if [[ "$file_path" == "$ROOT/"* ]]; then
              agenix_path="${file_path#"$ROOT"/}"
            fi
            (cd "$ROOT" && "$decrypt_bin" --identity "$KEY" --decrypt "$agenix_path")
          else
            "$decrypt_bin" --decrypt -i "$KEY" "$file_path"
          fi
        }

        write_env() {
          local name="$1"
          local value="$2"
          echo "${name}=${value}" >> "$GITHUB_ENV"
        }

        mask_multiline() {
          local value="$1"
          echo "::add-mask::${value}"
          while IFS= read -r line; do
            [[ -n "$line" ]] || continue
            echo "::add-mask::${line}"
          done <<<"$value"
        }

        decrypt_env_optional() {
          local name="$1"
          local file="$2"
          if [[ ! -f "$file" ]]; then
            echo "::notice ::Skipping optional release secret ${file}"
            return 0
          fi
          local value
          value="$(decrypt_age_file "$file")"
          mask_multiline "$value"
          {
            echo "${name}<<EOF"
            printf '%s\n' "$value"
            echo "EOF"
          } >> "$GITHUB_ENV"
        }

        decrypt_file_optional() {
          local name="$1"
          local file="$2"
          local suffix="$3"
          if [[ ! -f "$file" ]]; then
            echo "::notice ::Skipping optional release secret ${file}"
            return 0
          fi
          local temp_dir="${RUNNER_TEMP:-/tmp}"
          local temp_file
          temp_file="$(mktemp "${temp_dir}/${name}.XXXXXX")"
          if [[ -n "$suffix" ]]; then
            local with_suffix="${temp_file}.${suffix}"
            mv "$temp_file" "$with_suffix"
            temp_file="$with_suffix"
          fi
          decrypt_age_file "$file" > "$temp_file"
          chmod 600 "$temp_file"
          write_env "$name" "$temp_file"
        }

        decrypt_dotenv_optional() {
          local file="$1"
          if [[ ! -f "$file" ]]; then
            echo "::notice ::Skipping optional release secret ${file}"
            return 0
          fi
          local temp_file
          temp_file="$(mktemp "${RUNNER_TEMP:-/tmp}/burrow-release-dotenv.XXXXXX")"
          decrypt_age_file "$file" > "$temp_file"
          # shellcheck disable=SC1090
          set -a
          source "$temp_file"
          set +a
          rm -f "$temp_file"

          if [[ -z "${MINIO_ROOT_USER:-}" || -z "${MINIO_ROOT_PASSWORD:-}" ]]; then
            echo "::error ::${file} must define MINIO_ROOT_USER and MINIO_ROOT_PASSWORD." >&2
            exit 1
          fi
          echo "::add-mask::${MINIO_ROOT_USER}"
          echo "::add-mask::${MINIO_ROOT_PASSWORD}"
          {
            echo "AWS_ACCESS_KEY_ID=${MINIO_ROOT_USER}"
            echo "AWS_SECRET_ACCESS_KEY=${MINIO_ROOT_PASSWORD}"
            echo "AWS_DEFAULT_REGION=${BLOB_REGION:-hel1}"
            echo "AWS_REGION=${BLOB_REGION:-hel1}"
            echo "AWS_S3_ENDPOINT_URL=https://${BLOB_ENDPOINT:-hel1.your-objectstorage.com}"
          } >> "$GITHUB_ENV"
        }

        decode_base64_stream() {
          if command -v base64 >/dev/null 2>&1; then
            base64 -d 2>/dev/null || base64 -D
          elif command -v openssl >/dev/null 2>&1; then
            openssl base64 -d -A
          else
            echo "::error ::base64 or openssl is required to decode release secrets." >&2
            return 127
          fi
        }

        decode_base64_to_file() {
          local output="$1"
          decode_base64_stream > "$output"
        }

        decrypt_appstore_connect() {
          local file="$ROOT/secrets/apple/appstore-connect.env.age"
          if [[ ! -f "$file" ]]; then
            echo "::notice ::Skipping optional release secret ${file}"
            return 0
          fi

          local temp_file key_path key_value
          temp_file="$(mktemp "${RUNNER_TEMP:-/tmp}/burrow-asc-env.XXXXXX")"
          decrypt_age_file "$file" > "$temp_file"
          # shellcheck disable=SC1090
          set -a
          source "$temp_file"
          set +a
          rm -f "$temp_file"

          if [[ -z "${ASC_API_KEY_ID:-}" || -z "${ASC_API_ISSUER_ID:-}" ]]; then
            echo "::error ::${file} must define ASC_API_KEY_ID and ASC_API_ISSUER_ID." >&2
            exit 1
          fi

          key_path="$(mktemp "${RUNNER_TEMP:-/tmp}/burrow-asc-key.XXXXXX.p8")"
          if [[ -n "${ASC_API_KEY_BASE64:-}" ]]; then
            printf '%s' "$ASC_API_KEY_BASE64" | decode_base64_to_file "$key_path"
          elif [[ -n "${ASC_API_KEY_P8_BASE64:-}" ]]; then
            printf '%s' "$ASC_API_KEY_P8_BASE64" | decode_base64_to_file "$key_path"
          elif [[ -n "${APPSTORE_KEY:-}" ]]; then
            printf '%s\n' "$APPSTORE_KEY" > "$key_path"
          elif [[ -n "${ASC_API_KEY:-}" ]]; then
            printf '%s\n' "$ASC_API_KEY" > "$key_path"
          else
            echo "::error ::${file} must define ASC_API_KEY_BASE64 or ASC_API_KEY." >&2
            exit 1
          fi
          chmod 600 "$key_path"
          key_value="$(cat "$key_path")"
          mask_multiline "$key_value"
          echo "::add-mask::${ASC_API_KEY_ID}"
          echo "::add-mask::${ASC_API_ISSUER_ID}"
          write_env ASC_API_KEY_ID "$ASC_API_KEY_ID"
          write_env ASC_API_ISSUER_ID "$ASC_API_ISSUER_ID"
          write_env ASC_API_KEY_PATH "$key_path"
        }

        decrypt_distribution_signing() {
          local file="$ROOT/secrets/apple/distribution-signing.env.age"
          if [[ ! -f "$file" ]]; then
            echo "::notice ::Skipping optional release secret ${file}"
            return 0
          fi

          local temp_file cert_path cert_password cert_base64
          temp_file="$(mktemp "${RUNNER_TEMP:-/tmp}/burrow-signing-env.XXXXXX")"
          decrypt_age_file "$file" > "$temp_file"
          # shellcheck disable=SC1090
          set -a
          source "$temp_file"
          set +a
          rm -f "$temp_file"

          cert_base64="${APPLE_SIGNING_CERTIFICATE_BASE64:-${APPLE_DISTRIBUTION_CERTIFICATE_BASE64:-}}"
          cert_password="${APPLE_SIGNING_CERTIFICATE_PASSWORD:-${APPLE_DISTRIBUTION_CERTIFICATE_PASSWORD:-}}"
          if [[ -z "$cert_password" && -n "${APPLE_SIGNING_CERTIFICATE_PASSWORD_BASE64:-}" ]]; then
            cert_password="$(printf '%s' "$APPLE_SIGNING_CERTIFICATE_PASSWORD_BASE64" | decode_base64_stream)"
          fi
          if [[ -z "$cert_base64" || -z "$cert_password" ]]; then
            echo "::error ::${file} must define APPLE_SIGNING_CERTIFICATE_BASE64 and APPLE_SIGNING_CERTIFICATE_PASSWORD." >&2
            exit 1
          fi

          cert_path="$(mktemp "${RUNNER_TEMP:-/tmp}/burrow-apple-signing.XXXXXX.p12")"
          printf '%s' "$cert_base64" | decode_base64_to_file "$cert_path"
          chmod 600 "$cert_path"
          echo "::add-mask::${cert_password}"
          write_env APPLE_SIGNING_CERTIFICATE_PATH "$cert_path"
          write_env APPLE_SIGNING_CERTIFICATE_PASSWORD "$cert_password"
          write_env APPLE_KEYCHAIN_PASSWORD "$cert_password"
        }

        decrypt_sparkle() {
          local file="$ROOT/secrets/apple/sparkle.env.age"
          if [[ ! -f "$file" ]]; then
            echo "::notice ::Skipping optional release secret ${file}"
            return 0
          fi

          local temp_file key_path key_base64 key_value
          temp_file="$(mktemp "${RUNNER_TEMP:-/tmp}/burrow-sparkle-env.XXXXXX")"
          decrypt_age_file "$file" > "$temp_file"
          # shellcheck disable=SC1090
          set -a
          source "$temp_file"
          set +a
          rm -f "$temp_file"

          key_base64="${SPARKLE_EDDSA_KEY_BASE64:-${SPARKLE_PRIVATE_KEY_BASE64:-}}"
          key_path="$(mktemp "${RUNNER_TEMP:-/tmp}/burrow-sparkle-eddsa.XXXXXX.key")"
          if [[ -n "$key_base64" ]]; then
            printf '%s' "$key_base64" | decode_base64_to_file "$key_path"
          elif [[ -n "${SPARKLE_EDDSA_KEY:-}" ]]; then
            printf '%s\n' "$SPARKLE_EDDSA_KEY" > "$key_path"
          elif [[ -n "${SPARKLE_PRIVATE_KEY:-}" ]]; then
            printf '%s\n' "$SPARKLE_PRIVATE_KEY" > "$key_path"
          else
            echo "::error ::${file} must define SPARKLE_EDDSA_KEY_BASE64 or SPARKLE_EDDSA_KEY." >&2
            exit 1
          fi
          chmod 600 "$key_path"
          key_value="$(cat "$key_path")"
          mask_multiline "$key_value"
          write_env SPARKLE_EDDSA_KEY_PATH "$key_path"
        }

        decrypt_appstore_connect
        decrypt_distribution_signing
        decrypt_sparkle

        decrypt_dotenv_optional "$ROOT/secrets/hetzner/object-storage.age"
