diff --git a/infra/.envs/prod.tfvars b/infra/.envs/prod.tfvars index b965d0d61..642d62fbb 100644 --- a/infra/.envs/prod.tfvars +++ b/infra/.envs/prod.tfvars @@ -111,3 +111,9 @@ backend_min_instance_count = 1 frontend_min_instance_count = 1 notification_channel_ids = ["projects/web-compass-prod/notificationChannels/4991947607216940054"] email_service_account_email = "emailer-job-prod@webstatus-dev-internal-prod.iam.gserviceaccount.com" + +chime_details = { + env = "prod" + bcc_secret_ref = "chime-bcc-addresses" + from_address_secret_ref = "chime-from-address" +} diff --git a/infra/.envs/staging.tfvars b/infra/.envs/staging.tfvars index 75e091a15..9c6046fe6 100644 --- a/infra/.envs/staging.tfvars +++ b/infra/.envs/staging.tfvars @@ -115,3 +115,9 @@ backend_min_instance_count = 0 frontend_min_instance_count = 0 notification_channel_ids = ["projects/web-compass-staging/notificationChannels/7136127183667686021"] email_service_account_email = "emailer-job-staging@webstatus-dev-internal-staging.iam.gserviceaccount.com" + +chime_details = { + env = "autopush" + bcc_secret_ref = "chime-bcc-addresses" + from_address_secret_ref = "chime-from-address" +} diff --git a/infra/main.tf b/infra/main.tf index 95fffb3a0..04a19ea06 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -200,6 +200,8 @@ module "workers" { } frontend_base_url = var.frontend_base_url + chime_details = var.chime_details + email_service_account_email = var.email_service_account_email deletion_protection = var.deletion_protection } diff --git a/infra/variables.tf b/infra/variables.tf index 40251875a..2c9858cf7 100644 --- a/infra/variables.tf +++ b/infra/variables.tf @@ -214,3 +214,13 @@ variable "frontend_base_url" { type = string description = "Frontend base URL. Useful for email notifications for assets." } + +variable "chime_details" { + description = "Details for the chime API in the email worker" + type = object({ + # Limit env to "autopush" or "prod" to ensure it's used correctly in the code and avoid misconfiguration. + env = string + bcc_secret_ref = string + from_address_secret_ref = string + }) +} diff --git a/infra/workers/email/iam.tf b/infra/workers/email/iam.tf index ba0c8f1b0..50d490ae7 100644 --- a/infra/workers/email/iam.tf +++ b/infra/workers/email/iam.tf @@ -54,3 +54,20 @@ resource "google_project_iam_member" "gcp_trace_permission" { project = var.project_id member = "serviceAccount:${data.google_service_account.worker_sa.email}" } + + +resource "google_secret_manager_secret_iam_member" "worker_access_from_address" { + provider = google.internal_project + secret_id = data.google_secret_manager_secret.from_address_secret.id + role = "roles/secretmanager.secretAccessor" + member = "serviceAccount:${data.google_service_account.worker_sa.email}" + depends_on = [data.google_secret_manager_secret.from_address_secret] +} + +resource "google_secret_manager_secret_iam_member" "worker_access_bcc" { + provider = google.internal_project + secret_id = data.google_secret_manager_secret.bcc_secret.id + role = "roles/secretmanager.secretAccessor" + member = "serviceAccount:${data.google_service_account.worker_sa.email}" + depends_on = [data.google_secret_manager_secret.bcc_secret] +} diff --git a/infra/workers/email/main.tf b/infra/workers/email/main.tf index c8a9aabea..d41655759 100644 --- a/infra/workers/email/main.tf +++ b/infra/workers/email/main.tf @@ -51,6 +51,38 @@ resource "google_cloud_run_v2_worker_pool" "worker" { name = "FRONTEND_BASE_URL" value = var.frontend_base_url } + env { + name = "CHIME_ENV" + value = var.chime_env + } + env { + name = "CHIME_BCC" + value_source { + secret_key_ref { + secret = data.google_secret_manager_secret.bcc_secret.secret_id + version = "latest" + } + } + } + env { + name = "FROM_ADDRESS" + value_source { + secret_key_ref { + secret = data.google_secret_manager_secret.from_address_secret.secret_id + version = "latest" + } + } + } } } } + +data "google_secret_manager_secret" "from_address_secret" { + provider = google.internal_project + secret_id = var.from_address_secret_ref +} + +data "google_secret_manager_secret" "bcc_secret" { + provider = google.internal_project + secret_id = var.chime_bcc_secret_ref +} diff --git a/infra/workers/email/variables.tf b/infra/workers/email/variables.tf index 768df4280..f5b8ddf41 100644 --- a/infra/workers/email/variables.tf +++ b/infra/workers/email/variables.tf @@ -23,3 +23,6 @@ variable "service_account_email" { type = string } variable "regions" { type = set(string) } variable "deletion_protection" { type = bool } variable "frontend_base_url" { type = string } +variable "chime_env" { type = string } +variable "chime_bcc_secret_ref" { type = string } +variable "from_address_secret_ref" { type = string } diff --git a/infra/workers/main.tf b/infra/workers/main.tf index 506c5233e..73e15397b 100644 --- a/infra/workers/main.tf +++ b/infra/workers/main.tf @@ -117,4 +117,8 @@ module "email" { frontend_base_url = var.frontend_base_url deletion_protection = var.deletion_protection + + chime_env = var.chime_details.env + chime_bcc_secret_ref = var.chime_details.bcc_secret_ref + from_address_secret_ref = var.chime_details.from_address_secret_ref } diff --git a/infra/workers/variables.tf b/infra/workers/variables.tf index 19862eb17..ef8a1cf86 100644 --- a/infra/workers/variables.tf +++ b/infra/workers/variables.tf @@ -81,3 +81,11 @@ variable "frontend_base_url" { variable "deletion_protection" { type = bool } + +variable "chime_details" { + type = object({ + env = string + bcc_secret_ref = string + from_address_secret_ref = string + }) +} diff --git a/workers/email/cmd/job/main.go b/workers/email/cmd/job/main.go index 91bf8ec39..13df01a40 100644 --- a/workers/email/cmd/job/main.go +++ b/workers/email/cmd/job/main.go @@ -19,7 +19,9 @@ import ( "log/slog" "net/url" "os" + "strings" + "github.com/GoogleChrome/webstatus.dev/lib/email/chime" "github.com/GoogleChrome/webstatus.dev/lib/email/chime/chimeadapters" "github.com/GoogleChrome/webstatus.dev/lib/gcppubsub" "github.com/GoogleChrome/webstatus.dev/lib/gcppubsub/gcppubsubadapters" @@ -86,8 +88,29 @@ func main() { os.Exit(1) } + var emailSender sender.EmailSender + + slog.InfoContext(ctx, "using chime email sender") + chimeEnvStr := os.Getenv("CHIME_ENV") + chimeEnv := chime.EnvProd + if chimeEnvStr == "autopush" { + chimeEnv = chime.EnvAutopush + } + chimeBCC := os.Getenv("CHIME_BCC") + bccList := []string{} + if chimeBCC != "" { + bccList = strings.Split(chimeBCC, ",") + } + fromAddress := os.Getenv("FROM_ADDRESS") + chimeSender, err := chime.NewChimeSender(ctx, chimeEnv, bccList, fromAddress, nil) + if err != nil { + slog.ErrorContext(ctx, "failed to create chime sender", "error", err) + os.Exit(1) + } + emailSender = chimeadapters.NewEmailWorkerChimeAdapter(chimeSender) + listener := gcppubsubadapters.NewEmailWorkerSubscriberAdapter(sender.NewSender( - chimeadapters.NewEmailWorkerChimeAdapter(nil), + emailSender, spanneradapters.NewEmailWorkerChannelStateManager(spannerClient), renderer, ), queueClient, emailSubID) diff --git a/workers/event_producer/go.mod b/workers/event_producer/go.mod index 9059db8fc..96e74ea6d 100644 --- a/workers/event_producer/go.mod +++ b/workers/event_producer/go.mod @@ -11,7 +11,6 @@ require ( github.com/GoogleChrome/webstatus.dev/lib/gen v0.0.0-20251119220853-b545639c35ae github.com/google/go-cmp v0.7.0 github.com/google/uuid v1.6.0 - github.com/oapi-codegen/runtime v1.1.2 ) require ( @@ -61,6 +60,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/oapi-codegen/runtime v1.1.2 // indirect github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect