From b00767ca44c1368b4d9871a90a0bcf7144a5a9b6 Mon Sep 17 00:00:00 2001 From: chrispsheehan Date: Wed, 27 May 2026 11:32:45 +0100 Subject: [PATCH 1/2] fix: no infra change for fe code --- infra/modules/aws/frontend/README.md | 2 +- infra/modules/aws/frontend/main.tf | 9 +++++++++ infra/modules/aws/rds_reader_tagger/main.tf | 3 ++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/infra/modules/aws/frontend/README.md b/infra/modules/aws/frontend/README.md index 612f65b9..064619e8 100644 --- a/infra/modules/aws/frontend/README.md +++ b/infra/modules/aws/frontend/README.md @@ -50,4 +50,4 @@ If the hosted zone does not already exist, certificate validation and alias-reco Used by the frontend build and deploy workflow path. -The Terraform module uploads a bootstrap `index.html` so the distribution serves a valid page before the built frontend assets are published. Later frontend deploys replace that object with the real app bundle output. +The Terraform module uploads a bootstrap `index.html` so the distribution serves a valid page before the built frontend assets are published. Later frontend deploys replace that object with the real app bundle output, so Terraform intentionally ignores live content and metadata drift on that bootstrap object after creation. diff --git a/infra/modules/aws/frontend/main.tf b/infra/modules/aws/frontend/main.tf index 31c43756..396fc77d 100644 --- a/infra/modules/aws/frontend/main.tf +++ b/infra/modules/aws/frontend/main.tf @@ -31,6 +31,15 @@ resource "aws_s3_object" "bootstrap_index" { source = "${path.module}/bootstrap/index.html" etag = filemd5("${path.module}/bootstrap/index.html") content_type = "text/html; charset=utf-8" + + lifecycle { + ignore_changes = [ + content_type, + etag, + source, + tags_all, + ] + } } resource "aws_s3_object" "auth_config" { diff --git a/infra/modules/aws/rds_reader_tagger/main.tf b/infra/modules/aws/rds_reader_tagger/main.tf index ea68c86a..864643a3 100644 --- a/infra/modules/aws/rds_reader_tagger/main.tf +++ b/infra/modules/aws/rds_reader_tagger/main.tf @@ -45,7 +45,8 @@ resource "aws_cloudwatch_event_target" "reader_instance_created" { resource "aws_lambda_permission" "allow_eventbridge" { statement_id = "AllowEventBridgeInvoke" action = "lambda:InvokeFunction" - function_name = module.rds_reader_tagger.alias_arn + function_name = module.rds_reader_tagger.arn principal = "events.amazonaws.com" + qualifier = module.rds_reader_tagger.alias_name source_arn = aws_cloudwatch_event_rule.reader_instance_created.arn } From ea1339430390959235ae56ed18787b8641862032 Mon Sep 17 00:00:00 2001 From: chrispsheehan Date: Wed, 27 May 2026 11:46:38 +0100 Subject: [PATCH 2/2] chore: support health from bootstrap --- infra/modules/aws/_shared/service/README.md | 3 +-- infra/modules/aws/_shared/service/locals.tf | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/infra/modules/aws/_shared/service/README.md b/infra/modules/aws/_shared/service/README.md index 23890d99..9efa3943 100644 --- a/infra/modules/aws/_shared/service/README.md +++ b/infra/modules/aws/_shared/service/README.md @@ -41,8 +41,7 @@ When `connection_type = "vpc_link"`, the module can also attach a shared API Gat Bootstrap ECS services resolve the shared placeholder image from the ECR repository named by `ecr_repository_name` using the stable `bootstrap` tag. That placeholder image is expected to be a stable shared tag, so infra applies can reuse the same bootstrap task definition input instead of churning a new placeholder image reference on every release. -Bootstrap health checks use `/`. -Real task deploys use the normal app health path, such as `/health` or `//health`. +Bootstrap and real task deploys use the same app health path, such as `/health` or `//health`, so target group health checks do not need to change during the transition from bootstrap to the deployed task. ## Decision Rules diff --git a/infra/modules/aws/_shared/service/locals.tf b/infra/modules/aws/_shared/service/locals.tf index 71175172..dae3044b 100644 --- a/infra/modules/aws/_shared/service/locals.tf +++ b/infra/modules/aws/_shared/service/locals.tf @@ -19,7 +19,8 @@ locals { green_target_group_name = "tg-${substr(md5("${var.service_name}-green"), 0, 8)}-green" is_default_path = var.root_path == "" - health_check_path = var.bootstrap ? "/" : (local.is_default_path ? "/health" : "/${var.root_path}/health") + health_check_path = local.is_default_path ? "/health" : "/${var.root_path}/health" + bootstrap_health_setup = local.is_default_path ? "printf 'ok\\n' > /usr/share/nginx/html/health" : "mkdir -p /usr/share/nginx/html/${var.root_path} && printf 'ok\\n' > /usr/share/nginx/html/health && printf 'ok\\n' > /usr/share/nginx/html/${var.root_path}/health" exact_route_key = local.is_default_path ? "ANY /" : "ANY /${var.root_path}" proxy_route_key = local.is_default_path ? "ANY /{proxy+}" : "ANY /${var.root_path}/{proxy+}" target_group_arn = local.is_default_path ? var.default_target_group_arn : aws_lb_target_group.service_target_group[0].arn @@ -90,7 +91,7 @@ locals { command = [ "sh", "-c", - "printf 'ok\\n' > /usr/share/nginx/html/health && exec nginx -g 'daemon off;'", + "${local.bootstrap_health_setup} && exec nginx -g 'daemon off;'", ] portMappings = [