name: AWS Conformance Test

on:
  push:
    branches:
    - main

# This prevents two workflows from running at the same time.
# This workflows calls terragrunt, which does not allow concurrent runs.
concurrency:
  group: aws-conformance
  cancel-in-progress: false

permissions:
  id-token: write
  contents: read

env:
  TOFU_VERSION: "1.10.0"
  TG_VERSION: "0.77.22"
  TG_DIR: "deployment/live/aws/conformance/ci/"
  TESSERA_PREFIX_NAME: trillian-tessera
  ECR_REGISTRY: 864981736166.dkr.ecr.us-east-1.amazonaws.com
  ECR_REPOSITORY_CONFORMANCE: trillian-tessera/conformance:latest
  ECR_REPOSITORY_HAMMER: trillian-tessera/hammer:latest
  AWS_REGION: us-east-1

jobs:
  aws-integration:
    runs-on: ubuntu-latest

    steps:
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@00943011d9042930efac3dcd3a170e4273319bc8 # v5.1.0
        with:
          role-to-assume: ${{ vars.AWS_IAMROLE_GITHUB_CI }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Checkout code
        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
        with:
          persist-credentials: false

      ## Authenticate with ECR to push the conformance and hammer images.
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1

      ## Build the conformance image and push it to ECR. This will be used
      ## later on by Terragrunt.
      - name: Build, tag, and push Conformance image to Amazon ECR
        id: build-publish-conformance
        shell: bash
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: ${{ env.ECR_REPOSITORY_CONFORMANCE }}
        run: |
          docker build -f ./cmd/conformance/aws/Dockerfile . -t "$ECR_REGISTRY/$ECR_REPOSITORY"
          docker push "$ECR_REGISTRY/$ECR_REPOSITORY"
          echo "Pushed image to $ECR_REGISTRY/$ECR_REPOSITORY"

      ## Build the hammer image and push it to ECR. This will be used
      ## later on by Terragrunt.
      - name: Build, tag, and push Hammer image to Amazon ECR
        id: build-publish-hammer
        shell: bash
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: ${{ env.ECR_REPOSITORY_HAMMER }}
        run: |
          docker build -f ./internal/hammer/Dockerfile . -t "$ECR_REGISTRY/$ECR_REPOSITORY"
          docker push "$ECR_REGISTRY/$ECR_REPOSITORY"
          echo "Pushed image to $ECR_REGISTRY/$ECR_REPOSITORY"

      ## Destroy any pre-existing deployment/live/aws/conformance/ci env.
      ## This might happen if a previous integration test workflow has failed.
      - name: Terragrunt destroy pre conformance test
        id: terragrunt-destroy-pre
        uses: gruntwork-io/terragrunt-action@95fc057922e3c3d4cc021a81a213f088f333ddef # v3.0.2
        with:
          tofu_version: ${{ env.TOFU_VERSION }}
          tg_version: ${{ env.TG_VERSION }}
          tg_dir: ${{ env.TG_DIR }}
          tg_command: "destroy"
        env:
          ECS_EXECUTION_ROLE: ${{ vars.AWS_IAMROLE_ECS_EXECUTION }}
          ECS_CONFORMANCE_TASK_ROLE: ${{ vars.AWS_IAMROLE_ECS_CONFORMANCE_TASK }}
          TESSERA_SIGNER: unused
          TESSERA_VERIFIER: unused

      ## Generate a new keys for the log to use, and export them to environment
      ## variables for Terragrunt to use.
      - name: Generate Tessera keys
        id: generate-keys
        shell: bash
        run: |
          go run github.com/transparency-dev/serverless-log/cmd/generate_keys@80334bc9dc573e8f6c5b3694efad6358da50abd4 \
            --key_name=tessera/test/conformance \
            --out_priv=${{ runner.temp }}/key.sec \
            --out_pub=${{ runner.temp }}/key.pub
          cat ${{ runner.temp }}/key.pub
          echo "TESSERA_SIGNER=$(cat ${{ runner.temp }}/key.sec)" >> "$GITHUB_ENV"
          echo "TESSERA_VERIFIER=$(cat ${{ runner.temp }}/key.pub)" >> "$GITHUB_ENV"

      ## Apply the deployment/live/aws/conformance/ci terragrunt config.
      ## This will bring up the conformance infrastructure which consists of:
      ##   - the storage module
      ##   - a private S3 <--> ECS network link for the hammer to read the log
      ##   - an ECS cluster to run Fargate tasks
      ##   - a conformance service, with multiple conformance binary instances
      ##   - a hammer task definition (but no execution)
      # TODO(phboneff): AuroraDB takes a long time to be brought up and down
      #  consider keeping it around between tests / using Aurora Serveless
      - name: Terragrunt apply
        id: terragrunt-apply
        uses: gruntwork-io/terragrunt-action@95fc057922e3c3d4cc021a81a213f088f333ddef # v3.0.2
        with:
          tofu_version: ${{ env.TOFU_VERSION }}
          tg_version: ${{ env.TG_VERSION }}
          tg_dir: ${{ env.TG_DIR }}
          tg_command: "apply"
        env:
          ECS_EXECUTION_ROLE: ${{ vars.AWS_IAMROLE_ECS_EXECUTION }}
          ECS_CONFORMANCE_TASK_ROLE: ${{ vars.AWS_IAMROLE_ECS_CONFORMANCE_TASK }}
          INPUT_POST_EXEC_1: |
            echo "ECS_CLUSTER=$(terragrunt output -raw ecs_cluster)" >> "$GITHUB_ENV"
          INPUT_POST_EXEC_2: |
            echo "VPC_SUBNETS=$(terragrunt output -json vpc_subnets)" >> "$GITHUB_ENV"

      ## Now we can run the hammer using the task definition, against the
      ## conformance service. This step returns the hammer task's exit code.
      - name: Run Hammer
        id: hammer
        shell: bash
        run: |
          cat ${{ runner.temp }}/key.pub
          echo "Will launch a hammer ECS task."
          HAMMER_ARN=$(aws ecs run-task \
            --cluster="$ECS_CLUSTER" \
            --task-definition=hammer \
            --count=1 \
            --launch-type=FARGATE \
            --network-configuration='{"awsvpcConfiguration": {"assignPublicIp":"ENABLED","subnets": '$VPC_SUBNETS'}}' \
            --query 'tasks[0].taskArn')
          echo "Hammer task running, ARN: $HAMMER_ARN."
          echo "Waiting for task to stop..."
          aws ecs wait tasks-stopped --cluster="$ECS_CLUSTER" --tasks=[$HAMMER_ARN]
          echo "The task has stopped. Fetching exit code and returning this action with it."
          exit $(aws ecs describe-tasks --cluster="$ECS_CLUSTER" --tasks=[$HAMMER_ARN] --query 'tasks[0].containers[0].exitCode')

      - name: Terragrunt destroy post conformance test
        id: terragrunt-destroy-post
        uses: gruntwork-io/terragrunt-action@95fc057922e3c3d4cc021a81a213f088f333ddef # v3.0.2
        with:
          tofu_version: ${{ env.TOFU_VERSION }}
          tg_version: ${{ env.TG_VERSION }}
          tg_dir: ${{ env.TG_DIR }}
          tg_command: "destroy"
        env:
          ECS_EXECUTION_ROLE: ${{ vars.AWS_IAMROLE_ECS_EXECUTION }}
          ECS_CONFORMANCE_TASK_ROLE: ${{ vars.AWS_IAMROLE_ECS_CONFORMANCE_TASK }}
