From 7480aee3c86f23ba503773eb2f52c7cf1096487e Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Sat, 15 Aug 2026 01:26:23 -0400 Subject: [PATCH] fix(infra): serve pretty URLs via CloudFront directory index (PLAT-105) (#42) S3 OAC has no directory index, so /sustainability/ 404s while /sustainability/index.html is live. Rewrite directory URIs on viewer-request. --- terraform/cloudfront.tf | 15 +++++++++++++++ terraform/functions/directory-index.js | 15 +++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 terraform/functions/directory-index.js diff --git a/terraform/cloudfront.tf b/terraform/cloudfront.tf index 2f18033..e30e986 100644 --- a/terraform/cloudfront.tf +++ b/terraform/cloudfront.tf @@ -6,6 +6,16 @@ resource "aws_cloudfront_origin_access_control" "site" { signing_protocol = "sigv4" } +# Viewer-request rewrite so pretty URLs (/sustainability/) fetch S3 key +# sustainability/index.html. default_root_object only covers "/". PLAT-105. +resource "aws_cloudfront_function" "directory_index" { + name = "seahaven-site-prod-directory-index" + runtime = "cloudfront-js-2.0" + comment = "Rewrite directory and extensionless URIs to index.html" + publish = true + code = file("${path.module}/functions/directory-index.js") +} + # Shared CloudFront WAF (M-17) published by org-baseline stack seahaven-app-web-acl # in this account (PLAT-92). aws_cloudfront_distribution.web_acl_id takes the # WAFv2 ARN despite the attribute name. @@ -38,6 +48,11 @@ resource "aws_cloudfront_distribution" "site" { # Origin Cache-Control from GHA sync is honored (assets max-age=86400; html no-cache). cache_policy_id = "658327ea-f89d-4fab-a63d-7e88639e58f6" # CachingOptimized + + function_association { + event_type = "viewer-request" + function_arn = aws_cloudfront_function.directory_index.arn + } } custom_error_response { diff --git a/terraform/functions/directory-index.js b/terraform/functions/directory-index.js new file mode 100644 index 0000000..5b6e0e5 --- /dev/null +++ b/terraform/functions/directory-index.js @@ -0,0 +1,15 @@ +function handler(event) { + var request = event.request; + var uri = request.uri; + var last = uri.substring(uri.lastIndexOf("/") + 1); + + // S3 OAC has no directory index. default_root_object only covers "/". + // Keep the browser URL; rewrite the origin key to …/index.html. + if (uri.endsWith("/")) { + request.uri = uri + "index.html"; + } else if (last.length > 0 && last.indexOf(".") === -1) { + request.uri = uri + "/index.html"; + } + + return request; +}