# GitHub Actions deploy identity.
#
# Lets the GitHub repo's Actions workflow authenticate to GCP through Workload
# Identity Federation (no long-lived JSON key), then build the image with Cloud
# Build and update the Cloud Run jobs. The two outputs in outputs.tf are the
# exact values for the repo secrets GCP_WORKLOAD_IDENTITY_PROVIDER and
# GCP_DEPLOY_SERVICE_ACCOUNT.

resource "google_iam_workload_identity_pool" "github" {
  project                   = var.project_id
  workload_identity_pool_id = "github-pool"
  display_name              = "GitHub Actions pool"
  description               = "OIDC identity pool for GitHub Actions deploys"

  depends_on = [google_project_service.required]
}

resource "google_iam_workload_identity_pool_provider" "github" {
  project                            = var.project_id
  workload_identity_pool_id          = google_iam_workload_identity_pool.github.workload_identity_pool_id
  workload_identity_pool_provider_id = "github-provider"
  display_name                       = "GitHub OIDC provider"

  attribute_mapping = {
    "google.subject"        = "assertion.sub"
    "attribute.environment" = "assertion.environment"
    "attribute.ref"         = "assertion.ref"
    "attribute.repository"  = "assertion.repository"
  }

  # Restrict deploy impersonation to this repository's production environment
  # on main. Repository-only admission would let a workflow on another branch
  # request the production deployer identity.
  attribute_condition = "assertion.repository == \"${var.github_repository}\" && assertion.ref == \"refs/heads/main\" && assertion.environment == \"production\""

  oidc {
    issuer_uri = "https://token.actions.githubusercontent.com"
  }
}

resource "google_service_account" "deployer" {
  project      = var.project_id
  account_id   = "pingcap-deployer"
  display_name = "GitHub Actions deployer for pingcap-datapipelines"

  depends_on = [google_project_service.required]
}

# Allow only this repo's Actions runs to impersonate the deployer SA.
resource "google_service_account_iam_member" "deployer_workload_identity_user" {
  service_account_id = google_service_account.deployer.name
  role               = "roles/iam.workloadIdentityUser"
  member             = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.github.name}/attribute.repository/${var.github_repository}"
}

# Submit Cloud Build builds (the build itself runs as the Cloud Build service
# account, which already has Artifact Registry write access from the initial
# manual deploy; if a build push ever fails, grant roles/artifactregistry.writer
# to that build SA on the pingcap-datapipelines repo).
resource "google_project_iam_member" "deployer_cloudbuild" {
  project = var.project_id
  role    = "roles/cloudbuild.builds.editor"
  member  = "serviceAccount:${google_service_account.deployer.email}"
}

# Update the Cloud Run jobs to the new image.
resource "google_project_iam_member" "deployer_run_developer" {
  project = var.project_id
  role    = "roles/run.developer"
  member  = "serviceAccount:${google_service_account.deployer.email}"
}

# Updating a job that runs as the runtime SA requires actAs on that SA.
resource "google_service_account_iam_member" "deployer_act_as_runtime" {
  service_account_id = google_service_account.runtime.name
  role               = "roles/iam.serviceAccountUser"
  member             = "serviceAccount:${google_service_account.deployer.email}"
}

resource "google_service_account_iam_member" "deployer_act_as_outbound_runtime" {
  service_account_id = google_service_account.outbound_runtime.name
  role               = "roles/iam.serviceAccountUser"
  member             = "serviceAccount:${google_service_account.deployer.email}"
}

# `gcloud builds submit` needs serviceusage.services.use (to use the Cloud Build
# API under this project) beyond what cloudbuild.builds.editor grants.
resource "google_project_iam_member" "deployer_service_usage" {
  project = var.project_id
  role    = "roles/serviceusage.serviceUsageConsumer"
  member  = "serviceAccount:${google_service_account.deployer.email}"
}

# `gcloud builds submit` uploads source to the Cloud Build staging bucket and
# reads the bucket metadata first, so the deployer needs storage.admin on it
# (objectAdmin lacks storage.buckets.get).
resource "google_storage_bucket_iam_member" "deployer_cloudbuild_bucket" {
  bucket = "${var.project_id}_cloudbuild"
  role   = "roles/storage.admin"
  member = "serviceAccount:${google_service_account.deployer.email}"
}

# The workflow now builds on the runner and pushes directly to Artifact
# Registry, so the deployer needs write access. Granted at the project level so
# it covers every repo and avoids slow per-repo IAM propagation.
resource "google_project_iam_member" "deployer_ar_writer" {
  project = var.project_id
  role    = "roles/artifactregistry.writer"
  member  = "serviceAccount:${google_service_account.deployer.email}"
}
