Skip to content

Conversation

@TonsOfFun
Copy link
Contributor

Can you deploy this for free on my GCP? Maybe using terraform?


Superconductor Ticket Implementation

- Create Terraform manifests for Cloud Run, Artifact Registry, and Secret Manager
- Add a deployment script to automate infrastructure provisioning and image builds
- Configure Cloud Run for free-tier eligibility (scale-to-zero, idle CPU)
- Update Dockerfile and ignore files for production compatibility
- Support Rails master key management via GCP Secret Manager

Co-authored-by: Claude Code <noreply@anthropic.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds Terraform + a helper deploy script to provision GCP resources (Artifact Registry, Secret Manager, Cloud Run) and deploy the Rails app to Cloud Run.

Changes:

  • Introduces Terraform configuration (variables, main resources, outputs) for Cloud Run deployment.
  • Adds an example terraform.tfvars and a deploy.sh script to provision infra, build/push a Docker image, and update Cloud Run.
  • Updates repo ignores for Terraform artifacts and adds a .dockerignore.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
terraform/variables.tf Defines Terraform inputs for GCP project/region, app name, Rails master key, optional domain.
terraform/terraform.tfvars.example Example values for required Terraform variables.
terraform/outputs.tf Exposes Cloud Run service URL and Artifact Registry image/repo strings.
terraform/main.tf Provisions APIs, Artifact Registry, Secret Manager secret, Cloud Run service + IAM, optional domain mapping.
terraform/deploy.sh Automates terraform apply, Docker build/push, and a gcloud run service update.
Dockerfile Switches Ruby base image reference to docker.io/....
.gitignore Ignores Terraform local state/vars and related files.
.dockerignore Excludes infra/CI/dev/test/docs artifacts from Docker build context.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

image = "${var.region}-docker.pkg.dev/${var.project_id}/${var.app_name}/${var.app_name}:latest"

ports {
container_port = 80
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

Cloud Run container is configured to use port 80, but the Docker image runs as a non-root user (UID 1000). Binding to privileged ports (<1024) will fail at runtime, so the service likely won’t start. Use an unprivileged port (typically 8080) and let the app read PORT (already in config/puma.rb).

Suggested change
container_port = 80
container_port = 8080

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +55
resource "google_secret_manager_secret_version" "rails_master_key" {
secret = google_secret_manager_secret.rails_master_key.id
secret_data = var.rails_master_key
}
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

google_secret_manager_secret_version.secret_data will store the Rails master key value in the Terraform state file in plaintext (even if the input variable is marked sensitive). This is a significant secret-leak risk for anyone with access to state (local disk, CI artifacts, remote backend). Prefer creating the Secret in Terraform but adding versions outside Terraform (e.g., gcloud secrets versions add), or use a secured/encrypted remote backend with strict access controls and avoid committing/retaining local state.

Suggested change
resource "google_secret_manager_secret_version" "rails_master_key" {
secret = google_secret_manager_secret.rails_master_key.id
secret_data = var.rails_master_key
}
# NOTE: Secret versions (actual Rails master key values) should be
# created outside Terraform (e.g., via `gcloud secrets versions add`)
# to avoid storing secret data in Terraform state.

Copilot uses AI. Check for mistakes.
Comment on lines +155 to +161
resource "google_cloud_run_v2_service_iam_member" "public" {
project = google_cloud_run_v2_service.app.project
location = google_cloud_run_v2_service.app.location
name = google_cloud_run_v2_service.app.name
role = "roles/run.invoker"
member = "allUsers"
}
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

This unconditionally makes the Cloud Run service publicly invokable by allUsers. If this app is not intended to be fully public, this should be gated behind a variable (e.g., public_access = true/false) or use a more restrictive principal, otherwise it’s easy to accidentally expose internal environments.

Copilot uses AI. Check for mistakes.
Comment on lines +65 to +72
# Step 5: Deploy to Cloud Run (update the service to use the new image)
echo ""
echo "==> Step 5: Deploying new image to Cloud Run..."
gcloud run services update "$APP_NAME" \
--region "$REGION" \
--image "$DOCKER_TAG" \
--project "$PROJECT_ID" \
--quiet
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

The deploy script updates the Cloud Run service with gcloud run services update after Terraform creates it. This will cause configuration drift from Terraform state and makes future terraform apply runs potentially revert or conflict with the deployed image. Consider making the image tag a Terraform variable and updating it via Terraform, or add a Terraform lifecycle { ignore_changes = [template[0].containers[0].image] } if gcloud is intended to own image updates.

Copilot uses AI. Check for mistakes.
Comment on lines +26 to +30
# Parse project_id and region from tfvars
PROJECT_ID=$(grep 'project_id' "$SCRIPT_DIR/terraform.tfvars" | sed 's/.*= *"\(.*\)"/\1/')
REGION=$(grep 'region' "$SCRIPT_DIR/terraform.tfvars" | sed 's/.*= *"\(.*\)"/\1/')
APP_NAME=$(grep 'app_name' "$SCRIPT_DIR/terraform.tfvars" | sed 's/.*= *"\(.*\)"/\1/' || echo "dill")

Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

Parsing terraform.tfvars with grep/sed is brittle (e.g., it will break if values are unquoted, if there are multiple matching keys, or if a commented line matches). Consider using terraform output -raw (after apply) or terraform console to read values reliably, or enforce/validate the expected tfvars format before continuing.

Suggested change
# Parse project_id and region from tfvars
PROJECT_ID=$(grep 'project_id' "$SCRIPT_DIR/terraform.tfvars" | sed 's/.*= *"\(.*\)"/\1/')
REGION=$(grep 'region' "$SCRIPT_DIR/terraform.tfvars" | sed 's/.*= *"\(.*\)"/\1/')
APP_NAME=$(grep 'app_name' "$SCRIPT_DIR/terraform.tfvars" | sed 's/.*= *"\(.*\)"/\1/' || echo "dill")
# Initialize Terraform and read variables using terraform console to avoid brittle parsing
(
cd "$SCRIPT_DIR"
terraform init -input=false >/dev/null
)
PROJECT_ID=$(cd "$SCRIPT_DIR" && terraform console -input=false -var-file="terraform.tfvars" -execute='var.project_id' | tr -d '\r')
REGION=$(cd "$SCRIPT_DIR" && terraform console -input=false -var-file="terraform.tfvars" -execute='var.region' | tr -d '\r')
APP_NAME=$(cd "$SCRIPT_DIR" && terraform console -input=false -var-file="terraform.tfvars" -execute='try(var.app_name, "dill")' | tr -d '\r' || echo "dill")

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant