Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
5 changes: 5 additions & 0 deletions .github/workflows/plan-nonprod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ jobs:
with:
role-to-assume: ${{ vars.NONPROD_OIDC_ROLE_ARN }}
aws-region: ${{ vars.AWS_REGION }}
- uses: google-github-actions/auth@v3
with:
project_id: ${{ vars.GCP_PROJECT_ID }}
workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ vars.GCP_SERVICE_ACCOUNT }}
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/plan-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ jobs:
with:
role-to-assume: ${{ vars.PROD_OIDC_ROLE_ARN }}
aws-region: ${{ vars.AWS_REGION }}
- uses: google-github-actions/auth@v3
with:
project_id: ${{ vars.GCP_PROJECT_ID }}
workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ vars.GCP_SERVICE_ACCOUNT }}
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/plan-root.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ jobs:
with:
role-to-assume: ${{ vars.ROOT_OIDC_ROLE_ARN }}
aws-region: ${{ vars.AWS_REGION }}
- uses: google-github-actions/auth@v3
with:
project_id: ${{ vars.GCP_PROJECT_ID }}
workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ vars.GCP_SERVICE_ACCOUNT }}
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/plan-sandbox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ jobs:
with:
role-to-assume: ${{ vars.SANDBOX_OIDC_ROLE_ARN }}
aws-region: ${{ vars.AWS_REGION }}
- uses: google-github-actions/auth@v3
with:
project_id: ${{ vars.GCP_PROJECT_ID }}
workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ vars.GCP_SERVICE_ACCOUNT }}
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
Expand Down
18 changes: 18 additions & 0 deletions modules/gcp/api/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
terraform {
required_version = ">= 1.14.0"
required_providers {
google = {
source = "hashicorp/google"
version = ">= 7.26.0"
}
}
}

