From 1028c717a33067d968f6307e62ba1bfd4febd29a Mon Sep 17 00:00:00 2001 From: Rayna-Yu Date: Sat, 21 Mar 2026 23:02:34 -0400 Subject: [PATCH 1/2] add initial terraform implementation --- infrastructure/aws/lambda.tf | 107 +++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 infrastructure/aws/lambda.tf diff --git a/infrastructure/aws/lambda.tf b/infrastructure/aws/lambda.tf new file mode 100644 index 0000000..165db41 --- /dev/null +++ b/infrastructure/aws/lambda.tf @@ -0,0 +1,107 @@ +# IAM role for Lambda functions +resource "aws_iam_role" "lambda_role" { + name = "branch-lambda-role" + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { Service = "lambda.amazonaws.com" } + }] + }) +} + +# Attach basic execution policy for CloudWatch Logs +resource "aws_iam_role_policy_attachment" "lambda_basic" { + role = "aws_iam_role.lambda_role.name" + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" +} + +# Get AWS account ID for unique bucket naming +data "aws_caller_identity" "current" {} + +resource "aws_s3_bucket" "lambda_deployments" { + bucket = "branch-lambda-deployments-${data.aws_caller_identity.current.account_id}" +} + +resource "aws_s3_bucket_versioning" "lambda_deployments" { + bucket = aws_s3_bucket.lambda_deployments.id + + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "lambda_deployments" { + bucket = aws_s3_bucket.lambda_deployments.id + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +# Define all Lambda functions in one place +locals { + lambda_functions = toset([ + "projects", + "reports", + "users", + "donors", + "expenditures" + ]) +} + +# Minimal placeholder that will be replaced by GitHub Actions on first deployment +data "archive_file" "lambda_placeholder" { + type = "zip" + output_path = "$${path.module}/lambda-placeholder.zip" + source { + content = "exports.handler = async () => ({ statusCode: 200, body: JSON.stringify({ message: 'Placeholder - will be replaced by CI/CD' }) });" + filename = "handler.js" + } +} + +# This allows Terraform to create the Lambda functions initially +resource "aws_s3_object" "lambda_placeholder" { + for_each = local.lambda_functions + + bucket = aws_s3_bucket.lambda_deployments.id + key = "${each.key}/initial.zip" + source = data.archive_file.lambda_placeholder.output_path + + content_type = "application/zip" +} + +# Create all Lambda functions with a single resource block +resource "aws_lambda_function" "functions" { + for_each = local.lambda_functions + + function_name = "branch-${each.key}" + runtime = "nodejs20.x" + handler = "handler.handler" + timeout = 30 + memory_size = 256 + role = aws_iam_role.lambda_role.arn + + # Use S3 for deployment (initial placeholder, replaced by GitHub Actions) + s3_bucket = aws_s3_bucket.lambda_deployments.id + s3_key = aws_s3_object.lambda_placeholder[each.key].key + + # Prevent Terraform from reverting code deployments made by GitHub Actions + lifecycle { + ignore_changes = [s3_key] + } + + environment { + variables = { + NODE_ENV = "production" + DB_HOST = aws_db_instance.branch_rds.address + DB_USER = data.infisical_secrets.rds_folder.secrets["username"].value + DB_PASSWORD = data.infisical_secrets.rds_folder.secrets["password"].value + DB_PORT = try(data.infisical_secrets.rds_folder.secrets["db_port"].value, "5432") + DB_NAME = try(data.infisical_secrets.rds_folder.secrets["db_name"].value, aws_db_instance.branch_rds.db_name) + } + } +} \ No newline at end of file From f4df4edb4e3b6e4e3a7b742cc0c859d14ae9855b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 22 Mar 2026 03:05:44 +0000 Subject: [PATCH 2/2] chore: auto-format terraform and update documentation - Auto-formatted .tf files with terraform fmt - Updated README.md with terraform-docs Co-authored-by: Rayna-Yu --- infrastructure/aws/README.md | 15 +++++++++++++-- infrastructure/aws/lambda.tf | 20 ++++++++++---------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/infrastructure/aws/README.md b/infrastructure/aws/README.md index c52d8c9..c011548 100644 --- a/infrastructure/aws/README.md +++ b/infrastructure/aws/README.md @@ -11,6 +11,7 @@ | Name | Version | |------|---------| +| [archive](#provider\_archive) | n/a | | [aws](#provider\_aws) | 6.14.1 | | [infisical](#provider\_infisical) | n/a | @@ -25,7 +26,18 @@ No modules. | [aws_cognito_user_pool.branch_user_pool](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/resources/cognito_user_pool) | resource | | [aws_cognito_user_pool_client.branch_client](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/resources/cognito_user_pool_client) | resource | | [aws_db_instance.branch_rds](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/resources/db_instance) | resource | +| [aws_iam_role.lambda_role](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/resources/iam_role) | resource | +| [aws_iam_role_policy_attachment.lambda_basic](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/resources/iam_role_policy_attachment) | resource | +| [aws_lambda_function.functions](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/resources/lambda_function) | resource | +| [aws_s3_bucket.lambda_deployments](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/resources/s3_bucket) | resource | | [aws_s3_bucket.reports_bucket](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/resources/s3_bucket) | resource | +| [aws_s3_bucket_policy.reports_bucket_policy](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/resources/s3_bucket_policy) | resource | +| [aws_s3_bucket_public_access_block.reports_bucket_public_access](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/resources/s3_bucket_public_access_block) | resource | +| [aws_s3_bucket_server_side_encryption_configuration.lambda_deployments](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/resources/s3_bucket_server_side_encryption_configuration) | resource | +| [aws_s3_bucket_versioning.lambda_deployments](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/resources/s3_bucket_versioning) | resource | +| [aws_s3_object.lambda_placeholder](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/resources/s3_object) | resource | +| [archive_file.lambda_placeholder](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/6.14.1/docs/data-sources/caller_identity) | data source | | [infisical_secrets.rds_folder](https://registry.terraform.io/providers/infisical/infisical/latest/docs/data-sources/secrets) | data source | ## Inputs @@ -40,9 +52,8 @@ No modules. | Name | Description | |------|-------------| -| [cognito\_client\_id](#output\_cognito\_client\_id) | Cognito User Pool Client ID | | [cognito\_region](#output\_cognito\_region) | AWS Region for Cognito | | [cognito\_user\_pool\_arn](#output\_cognito\_user\_pool\_arn) | Cognito User Pool ARN | | [cognito\_user\_pool\_endpoint](#output\_cognito\_user\_pool\_endpoint) | Cognito User Pool Endpoint | -| [cognito\_user\_pool\_id](#output\_cognito\_user\_pool\_id) | Cognito User Pool ID | +| [reports\_bucket\_name](#output\_reports\_bucket\_name) | Name of the S3 bucket for generated reports | diff --git a/infrastructure/aws/lambda.tf b/infrastructure/aws/lambda.tf index 165db41..2453f6e 100644 --- a/infrastructure/aws/lambda.tf +++ b/infrastructure/aws/lambda.tf @@ -4,8 +4,8 @@ resource "aws_iam_role" "lambda_role" { assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ - Action = "sts:AssumeRole" - Effect = "Allow" + Action = "sts:AssumeRole" + Effect = "Allow" Principal = { Service = "lambda.amazonaws.com" } }] }) @@ -26,7 +26,7 @@ resource "aws_s3_bucket" "lambda_deployments" { resource "aws_s3_bucket_versioning" "lambda_deployments" { bucket = aws_s3_bucket.lambda_deployments.id - + versioning_configuration { status = "Enabled" } @@ -46,7 +46,7 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "lambda_deployment locals { lambda_functions = toset([ "projects", - "reports", + "reports", "users", "donors", "expenditures" @@ -66,34 +66,34 @@ data "archive_file" "lambda_placeholder" { # This allows Terraform to create the Lambda functions initially resource "aws_s3_object" "lambda_placeholder" { for_each = local.lambda_functions - + bucket = aws_s3_bucket.lambda_deployments.id key = "${each.key}/initial.zip" source = data.archive_file.lambda_placeholder.output_path - + content_type = "application/zip" } # Create all Lambda functions with a single resource block resource "aws_lambda_function" "functions" { for_each = local.lambda_functions - + function_name = "branch-${each.key}" runtime = "nodejs20.x" handler = "handler.handler" timeout = 30 memory_size = 256 role = aws_iam_role.lambda_role.arn - + # Use S3 for deployment (initial placeholder, replaced by GitHub Actions) s3_bucket = aws_s3_bucket.lambda_deployments.id s3_key = aws_s3_object.lambda_placeholder[each.key].key - + # Prevent Terraform from reverting code deployments made by GitHub Actions lifecycle { ignore_changes = [s3_key] } - + environment { variables = { NODE_ENV = "production"