---
# yamllint disable rule:line-length
# Opt-in teaching sample. The repository root Pages pipeline must not include this file.
workflow:
  rules:
    - if: '$IAC_PIPELINE == "true"'
    - when: never

stages:
  - format
  - validate
  - test
  - plan
  - apply
  - verify
  - drift

variables:
  AWS_REGION: ap-south-1
  AWS_DEFAULT_REGION: ap-south-1
  AWS_PROFILE: ci-oidc
  IAC_TOOL: tofu
  TERRAFORM_VERSION: 1.16.0
  OPENTOFU_VERSION: 1.12.6
  TERRAFORM_LINUX_AMD64_SHA256: 41d05b927aa174f15d1228c4eba832a323b716c68b415ef5a00179f46cc602d3
  OPENTOFU_LINUX_AMD64_SHA256: 5dc43da4f750f33873dc25e94587128709e819e544b7be9016b255316153c3a8
  FOUNDATION_ROOT: learn-terraform/capstone/infra/stacks/foundation

.iac:
  image: alpine:3.22
  before_script:
    - apk add --no-cache aws-cli curl unzip
    - test "$IAC_TOOL" = terraform || test "$IAC_TOOL" = tofu
    - test "$TERRAFORM_VERSION" = "1.16.0"
    - test "$OPENTOFU_VERSION" = "1.12.6"
    - test "$TERRAFORM_LINUX_AMD64_SHA256" = "41d05b927aa174f15d1228c4eba832a323b716c68b415ef5a00179f46cc602d3"
    - test "$OPENTOFU_LINUX_AMD64_SHA256" = "5dc43da4f750f33873dc25e94587128709e819e544b7be9016b255316153c3a8"
    - |
      if [ "$IAC_TOOL" = terraform ]; then
        curl -fsSLo /tmp/iac.zip "https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip"
        printf '%s  %s\n' "$TERRAFORM_LINUX_AMD64_SHA256" /tmp/iac.zip | sha256sum -c -
      else
        curl -fsSLo /tmp/iac.zip "https://github.com/opentofu/opentofu/releases/download/v${OPENTOFU_VERSION}/tofu_${OPENTOFU_VERSION}_linux_amd64.zip"
        printf '%s  %s\n' "$OPENTOFU_LINUX_AMD64_SHA256" /tmp/iac.zip | sha256sum -c -
      fi
    - unzip -q /tmp/iac.zip -d /usr/local/bin
    - '"$IAC_TOOL" version'
  after_script:
    - printf 'job=%s status=%s commit=%s\n' "$CI_JOB_NAME" "$CI_JOB_STATUS" "$CI_COMMIT_SHA" > ci-evidence.txt
  artifacts:
    when: always
    expire_in: 1 hour
    paths:
      - ci-evidence.txt

.aws_oidc:
  extends: .iac
  id_tokens:
    AWS_ID_TOKEN:
      aud: sts.amazonaws.com
  before_script:
    - apk add --no-cache aws-cli curl unzip
    - test "$IAC_TOOL" = terraform || test "$IAC_TOOL" = tofu
    - test "$TERRAFORM_VERSION" = "1.16.0"
    - test "$OPENTOFU_VERSION" = "1.12.6"
    - test "$TERRAFORM_LINUX_AMD64_SHA256" = "41d05b927aa174f15d1228c4eba832a323b716c68b415ef5a00179f46cc602d3"
    - test "$OPENTOFU_LINUX_AMD64_SHA256" = "5dc43da4f750f33873dc25e94587128709e819e544b7be9016b255316153c3a8"
    - |
      if [ "$IAC_TOOL" = terraform ]; then
        curl -fsSLo /tmp/iac.zip "https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip"
        printf '%s  %s\n' "$TERRAFORM_LINUX_AMD64_SHA256" /tmp/iac.zip | sha256sum -c -
      else
        curl -fsSLo /tmp/iac.zip "https://github.com/opentofu/opentofu/releases/download/v${OPENTOFU_VERSION}/tofu_${OPENTOFU_VERSION}_linux_amd64.zip"
        printf '%s  %s\n' "$OPENTOFU_LINUX_AMD64_SHA256" /tmp/iac.zip | sha256sum -c -
      fi
    - unzip -q /tmp/iac.zip -d /usr/local/bin
    - '"$IAC_TOOL" version'
    - test -n "$AWS_ROLE_ARN"
    - test -n "$EXPECTED_AWS_ACCOUNT_ID"
    - test -n "$TF_VAR_budget_alert_email"
    - test -f "$FOUNDATION_BACKEND_CONFIG"
    - export AWS_WEB_IDENTITY_TOKEN_FILE="$CI_PROJECT_DIR/aws_oidc_token"
    - printf '%s' "$AWS_ID_TOKEN" > "$AWS_WEB_IDENTITY_TOKEN_FILE"
    - printf '[profile %s]\nrole_arn = %s\nweb_identity_token_file = %s\nregion = %s\n' "$AWS_PROFILE" "$AWS_ROLE_ARN" "$AWS_WEB_IDENTITY_TOKEN_FILE" "$AWS_REGION" > "$CI_PROJECT_DIR/aws_config"
    - export AWS_CONFIG_FILE="$CI_PROJECT_DIR/aws_config"
    - aws sts get-caller-identity --profile "$AWS_PROFILE" --query Account --output text > caller-account.txt
    - test "$EXPECTED_AWS_ACCOUNT_ID" = "$(cat caller-account.txt)"

