# .gitea/workflows/authority-key-rotation.yml
# Manual workflow to push a new Authority signing key using OPS3 tooling

name: Authority Key Rotation

on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Target environment name (used to select secrets/vars)'
        required: true
        default: 'staging'
        type: choice
        options:
          - staging
          - production
      authority_url:
        description: 'Override Authority URL (leave blank to use env-specific secret)'
        required: false
        default: ''
        type: string
      key_id:
        description: 'New signing key identifier (kid)'
        required: true
        type: string
      key_path:
        description: 'Path (as Authority sees it) to the PEM key'
        required: true
        type: string
      source:
        description: 'Signing key source loader (default: file)'
        required: false
        default: 'file'
        type: string
      algorithm:
        description: 'Signing algorithm (default: ES256)'
        required: false
        default: 'ES256'
        type: string
      provider:
        description: 'Preferred crypto provider hint'
        required: false
        default: ''
        type: string
      metadata:
        description: 'Optional key=value metadata entries (comma-separated)'
        required: false
        default: ''
        type: string

jobs:
  rotate:
    runs-on: ubuntu-22.04
    environment: ${{ inputs.environment }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Resolve Authority configuration
        id: config
        run: |
          set -euo pipefail

          env_name=${{ inputs.environment }}
          echo "Environment: $env_name"

          bootstrap_key=""
          authority_url="${{ inputs.authority_url }}"

          # Helper to prefer secrets over variables and fall back to shared defaults
          resolve_var() {
            local name="$1"
            local default="$2"
            local value="${{ secrets[name] }}"
            if [ -z "$value" ]; then value="${{ vars[name] }}"; fi
            if [ -z "$value" ]; then value="$default"; fi
            printf '%s' "$value"
          }

          key_name="${env_name^^}_AUTHORITY_BOOTSTRAP_KEY"
          bootstrap_key="$(resolve_var "$key_name" "")"
          if [ -z "$bootstrap_key" ]; then
            bootstrap_key="$(resolve_var "AUTHORITY_BOOTSTRAP_KEY" "")"
          fi

          if [ -z "$bootstrap_key" ]; then
            echo "::error::Missing bootstrap key secret (expected $key_name or AUTHORITY_BOOTSTRAP_KEY)"
            exit 1
          fi

          if [ -z "$authority_url" ]; then
            url_name="${env_name^^}_AUTHORITY_URL"
            authority_url="$(resolve_var "$url_name" "")"
            if [ -z "$authority_url" ]; then
              authority_url="$(resolve_var "AUTHORITY_URL" "")"
            fi
          fi

          if [ -z "$authority_url" ]; then
            echo "::error::Authority URL not provided and no secret/var found"
            exit 1
          fi

          key_file="${RUNNER_TEMP}/authority-bootstrap-key"
          printf '%s\n' "$bootstrap_key" > "$key_file"
          chmod 600 "$key_file"

          echo "bootstrap-key-file=$key_file" >> "$GITHUB_OUTPUT"
          echo "authority-url=$authority_url" >> "$GITHUB_OUTPUT"

      - name: Execute key rotation
        id: rotate
        shell: bash
        env:
          AUTHORITY_BOOTSTRAP_KEY_FILE: ${{ steps.config.outputs['bootstrap-key-file'] }}
          AUTHORITY_URL: ${{ steps.config.outputs['authority-url'] }}
          KEY_ID: ${{ inputs.key_id }}
          KEY_PATH: ${{ inputs.key_path }}
          KEY_SOURCE: ${{ inputs.source }}
          KEY_ALGORITHM: ${{ inputs.algorithm }}
          KEY_PROVIDER: ${{ inputs.provider }}
          KEY_METADATA: ${{ inputs.metadata }}
        run: |
          set -euo pipefail

          bootstrap_key=$(cat "$AUTHORITY_BOOTSTRAP_KEY_FILE")

          metadata_args=()
          if [ -n "$KEY_METADATA" ]; then
            IFS=',' read -ra META <<< "$KEY_METADATA"
            for entry in "${META[@]}"; do
              trimmed="$(echo "$entry" | xargs)"
              [ -z "$trimmed" ] && continue
              metadata_args+=(-m "$trimmed")
            done
          fi

          provider_args=()
          if [ -n "$KEY_PROVIDER" ]; then
            provider_args+=(--provider "$KEY_PROVIDER")
          fi

          ./ops/authority/key-rotation.sh \
            --authority-url "$AUTHORITY_URL" \
            --api-key "$bootstrap_key" \
            --key-id "$KEY_ID" \
            --key-path "$KEY_PATH" \
            --source "$KEY_SOURCE" \
            --algorithm "$KEY_ALGORITHM" \
            "${provider_args[@]}" \
            "${metadata_args[@]}"

      - name: JWKS summary
        run: |
          echo "✅ Rotation complete"
          echo "Environment: ${{ inputs.environment }}"
          echo "Authority: ${{ steps.config.outputs['authority-url'] }}"
          echo "Key ID: ${{ inputs.key_id }}"
          echo "Key Path: ${{ inputs.key_path }}"
          echo "Source: ${{ inputs.source }}"
          echo "Algorithm: ${{ inputs.algorithm }}"
