From 50eb3128676781b4794582bcc3f0da14dd4c20e9 Mon Sep 17 00:00:00 2001 From: Marina Kim Date: Sun, 1 Mar 2026 11:12:45 +0000 Subject: [PATCH 1/4] adds terraform and github pipeline --- .github/workflows/github-pipeline.yml | 59 +++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .github/workflows/github-pipeline.yml diff --git a/.github/workflows/github-pipeline.yml b/.github/workflows/github-pipeline.yml new file mode 100644 index 0000000..01eed33 --- /dev/null +++ b/.github/workflows/github-pipeline.yml @@ -0,0 +1,59 @@ +name: Deploy Frontend + +on: + push: + branches: + - develop + - main + +jobs: + deploy: + runs-on: ubuntu-latest + + strategy: + matrix: + include: + - branch: develop + environment: dev + bucket: catbytes-frontend-app-dev + distribution: E3R0HUJOSQPR1E + build_mode: development + - branch: main + environment: prod + bucket: catbytes-frontend-app-prod + distribution: PROD_DISTRIBUTION_ID_HERE + build_mode: production + + if: github.ref_name == matrix.branch + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install dependencies + run: npm ci + + - name: Build Vite app + run: npm run build -- --mode ${{ matrix.build_mode }} + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Upload to S3 + run: | + aws s3 sync dist/ s3://${{ matrix.bucket }} --delete + + - name: Invalidate CloudFront + run: | + aws cloudfront create-invalidation \ + --distribution-id ${{ matrix.distribution }} \ + --paths "/*" \ No newline at end of file From e3461e02b3dfc015a41fa1cf8fdfead37a66d9be Mon Sep 17 00:00:00 2001 From: Marina Kim Date: Sun, 1 Mar 2026 11:13:40 +0000 Subject: [PATCH 2/4] adds terraform and pipeline --- .gitignore | 15 ++++- infrastructure/dev/main.tf | 115 ++++++++++++++++++++++++++++++++ infrastructure/dev/outputs.tf | 3 + infrastructure/dev/providers.tf | 10 +++ infrastructure/dev/variables.tf | 0 5 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 infrastructure/dev/main.tf create mode 100644 infrastructure/dev/outputs.tf create mode 100644 infrastructure/dev/providers.tf create mode 100644 infrastructure/dev/variables.tf diff --git a/.gitignore b/.gitignore index d01aba1..8f685bf 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ dist-ssr *.local *.env .env +.env.* .vite/ @@ -27,4 +28,16 @@ dist-ssr *.sln *.sw? .vite -*.tsbuildinfo \ No newline at end of file +*.tsbuildinfo + +# Terraform +**/.terraform/* +**/.terraform.lock.hcl +**/terraform.tfstate +**/terraform.tfstate.* +**/.terraform.tfstate.lock.info +**/crash.log + +# Sensitive variables +**/terraform.tfvars +**/*.auto.tfvars \ No newline at end of file diff --git a/infrastructure/dev/main.tf b/infrastructure/dev/main.tf new file mode 100644 index 0000000..06f3c5f --- /dev/null +++ b/infrastructure/dev/main.tf @@ -0,0 +1,115 @@ +resource "aws_s3_bucket" "frontend" { + bucket = "catbytes-frontend-app-dev" + + tags = { + Environment = "dev" + Project = "catbytes" + } +} + +resource "aws_s3_bucket_public_access_block" "frontend" { + bucket = aws_s3_bucket.frontend.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_s3_bucket_versioning" "frontend" { + bucket = aws_s3_bucket.frontend.id + + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "frontend" { + bucket = aws_s3_bucket.frontend.id + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +resource "aws_cloudfront_origin_access_control" "frontend" { + name = "catbytes-dev-oac" + description = "OAC for dev frontend" + origin_access_control_origin_type = "s3" + signing_behavior = "always" + signing_protocol = "sigv4" +} + +resource "aws_cloudfront_distribution" "frontend" { + aliases = ["app.dev.catbytes.io"] + enabled = true + default_root_object = "index.html" + + origin { + domain_name = aws_s3_bucket.frontend.bucket_regional_domain_name + origin_id = "s3-frontend" + origin_access_control_id = aws_cloudfront_origin_access_control.frontend.id + } + + default_cache_behavior { + target_origin_id = "s3-frontend" + viewer_protocol_policy = "redirect-to-https" + + allowed_methods = ["GET", "HEAD"] + cached_methods = ["GET", "HEAD"] + + forwarded_values { + query_string = false + cookies { + forward = "none" + } + } + } + + restrictions { + geo_restriction { + restriction_type = "none" + } + } + + viewer_certificate { + acm_certificate_arn = aws_acm_certificate.dev_cert.arn + ssl_support_method = "sni-only" + minimum_protocol_version = "TLSv1.2_2021" + } +} + +resource "aws_s3_bucket_policy" "frontend" { + bucket = aws_s3_bucket.frontend.id + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "cloudfront.amazonaws.com" + } + Action = "s3:GetObject" + Resource = "${aws_s3_bucket.frontend.arn}/*" + Condition = { + StringEquals = { + "AWS:SourceArn" = aws_cloudfront_distribution.frontend.arn + } + } + } + ] + }) +} + +resource "aws_acm_certificate" "dev_cert" { + provider = aws.us_east_1 + domain_name = "app.dev.catbytes.io" + validation_method = "DNS" + + lifecycle { + create_before_destroy = true + } +} \ No newline at end of file diff --git a/infrastructure/dev/outputs.tf b/infrastructure/dev/outputs.tf new file mode 100644 index 0000000..327ed8f --- /dev/null +++ b/infrastructure/dev/outputs.tf @@ -0,0 +1,3 @@ +output "cloudfront_domain_name" { + value = aws_cloudfront_distribution.frontend.domain_name +} \ No newline at end of file diff --git a/infrastructure/dev/providers.tf b/infrastructure/dev/providers.tf new file mode 100644 index 0000000..6bcf6b6 --- /dev/null +++ b/infrastructure/dev/providers.tf @@ -0,0 +1,10 @@ +provider "aws" { + region = "eu-west-2" + profile = "terraform-catbytes-dev" +} + +provider "aws" { + alias = "us_east_1" + region = "us-east-1" + profile = "terraform-catbytes-dev" +} \ No newline at end of file diff --git a/infrastructure/dev/variables.tf b/infrastructure/dev/variables.tf new file mode 100644 index 0000000..e69de29 From 067f9776210e563f874858af16f0aeb86267b16d Mon Sep 17 00:00:00 2001 From: Marina Kim Date: Sun, 1 Mar 2026 11:48:50 +0000 Subject: [PATCH 3/4] ads terraform backend file to manage state in S3 and DynamoDB --- infrastructure/dev/backend.tf | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 infrastructure/dev/backend.tf diff --git a/infrastructure/dev/backend.tf b/infrastructure/dev/backend.tf new file mode 100644 index 0000000..c6dcc84 --- /dev/null +++ b/infrastructure/dev/backend.tf @@ -0,0 +1,9 @@ +terraform { + backend "s3" { + bucket = "catbytes-terraform-state-463470984434" + key = "dev/terraform.tfstate" + region = "eu-west-2" + dynamodb_table = "catbytes-terraform-locks" + encrypt = true + } +} \ No newline at end of file From b75b2608cfa06ecc0367d24f95b66b1f81041b9e Mon Sep 17 00:00:00 2001 From: Marina Kim Date: Sun, 19 Apr 2026 08:42:50 +0100 Subject: [PATCH 4/4] updates terraform script --- infrastructure/dev/main.tf | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/infrastructure/dev/main.tf b/infrastructure/dev/main.tf index 06f3c5f..87d6f34 100644 --- a/infrastructure/dev/main.tf +++ b/infrastructure/dev/main.tf @@ -79,6 +79,17 @@ resource "aws_cloudfront_distribution" "frontend" { ssl_support_method = "sni-only" minimum_protocol_version = "TLSv1.2_2021" } + custom_error_response { + error_code = 403 + response_code = 200 + response_page_path = "/index.html" + } + + custom_error_response { + error_code = 404 + response_code = 200 + response_page_path = "/index.html" + } } resource "aws_s3_bucket_policy" "frontend" {