resource "google_project_service" "enabled_apis" {
for_each = toset(var.gcp_service_list)

project = var.gcp_project_id
service = each.key

disable_on_destroy = false
}
4 changes: 4 additions & 0 deletions modules/gcp/api/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output "enabled_services" {
value = [for s in google_project_service.enabled_apis : s.service]
description = "The list of services that were enabled"
}
10 changes: 10 additions & 0 deletions modules/gcp/api/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
variable "gcp_project_id" {
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

The input variable is named gcp_project_id, but the other GCP modules in this repo use project_id (e.g., modules/gcp/firestore/variables.tf:1, modules/gcp/budget/variables.tf:1). For a consistent module API and less glue code in callers, consider renaming this to project_id.

Suggested change
variable "gcp_project_id" {
variable "project_id" {

Copilot uses AI. Check for mistakes.
description = "The ID of the project where APIs will be enabled"
type = string
}

variable "gcp_service_list" {
description = "The list of APIs to enable"
type = list(string)
default = []
}
51 changes: 51 additions & 0 deletions modules/gcp/budget/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
data "google_billing_account" "account" {
display_name = var.billing_account_name
open = true
}
Comment on lines +1 to +4
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

New modules in this repo consistently declare a terraform block with required_version and required_providers (see modules/aws/vpc/main.tf:1-9 and modules/gcp/api/main.tf:1-9). This module currently omits it; adding it would keep provider/version constraints explicit and aligned with the rest of the codebase.

Copilot uses AI. Check for mistakes.

resource "google_monitoring_notification_channel" "email_devops" {
project = var.project_id
display_name = "Budget Alert Email"
type = "email"

labels = {
email_address = var.billing_notification_email
}
}

resource "google_billing_budget" "monthly_limit" {
billing_account = data.google_billing_account.account.id
display_name = var.budget_name

budget_filter {
projects = ["projects/${var.project_id}"]
}

amount {
specified_amount {
currency_code = "USD"
units = tostring(var.limit_amount_usd)
}
}

threshold_rules {
threshold_percent = 0.5
}

threshold_rules {
threshold_percent = 0.9
}

threshold_rules {
threshold_percent = 1.0
spend_basis = "FORECASTED_SPEND"
}

all_updates_rule {
monitoring_notification_channels = [
google_monitoring_notification_channel.email_devops.id
]

disable_default_iam_recipients = false
}
}
9 changes: 9 additions & 0 deletions modules/gcp/budget/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "budget_name" {
description = "Name of the GCP budget."
value = google_billing_budget.monthly_limit.display_name
}

output "budget_id" {
description = "The GCP budget resource name."
value = google_billing_budget.monthly_limit.name
}
33 changes: 33 additions & 0 deletions modules/gcp/budget/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
variable "project_id" {
description = "The GCP project ID for the budget."
type = string
}

variable "billing_account_name" {
description = "Name of the GCP billing account to create the budget under."
type = string
default = "durianpy-cms"
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

Using data.google_billing_account lookup by display_name plus a repo-specific default ("durianpy-cms") makes the module brittle: display names aren’t guaranteed unique/stable and the default may not match the actual billing account display name in other environments. Prefer taking a billing_account_id (or billing_account resource name) as an explicit required input, or at least remove the default so misconfiguration fails fast.

Suggested change
default = "durianpy-cms"

Copilot uses AI. Check for mistakes.
}

variable "budget_name" {
description = "Name of the GCP budget."
type = string
default = "Monthly Budget"
}

variable "limit_amount_usd" {
description = "Monthly spend limit in USD for the GCP account budget."
type = number
default = 100

validation {
condition = var.limit_amount_usd > 0 && floor(var.limit_amount_usd) == var.limit_amount_usd
error_message = "limit_amount_usd must be a positive whole number."
}
}

variable "billing_notification_email" {
description = "Email address for GCP account cost alerts."
type = string
default = "durianpy.davao+devops@gmail.com"
}
20 changes: 20 additions & 0 deletions modules/gcp/firestore/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
resource "google_project_service" "firestore" {
project = var.project_id
service = var.api_service_name
Comment on lines +1 to +3
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

New modules in this repo consistently declare a terraform block with required_version and required_providers (e.g., modules/aws/budget/main.tf:1-9, modules/gcp/api/main.tf:1-9). Adding the same here would keep provider constraints explicit and consistent across modules.

Copilot uses AI. Check for mistakes.
disable_on_destroy = false
}
Comment on lines +1 to +5
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

This module unconditionally creates a google_project_service for Firestore. When the caller also enables firestore.googleapis.com elsewhere (e.g., via a shared “enable APIs” module), Terraform ends up with two resources managing the same remote service and applies can fail. Consider adding a flag to disable API enabling here (or accept an existing service resource via dependency) so callers can avoid duplicate ownership.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback You may delete this line

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Implemented in 58be412. I removed firestore.googleapis.com from module.gcp_project_apis in workspaces/prod/main.tf, so Firestore API enablement is owned only by the Firestore module and no longer conflicts.

No UI changes were made (Terraform-only change), so there is no UI screenshot to attach.


resource "google_firestore_database" "this" {
project = var.project_id
name = var.database_name
location_id = var.region
type = var.database_type
concurrency_mode = var.concurrency_mode
app_engine_integration_mode = var.app_engine_integration_mode
database_edition = var.database_edition

mongodb_compatible_data_access_mode = var.mongodb_compatible_data_access_mode
delete_protection_state = var.delete_protection_state

depends_on = [google_project_service.firestore]
}
9 changes: 9 additions & 0 deletions modules/gcp/firestore/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "firestore_db_id" {
description = "The Firestore database resource name."
value = google_firestore_database.this.name
}

output "firestore_db_project" {
description = "The project that owns the Firestore database."
value = google_firestore_database.this.project
}
57 changes: 57 additions & 0 deletions modules/gcp/firestore/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
variable "project_id" {
description = "The GCP project ID where Firestore will be created."
type = string
}

variable "region" {
description = "The Firestore location ID."
type = string
}

variable "database_name" {
description = "The Firestore database name."
type = string
default = "payloadcms-poc-db"
}

variable "api_service_name" {
description = "The Google API service to enable before creating Firestore."
type = string
default = "firestore.googleapis.com"
}

variable "database_type" {
description = "The Firestore database type."
type = string
default = "FIRESTORE_NATIVE"
}

variable "concurrency_mode" {
description = "The Firestore concurrency mode."
type = string
default = "OPTIMISTIC"
}

variable "app_engine_integration_mode" {
description = "The App Engine integration mode for Firestore."
type = string
default = "DISABLED"
}

variable "database_edition" {
description = "The Firestore database edition."
type = string
default = "ENTERPRISE"
}

variable "mongodb_compatible_data_access_mode" {
description = "MongoDB-compatible data access mode for Firestore."
type = string
default = "DATA_ACCESS_MODE_ENABLED"
}

variable "delete_protection_state" {
description = "Delete protection state for the Firestore database."
type = string
default = "DELETE_PROTECTION_DISABLED"
}
7 changes: 5 additions & 2 deletions workspaces/prod/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions workspaces/prod/backend.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ terraform {
}
google = {
source = "hashicorp/google"
version = ">= 6.0"
version = ">= 7.26.0"
}
google-beta = {
source = "hashicorp/google-beta"
version = ">= 6.0"
version = ">= 7.26.0"
}
Comment on lines 9 to 16
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

google-beta remains listed in required_providers, but this workspace no longer configures/uses the google-beta provider (the only references are in commented-out code). If it’s no longer needed, remove it from required_providers to avoid extra provider downloads/lockfile churn; if it is needed, re-add the provider configuration block in providers.tf.

Copilot uses AI. Check for mistakes.
}

Expand Down
34 changes: 34 additions & 0 deletions workspaces/prod/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,37 @@ module "vpc" {
"10.20.80.0/20",
]
}

