From 034588103fa44972278712c63ef61048b4b4ea3c Mon Sep 17 00:00:00 2001 From: Christine Stirrat Date: Mon, 20 Apr 2026 16:28:16 -0400 Subject: [PATCH 1/4] fix: make terraform state bucket name configurable --- cli/commands/configure.py | 2 +- terraform/aws/main.tf | 2 +- terraform/bootstrap/variables.tf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/commands/configure.py b/cli/commands/configure.py index 7f4c5cb..01daeae 100644 --- a/cli/commands/configure.py +++ b/cli/commands/configure.py @@ -21,7 +21,7 @@ PLUGINS = ["CKAN", "Socrata", "ArcGIS"] # Bucket name must match the `backend "s3"` block in terraform/aws/main.tf. -TERRAFORM_STATE_BUCKET = "opencontext-terraform-state" +TERRAFORM_STATE_BUCKET = "opencontext-terraform-state-govex-dc" def _ensure_state_bucket(bucket_name: str, region: str) -> None: diff --git a/terraform/aws/main.tf b/terraform/aws/main.tf index 7057ec5..8af2d66 100644 --- a/terraform/aws/main.tf +++ b/terraform/aws/main.tf @@ -2,7 +2,7 @@ terraform { required_version = ">= 1.0" backend "s3" { - bucket = "opencontext-terraform-state" + bucket = "opencontext-terraform-state-govex-dc" key = "opencontext/terraform.tfstate" region = "us-east-1" encrypt = true diff --git a/terraform/bootstrap/variables.tf b/terraform/bootstrap/variables.tf index 625c8c2..10c01ba 100644 --- a/terraform/bootstrap/variables.tf +++ b/terraform/bootstrap/variables.tf @@ -7,5 +7,5 @@ variable "aws_region" { variable "state_bucket_name" { description = "Name of the S3 bucket for Terraform state" type = string - default = "opencontext-terraform-state" + default = "opencontext-terraform-state-govex-dc" } From fe06085054c2735797476c15274ae3b8b38236f2 Mon Sep 17 00:00:00 2001 From: Christine Stirrat Date: Mon, 20 Apr 2026 16:32:28 -0400 Subject: [PATCH 2/4] fix: prompt for unique S3 state bucket name in configure wizard --- cli/commands/configure.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/cli/commands/configure.py b/cli/commands/configure.py index 01daeae..0ab7ef6 100644 --- a/cli/commands/configure.py +++ b/cli/commands/configure.py @@ -20,9 +20,6 @@ PLUGINS = ["CKAN", "Socrata", "ArcGIS"] -# Bucket name must match the `backend "s3"` block in terraform/aws/main.tf. -TERRAFORM_STATE_BUCKET = "opencontext-terraform-state-govex-dc" - def _ensure_state_bucket(bucket_name: str, region: str) -> None: """Check that the Terraform S3 state bucket exists; create it if not. @@ -198,19 +195,8 @@ def _write_tfvars( @friendly_exit -def configure( - state_bucket: str = typer.Option( - TERRAFORM_STATE_BUCKET, - "--state-bucket", - help="S3 bucket name for Terraform state (default: opencontext-terraform-state)", - ), -) -> None: +def configure() -> None: """Interactive wizard to configure your OpenContext MCP server.""" - # When called programmatically (e.g. in tests), Typer does not resolve - # Option defaults — guard against receiving the raw OptionInfo sentinel. - if not isinstance(state_bucket, str): - state_bucket = TERRAFORM_STATE_BUCKET - project_root = get_project_root() terraform_dir = get_terraform_dir() @@ -274,6 +260,19 @@ def configure( raise typer.Exit(0) city_slug = city_name.lower().replace(" ", "-") + + # Prompt for a unique S3 bucket name for Terraform state. + # S3 bucket names are globally unique across all AWS accounts, so the + # default includes the org city slug to avoid collisions with other + # deployments of this project. + suggested_bucket = f"opencontext-terraform-state-{city_slug}" + state_bucket = questionary.text( + "S3 bucket name for Terraform state:", + default=suggested_bucket, + ).ask() + if state_bucket is None: + raise typer.Exit(0) + suggested_lambda = f"{city_slug}-opencontext-mcp-{env}" lambda_name = questionary.text( @@ -398,6 +397,7 @@ def configure( summary.add_row("City", city_name) summary.add_row("Environment", env) summary.add_row("Plugin", plugin) + summary.add_row("Terraform state bucket", state_bucket) summary.add_row("Lambda name", lambda_name) summary.add_row("AWS region", region) summary.add_row("Lambda memory", f"{lambda_memory} MB") From 07b6f8314a6469ef725bc18d588162be7a875133 Mon Sep 17 00:00:00 2001 From: Christine Stirrat Date: Mon, 20 Apr 2026 16:34:43 -0400 Subject: [PATCH 3/4] fix: remove terraform validate from pre-deploy checks (chicken-and-egg with lambda zip) --- cli/commands/validate.py | 37 +++++++------------------------------ 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/cli/commands/validate.py b/cli/commands/validate.py index c46075a..98b8552 100644 --- a/cli/commands/validate.py +++ b/cli/commands/validate.py @@ -130,36 +130,13 @@ def run_checks(env: str) -> bool: ".terraform directory found" if tf_initialized else "Run: opencontext configure", )) - # 7. terraform validate - if tf_installed and tf_initialized: - try: - result = subprocess.run( - ["terraform", "validate", "-json"], - cwd=terraform_dir, - capture_output=True, text=True, timeout=30, - ) - if result.returncode == 0: - checks.append(("terraform validate", True, "Configuration valid")) - else: - error_msg = "" - try: - data = json.loads(result.stdout) - error_msg = data.get("error_message", "") - except Exception: - pass - if not error_msg: - error_msg = (result.stderr or result.stdout or "Validation failed").strip() - checks.append(("terraform validate", False, error_msg[:100])) - except (FileNotFoundError, subprocess.TimeoutExpired) as e: - checks.append(("terraform validate", False, str(e)[:80])) - else: - checks.append(( - "terraform validate", - False, - "Skipped — terraform not installed or not initialized", - )) + # Note: terraform validate is intentionally skipped here because it + # references lambda-deployment.zip, which does not exist until the + # packaging step inside `opencontext deploy`. Running validate before + # packaging would always fail. Terraform plan (run inside deploy) catches + # the same configuration errors after the zip has been created. - # 8. AWS credentials valid + # 7. AWS credentials valid try: result = subprocess.run( ["aws", "sts", "get-caller-identity", "--output", "json"], @@ -179,7 +156,7 @@ def run_checks(env: str) -> bool: except (subprocess.TimeoutExpired, json.JSONDecodeError): checks.append(("AWS credentials valid", False, "Run: aws configure")) - # 9. ACM cert exists for custom domain (only if custom_domain is set) + # 8. ACM cert exists for custom domain (only if custom_domain is set) if custom_domain: try: result = subprocess.run( From 68201bd93253ba80c867a694a3d7fb1338763e1a Mon Sep 17 00:00:00 2001 From: Christine Stirrat Date: Mon, 20 Apr 2026 21:12:51 -0400 Subject: [PATCH 4/4] fix: revert hardcoded org-specific bucket names, remove default from bootstrap --- terraform/aws/main.tf | 2 +- terraform/bootstrap/variables.tf | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/terraform/aws/main.tf b/terraform/aws/main.tf index 8af2d66..7057ec5 100644 --- a/terraform/aws/main.tf +++ b/terraform/aws/main.tf @@ -2,7 +2,7 @@ terraform { required_version = ">= 1.0" backend "s3" { - bucket = "opencontext-terraform-state-govex-dc" + bucket = "opencontext-terraform-state" key = "opencontext/terraform.tfstate" region = "us-east-1" encrypt = true diff --git a/terraform/bootstrap/variables.tf b/terraform/bootstrap/variables.tf index 10c01ba..3a87afe 100644 --- a/terraform/bootstrap/variables.tf +++ b/terraform/bootstrap/variables.tf @@ -7,5 +7,4 @@ variable "aws_region" { variable "state_bucket_name" { description = "Name of the S3 bucket for Terraform state" type = string - default = "opencontext-terraform-state-govex-dc" }