fmt:
  extends: .iac
  stage: format
  script:
    - '"$IAC_TOOL" fmt -check -recursive learn-terraform/capstone'

validate:
  extends: .iac
  stage: validate
  script:
    - '"$IAC_TOOL" -chdir="$FOUNDATION_ROOT" init -backend=false -input=false'
    - '"$IAC_TOOL" -chdir="$FOUNDATION_ROOT" validate'

native-test:
  extends: .iac
  stage: test
  script:
    - '"$IAC_TOOL" -chdir=learn-terraform/capstone/infra/modules/network init -backend=false -input=false'
    - '"$IAC_TOOL" -chdir=learn-terraform/capstone/infra/modules/network test -test-directory=tests'

plan:
  extends: .aws_oidc
  stage: plan
  resource_group: foundation-production
  script:
    - '"$IAC_TOOL" -chdir="$FOUNDATION_ROOT" init -input=false -backend-config="$FOUNDATION_BACKEND_CONFIG" -backend-config="profile=$AWS_PROFILE"'
    - '"$IAC_TOOL" -chdir="$FOUNDATION_ROOT" plan -input=false -out=tfplan -var-file=../../environments/production/foundation.tfvars -var="aws_profile=$AWS_PROFILE" -var="expected_aws_account_id=$EXPECTED_AWS_ACCOUNT_ID"'
    - '"$IAC_TOOL" -chdir="$FOUNDATION_ROOT" show tfplan'
    - printf '%s\n' "$CI_COMMIT_SHA" > "$FOUNDATION_ROOT/plan.commit"
    - printf '%s\n' "$IAC_TOOL" > "$FOUNDATION_ROOT/plan.tool"
    - '"$IAC_TOOL" version -json > "$FOUNDATION_ROOT/plan.tool-version.json"'
    - printf '%s\n' "$AWS_REGION" > "$FOUNDATION_ROOT/plan.region"
    - sha256sum "$FOUNDATION_BACKEND_CONFIG" | awk '{print $1}' > "$FOUNDATION_ROOT/plan.backend"
    - cp caller-account.txt "$FOUNDATION_ROOT/plan.account"
  artifacts:
    expire_in: 1 hour
    paths:
      - learn-terraform/capstone/infra/stacks/foundation/tfplan
      - learn-terraform/capstone/infra/stacks/foundation/plan.commit
      - learn-terraform/capstone/infra/stacks/foundation/plan.tool
      - learn-terraform/capstone/infra/stacks/foundation/plan.tool-version.json
      - learn-terraform/capstone/infra/stacks/foundation/.terraform.lock.hcl
      - learn-terraform/capstone/infra/stacks/foundation/plan.region
      - learn-terraform/capstone/infra/stacks/foundation/plan.backend
      - learn-terraform/capstone/infra/stacks/foundation/plan.account
      - ci-evidence.txt

apply-production:
  extends: .aws_oidc
  stage: apply
  resource_group: foundation-production
  needs:
    - job: plan
      artifacts: true
  environment:
    name: production
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_REF_PROTECTED == "true"'
      when: manual
    - when: never
  script:
    - test -f "$FOUNDATION_ROOT/.terraform.lock.hcl"
    - '"$IAC_TOOL" -chdir="$FOUNDATION_ROOT" init -input=false -lockfile=readonly -backend-config="$FOUNDATION_BACKEND_CONFIG" -backend-config="profile=$AWS_PROFILE"'
    - test "$CI_COMMIT_SHA" = "$(cat "$FOUNDATION_ROOT/plan.commit")"
    - test "$IAC_TOOL" = "$(cat "$FOUNDATION_ROOT/plan.tool")"
    - '"$IAC_TOOL" version -json > "$FOUNDATION_ROOT/apply.tool-version.json"'
    - cmp "$FOUNDATION_ROOT/plan.tool-version.json" "$FOUNDATION_ROOT/apply.tool-version.json"
    - test "$AWS_REGION" = "$(cat "$FOUNDATION_ROOT/plan.region")"
    - test "$(cat "$FOUNDATION_ROOT/plan.backend")" = "$(sha256sum "$FOUNDATION_BACKEND_CONFIG" | awk '{print $1}')"
    - test "$EXPECTED_AWS_ACCOUNT_ID" = "$(cat "$FOUNDATION_ROOT/plan.account")"
    - '"$IAC_TOOL" -chdir="$FOUNDATION_ROOT" apply -input=false tfplan'

verify:
  extends: .aws_oidc
  stage: verify
  resource_group: foundation-production
  needs:
    - job: apply-production
  script:
    - '"$IAC_TOOL" -chdir="$FOUNDATION_ROOT" init -input=false -backend-config="$FOUNDATION_BACKEND_CONFIG" -backend-config="profile=$AWS_PROFILE"'
    - '"$IAC_TOOL" -chdir="$FOUNDATION_ROOT" output'

drift:
  extends: .aws_oidc
  stage: drift
  resource_group: foundation-production
  needs:
    - job: verify
  allow_failure: true
  script:
    - '"$IAC_TOOL" -chdir="$FOUNDATION_ROOT" init -input=false -backend-config="$FOUNDATION_BACKEND_CONFIG" -backend-config="profile=$AWS_PROFILE"'
    - '"$IAC_TOOL" -chdir="$FOUNDATION_ROOT" plan -refresh-only -detailed-exitcode -input=false -var-file=../../environments/production/foundation.tfvars -var="aws_profile=$AWS_PROFILE" -var="expected_aws_account_id=$EXPECTED_AWS_ACCOUNT_ID" || test "$?" = 2'