module "gcp_project_apis" {
source = "../../modules/gcp/api"
gcp_project_id = var.gcp_project_id

gcp_service_list = [
"billingbudgets.googleapis.com",
"monitoring.googleapis.com",
"iam.googleapis.com",
"serviceusage.googleapis.com",
"cloudresourcemanager.googleapis.com",
"firestore.googleapis.com"
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

firestore.googleapis.com is enabled here via module.gcp_project_apis, but the Firestore module also manages the same API with its own google_project_service resource. Managing the same project service from two Terraform resources will typically fail with “already managed”/conflict errors; pick a single place to enable this API (e.g., remove it from this list or make the Firestore module’s API-enabling optional).

Suggested change
"cloudresourcemanager.googleapis.com",
"firestore.googleapis.com"
"cloudresourcemanager.googleapis.com"

Copilot uses AI. Check for mistakes.
]
}

module "gcp_budget" {
source = "../../modules/gcp/budget"

project_id = var.gcp_project_id
budget_name = "Durianpy Prod GCP Budget"
limit_amount_usd = var.gcp_budget_limit_usd
billing_notification_email = var.budget_notification_email

depends_on = [module.gcp_project_apis]
}

module "gcp_firestore" {
source = "../../modules/gcp/firestore"

project_id = var.gcp_project_id
region = var.gcp_region

depends_on = [module.gcp_project_apis]
}
20 changes: 20 additions & 0 deletions workspaces/prod/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@
# value = module.gcp_prod.enabled_apis
# }

output "gcp_project_id" {
description = "GCP project ID for production."
value = var.gcp_project_id
}

output "gcp_enabled_apis" {
description = "APIs enabled in the prod GCP project."
value = module.gcp_project_apis.enabled_services
}

output "gcp_budget_name" {
description = "Name of the prod GCP budget."
value = module.gcp_budget.budget_name
}

output "gcp_firestore_db_id" {
description = "ID of the Firestore database in prod."
value = module.gcp_firestore.firestore_db_id
}

output "github_oidc_role_arn" {
description = "ARN of the GitHub Actions OIDC IAM role."
value = module.github_oidc.role_arn
Expand Down
11 changes: 4 additions & 7 deletions workspaces/prod/providers.tf
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ provider "aws" {
}

provider "google" {
project = var.gcp_project_id
region = var.gcp_region
}

provider "google-beta" {
project = var.gcp_project_id
region = var.gcp_region
region = var.gcp_region
project = var.gcp_project_id
user_project_override = true
billing_project = var.gcp_project_id
}
Loading
Loading