Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions .github/workflows/terraform.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
name: Terraform CI/CD

on:
push:
branches: [ main, develop ]
paths:
- 'environments/**'
- 'modules/**'
- '.github/workflows/terraform.yml'
Comment on lines +6 to +9
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description mentions environments/prod/ and modules/, but neither directory is present in the repo (empty directories aren’t tracked by git). If you want these to exist as scaffolding, add a placeholder file like .gitkeep/README, or adjust the workflow/description accordingly.

Copilot uses AI. Check for mistakes.
pull_request:
branches: [ main ]
paths:
- 'environments/**'
- 'modules/**'
- '.github/workflows/terraform.yml'
workflow_dispatch:

jobs:
terraform-validate:
name: Validate Terraform
runs-on: ubuntu-latest

permissions:
contents: read

strategy:
matrix:
environment: [dev, prod]
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validate job matrix includes prod, but this repo currently only has environments/dev/ (no environments/prod/). This will cause the workflow to fail when it sets working-directory: environments/prod. Either add a minimal environments/prod Terraform config (even a placeholder) or remove prod from the matrix until it exists.

Suggested change
environment: [dev, prod]
environment: [dev]

Copilot uses AI. Check for mistakes.

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.6.0

- name: Terraform Format Check
run: terraform fmt -check -recursive
continue-on-error: true
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

terraform fmt -check is configured with continue-on-error: true, which allows unformatted Terraform code to pass CI even though the job is labeled as a format check. If formatting is meant to be enforced, remove continue-on-error so the workflow fails on fmt differences.

Suggested change
continue-on-error: true

Copilot uses AI. Check for mistakes.

- name: Terraform Init
working-directory: environments/${{ matrix.environment }}
run: terraform init -backend=false

- name: Terraform Validate
working-directory: environments/${{ matrix.environment }}
run: terraform validate

terraform-plan:
name: Plan Terraform Changes
runs-on: ubuntu-latest
needs: terraform-validate
if: github.event_name == 'pull_request'

permissions:
contents: read
pull-requests: write

strategy:
matrix:
environment: [dev]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.6.0

- name: Terraform Init
working-directory: environments/${{ matrix.environment }}
run: terraform init -backend=false

- name: Terraform Plan
working-directory: environments/${{ matrix.environment }}
run: terraform plan -no-color
Comment on lines +69 to +80
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plan step runs terraform plan without any AWS credentials setup in the workflow. With the AWS provider configured, plan will typically fail on CI (provider credential validation / refresh). Add an explicit AWS auth step (e.g., OIDC via aws-actions/configure-aws-credentials + permissions: id-token: write, or repository secrets) before running init/plan.

Copilot uses AI. Check for mistakes.

terraform-apply:
name: Apply Terraform Changes
runs-on: ubuntu-latest
needs: terraform-validate
if: github.event_name == 'push' && github.ref == 'refs/heads/main'

permissions:
contents: read

strategy:
matrix:
environment: [dev]
max-parallel: 1

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.6.0

- name: Terraform Init
working-directory: environments/${{ matrix.environment }}
run: terraform init -backend=false
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

terraform init -backend=false is used in the apply job. That explicitly disables the S3 backend in backend.tf, so terraform apply will use local state on the runner (no remote state, no locking) and will drift/break future runs. The apply job should run a normal terraform init configured for the remote backend.

Suggested change
run: terraform init -backend=false
run: terraform init

Copilot uses AI. Check for mistakes.

- name: Terraform Apply
working-directory: environments/${{ matrix.environment }}
run: terraform apply -auto-approve
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,17 @@ solana/
**/.env*

solana/

# Terraform
**/.terraform/
**/.terraform.lock.hcl
**/terraform.tfstate
**/terraform.tfstate.backup
**/*.tfvars
**/*.tfvars.json
**/override.tf
**/override.tf.json
**/*_override.tf
**/*_override.tf.json
.terraformrc
terraform.rc
9 changes: 9 additions & 0 deletions environments/dev/backend.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "dev/terraform.tfstate"
region = "eu-central-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
Comment on lines +2 to +8
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The backend config hard-codes the S3 bucket and DynamoDB table names (my-terraform-state, terraform-locks). As-is, terraform init will fail in any AWS account where these resources haven't been pre-created and can’t be varied per environment/account. Consider using partial backend configuration and supplying bucket/table via -backend-config (e.g., from CI secrets/vars), or adding a documented/bootstrap step/module to create the state bucket + lock table.

Copilot uses AI. Check for mistakes.
}
73 changes: 73 additions & 0 deletions environments/dev/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
terraform {
required_version = ">= 1.6.0"

required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}

provider "aws" {
region = var.aws_region

default_tags {
tags = {
Environment = "dev"
Project = "SolVoid"
ManagedBy = "Terraform"
}
}
Comment on lines +15 to +21
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The environment and project_name variables exist, but tags and resource names are still hard-coded to dev / SolVoid in multiple places. This reduces portability across environments and makes the environment variable unused for naming/tagging. Use var.environment and var.project_name consistently for default_tags and Name suffixes.

Copilot uses AI. Check for mistakes.
}

# Example resource - VPC
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true

tags = {
Name = "${var.project_name}-vpc-dev"
}
}
Comment on lines +30 to +33
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resource Name tags hard-code -dev (e.g., ${var.project_name}-vpc-dev, ${var.project_name}-igw-dev). Since an environment variable is defined, consider using it in these names so the same config pattern can be reused for other environments without duplicated edits.

Copilot uses AI. Check for mistakes.

# Example resource - Subnet
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_cidr
map_public_ip_on_launch = true

tags = {
Name = "${var.project_name}-public-subnet-dev"
}
}

# Example resource - Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id

tags = {
Name = "${var.project_name}-igw-dev"
}
}

# Example resource - Route Table
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id

route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}

tags = {
Name = "${var.project_name}-public-rt-dev"
}
}

# Example resource - Route Table Association
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
29 changes: 29 additions & 0 deletions environments/dev/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
variable "aws_region" {
description = "AWS region for infrastructure deployment"
type = string
default = "us-east-1"
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aws_region defaults to us-east-1, but the S3 backend in backend.tf is hard-coded to eu-central-1. This mismatch is likely to confuse users and can break init if the state bucket actually lives in a different region than expected. Consider aligning the default region with the backend region (or documenting the intended separation clearly).

Suggested change
default = "us-east-1"
default = "eu-central-1"

Copilot uses AI. Check for mistakes.
}

variable "project_name" {
description = "Project name for resource naming"
type = string
default = "solvoid"
}

variable "vpc_cidr" {
description = "CIDR block for VPC"
type = string
default = "10.0.0.0/16"
}

variable "public_subnet_cidr" {
description = "CIDR block for public subnet"
type = string
default = "10.0.1.0/24"
}

variable "environment" {
description = "Environment name"
type = string
default = "dev"
}
Loading