Skip to content

Managed domains - #4

Open
siddhsuresh wants to merge 38 commits into
mainfrom
managed-domains
Open

Managed domains#4
siddhsuresh wants to merge 38 commits into
mainfrom
managed-domains

Conversation

@siddhsuresh

@siddhsuresh siddhsuresh commented May 29, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces Ravion-managed domains across ECS clusters, ECS services, and static sites.

  • Moves cluster HTTPS listeners into the ECS cluster module and supports managed wildcard certificates.
  • Adds automatic and custom domain routing for ECS services.
  • Adds managed certificate and custom-domain integration for static sites.
  • Extends the ALB module to support parent-owned HTTPS listeners and forced HTTP redirects.

Confidence Score: 3/5

The PR is not yet safe to merge because the incomplete private IPv6 state migration can interrupt HTTPS traffic during upgrades.

Existing managed-domain clusters can still recreate the renamed private IPv6 ingress rule because its moved block is absent, and ECS service custom domains still allow nullable ALB routing targets to reach the provider without clear validation.

Files Needing Attention: compute/ecs_cluster/listeners.tf; compute/ecs_service/ravion_domains.tf

Important Files Changed

Filename Overview
compute/ecs_cluster/listeners.tf Centralizes public and private HTTPS listeners and ingress rules, but the previously reported private IPv6 state migration remains incomplete.
compute/ecs_cluster/ravion_domains.tf Creates the shared managed wildcard certificate and points its DNS target at the selected cluster ALB.
compute/ecs_service/ravion_domains.tf Adds service certificates and domain records, while the previously reported validation gap for custom-domain ALB targets remains.
hosting/static_site/ravion_domains.tf Adds managed certificates and custom-domain records targeting the static site's CloudFront distribution.
networking/alb/listeners.tf Supports HTTP-to-HTTPS redirects when the HTTPS listener is owned by a parent module.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Cluster["ECS cluster"] --> Cert["Ravion wildcard certificate"]
  Cert --> Listener["Cluster HTTPS listener"]
  Service["ECS service"] --> Rule["ALB host routing rule"]
  Rule --> Listener
  Service --> Domain["Managed or custom domain"]
  Domain --> ALB["Cluster ALB"]
  Site["Static site"] --> SiteCert["Ravion certificate"]
  SiteCert --> CDN["CloudFront distribution"]
  Site --> SiteDomain["Custom domain"]
  SiteDomain --> CDN
Loading

Reviews (2): Last reviewed commit: "feat(definitions): hide BYO certificate/..." | Re-trigger Greptile

siddhsuresh and others added 24 commits May 27, 2026 17:10
use_ravion_managed_domains toggle: ravion_certificate (shared_wildcard) issues
*.<name>-<hash>.<apex>; this module owns the public ALB HTTPS listener with that
cert as default (alb submodule skips its HTTPS listener + cert ARNs); opens SG
443. Outputs the wildcard fqdn + listener arn + cert arn + aws account/region
for ecs_service to nest under. Provider pinned ravion.com/ravion/ravion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cluster_parent_fqdn enables Ravion domains. Mode A (no domains): ravion_domain
auto-FQDN <name>.<cluster-apex> rides the cluster wildcard via a listener rule.
Mode B (domains): per-service ravion_certificate (<=10 SANs) attached to the
cluster listener + ravion_domain custom routing records; auto-FQDN retires once
customs are healthy (ravion_auto_domain_status). Skips caller listener rules in
Ravion mode. Outputs auto fqdn/url + custom cert arn.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
use_ravion_managed_domains: ravion_certificate (instance, target_arn = the
CloudFront distribution ARN, region us-east-1) covering custom domains or a
generated auto-FQDN; ravion_domain custom routing records (ALIAS to the
distribution, CloudFront zone Z2FDTNDATAQYW2). Configure var.distributions
without aliases/cert in this mode (Ravion sets them server-side).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The cluster only wired the Ravion wildcard cert + 443 HTTPS listener on the
public ALB, so private services (web-private / private-network-server) had no
Ravion-owned listener to attach to. Mirror the public wiring onto the private
ALB — one wildcard cert backs both listeners (an ACM ARN can default many).

ecs_cluster:
- enable_ravion_domain now triggers on public OR private ALB (was public-only);
  precondition requires at least one ALB instead of mandating the public one.
- Add aws_lb_listener.ravion_https_private on the private ALB (same cluster
  cert) + a private-ALB 443 ingress rule; private alb submodule now skips its
  own HTTPS listener/cert in Ravion mode, same as the public submodule.
- public/private_alb_https_listener_arn outputs surface the Ravion-owned
  listener when present (length()-guarded so a private-only cluster is valid).

ecs_service:
- Generalize cluster_https_listener_arn / cluster_alb_dns_name / cluster_alb_zone_id
  descriptions: pipe the public OR private ALB outputs per the service's
  visibility. The resources were already visibility-agnostic; only the docs
  hardcoded "public".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…iven id

The cluster wildcard FQDN used var.name (the project-environment slug, e.g.
testttsss-prod-modules), not the user-facing instance given id (elysia-ecs-cluster).
Declare module_instance_given_id (injected by the runner as
TF_VAR_module_instance_given_id) and default the cert leaf to it, so the
wildcard becomes <given-id>-<hash>.<ravion-apex>.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Match the ecs_cluster fix: the service auto-domain (<leaf>.<cluster-wildcard>)
used var.name (project-env slug) instead of the user-facing instance given id.
Declare module_instance_given_id (runner-injected) and default the leaf to it,
so the auto-FQDN becomes <given-id>.<cluster-apex>.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ravion_certificate.cluster now passes target_dns_name/target_zone_id
(public ALB if present, else private) so Ravion publishes a *.<apex>
ALIAS to the cluster ALB. Service auto-FQDNs riding the wildcard then
resolve with no per-service DNS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ollide

Fixed name + create_before_destroy = true means any attribute change that
forces TG replacement (e.g. container_port change) fails apply because the
new TG can't share the same name as the existing one. Switching to name_prefix
lets AWS allocate a unique suffix on each create.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Existing 'spa' and 'filesystem' modes append /index.html to extensionless
paths, which is wrong for object sites whose URLs ARE the S3 keys —
namely a Terraform provider registry, where the viewer requests
`/v1/providers/<ns>/<type>/versions` and must get back the literal JSON
file at that key, not `/<...>/versions/index.html`.

`raw` is a 1:1 viewer-URI → /<version>/<URI> mapping. KVS-driven
versioning still applies. Use for terraform registries, S3-like content
APIs, or any case where viewer URLs must equal S3 keys 1:1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move all required_providers source references from
`providers.siddharthsuresh.dev/ravion/ravion` (cloudflared → local
registry on a laptop) to `provider-cf.siddharthsuresh.dev/ravion/ravion`
(CloudFront → S3, multi-version, KMS-signed). The local-cloudflared
path stays alive during the cutover so existing stacks pinning the old
hostname keep working until they're migrated or destroyed.

Migration note: existing stacks have provider addresses recorded in
their cloud-backend state under the old hostname. A subsequent apply
will need a state-replace-provider pass, OR be done as part of a
destroy+recreate. New stacks pick up the new hostname automatically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The runner's terraformrc network-mirror config is hardcoded for the
canonical hostname (providers.siddharthsuresh.dev). Pointing modules at
provider-cf.siddharthsuresh.dev triggers terraform's
"requires authentication credentials" error since the runner doesn't
emit a credentials/mirror block for that host. The proper migration is
stage B — keep the source unchanged and point the canonical hostname's
DNS at CloudFront — not a per-module source rewrite. Reverting `2f78c63`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ains state

ecs_cluster always owns the public/private HTTPS listener at a stable TF address
so toggling use_ravion_managed_domains is an in-place certificate swap, not a
destroy+create across two addresses. Only the default cert (Ravion wildcard vs
the customer's first ARN), the SNI cert set, and ravion_certificate.cluster
change on toggle.

- alb submodule: additive force_http_to_https_redirect keeps the HTTP->HTTPS
  redirect when a parent owns port 443; redirect deduped into locals
- new ravion_managed_domains_enabled output for service-level show/hide
- moved blocks for the in-root renames + submodule->root migration
- focused tests/listeners.tftest.hcl (8/8 pass)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sification

Each domains entry is classified per-entry instead of all-or-nothing:
<leaf>.<apex> (one label under the cluster apex) rides the cluster wildcard
cert via SNI (no per-service cert, no DNS record); everything else gets one
per-service instance cert + a customer routing record. Empty list falls back
to the auto-FQDN <given-id>.<apex>. Removes the ravion_auto_domain_status
retirement flow — the domains list is the single source of truth.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lowercase + strip trailing dot/whitespace + drop empties, and require a
non-empty leaf for the wildcard bucket, so mixed-case / trailing-dot /
empty-leaf entries classify correctly and never yield an invalid ALB host
header.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Domains under the cluster apex that aren't a single-label <leaf>.<apex>
(the bare apex, or names more than one label deep) can't ride the
*.<apex> wildcard cert and can't be satisfied with a customer record
(the record would live in the Ravion-managed zone). Add an
invalid_apex_domains local + a lifecycle.precondition on
ravion_certificate.svc that fails the plan with the offending entries
and the fix, instead of silently mis-routing them into a per-service
cert + an unwritable routing record. Pairs with the server-side
RejectCustomDomainUnderApex backstop for direct-API callers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- B3: mock the ravion provider in the pre-existing ecs_cluster + ecs_service
  basic.tftest.hcl so the suites stop aborting on "Missing Ravion API key"
  (declaring the provider configures it even when all ravion resources are
  count=0 on the BYO path).
- M13: split the ravion listener rule's host headers into chunks of <=5 values
  (AWS ALB's per-rule condition-value quota), each chunk with its own priority.
- M14: keep the rolling target group's pre-branch stable name
  substr(var.name,0,28)+"-tg" instead of name_prefix — avoids the one-time
  ForceNew that deadlocks against the listener rule's ignore_changes=[action],
  and stays within ALB's 32-char TG-name limit.
- #39: gate the ravion listener rule (and cert/domain) on enable_load_balancer
  so it can't be created with a null target_group_arn.
- #40: widen the auto-derived rule-priority hash entropy to cut collisions on
  the shared cluster listener.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…in-place rotation

Rotating the shared_wildcard cert (any RequiresReplace change, e.g. a renamed
apex) destroyed the old cert before swapping the listener, hitting ACM
ResourceInUse and deadlocking. create_before_destroy issues the new cert and
swaps it onto the listener in-place before deleting the old one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ision_check

A second cluster claiming an apex another cluster already owns silently
hijacked the *.<apex> routing ALIAS. Add a plan-time precondition backed by
the ravion_dns_collision_check data source (the backend resolves the name leaf
to *.<name>.<apex> and reports a collision only when a DIFFERENT module
instance owns it, so a self re-apply passes). The allocator enforces the same
rule server-side as an apply-time backstop.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ider >= 1.0.0

Add a ravion_parent_apex_check data source + a precondition on the service's
nested wildcard domains: the plan fails if cluster_parent_fqdn points at an
apex the service isn't entitled to (e.g. another cluster's apex). The control
plane enforces the same rule at apply (Dns:PARENT_APEX_UNAUTHORIZED), so this
only surfaces the failure earlier — users never write the guard.

The empty-domains auto-FQDN fallback (effective_domains) is unchanged: a service
with no custom domains still gets <given-id>.<apex> and stays accessible.

Bump the ravion provider pin to >= 1.0.0 across ecs_service, ecs_cluster, and
static_site (the build that ships the parent-apex data source + the server-side
apex guards).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ependents

Wire the second new data source: read the live service domains nested under the
cluster wildcard apex and expose them as the ravion_cluster_dependent_domains
output for the UI / safe-teardown orchestration.

Deliberately an output, not a precondition: a cluster legitimately has dependents
during normal operation and Terraform can't scope a precondition to destroy-time,
so a dependent_count == 0 gate would block every apply. The control plane already
refuses a wildcard-cert teardown while dependents exist (Dns:CERT_APEX_IN_USE).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… rule

The control plane now authorizes parent-apex nesting from a signed token claim
(the clusters the run references), not same-environment. Update the guard
comment + precondition error message to say "references that cluster" instead of
"in this environment."

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@siddhsuresh
siddhsuresh marked this pull request as ready for review June 1, 2026 15:37
Comment thread compute/ecs_cluster/listeners.tf Outdated
Comment on lines +185 to +188
moved {
from = aws_vpc_security_group_ingress_rule.ravion_https_private_ipv4
to = aws_vpc_security_group_ingress_rule.private_https_ipv4
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 The private IPv6 SG rule rename is missing a moved block. Three of the four symmetrical SG rule renames have moved blocks (ravion_https_ipv4, ravion_https_ipv6, ravion_https_private_ipv4), but ravion_https_private_ipv6private_https_ipv6 is absent. For any cluster already in Ravion mode with a private ALB, Terraform will destroy the old rule and create a new one, creating a brief window where IPv6 traffic on port 443 to the private ALB is not covered.

Suggested change
moved {
from = aws_vpc_security_group_ingress_rule.ravion_https_private_ipv4
to = aws_vpc_security_group_ingress_rule.private_https_ipv4
}
moved {
from = aws_vpc_security_group_ingress_rule.ravion_https_private_ipv4
to = aws_vpc_security_group_ingress_rule.private_https_ipv4
}
moved {
from = aws_vpc_security_group_ingress_rule.ravion_https_private_ipv6
to = aws_vpc_security_group_ingress_rule.private_https_ipv6
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: compute/ecs_cluster/listeners.tf
Line: 185-188

Comment:
The private IPv6 SG rule rename is missing a `moved` block. Three of the four symmetrical SG rule renames have `moved` blocks (`ravion_https_ipv4`, `ravion_https_ipv6`, `ravion_https_private_ipv4`), but `ravion_https_private_ipv6``private_https_ipv6` is absent. For any cluster already in Ravion mode with a private ALB, Terraform will destroy the old rule and create a new one, creating a brief window where IPv6 traffic on port 443 to the private ALB is not covered.

```suggestion
moved {
  from = aws_vpc_security_group_ingress_rule.ravion_https_private_ipv4
  to   = aws_vpc_security_group_ingress_rule.private_https_ipv4
}

moved {
  from = aws_vpc_security_group_ingress_rule.ravion_https_private_ipv6
  to   = aws_vpc_security_group_ingress_rule.private_https_ipv6
}
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +136 to +139
precondition {
condition = length(local.custom_domains) == 0 || (var.cluster_https_listener_arn != null && var.cluster_https_listener_arn != "")
error_message = "cluster_https_listener_arn is required when the domains list includes a custom (non-wildcard) domain."
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 ravion_domain.custom uses var.cluster_alb_dns_name and var.cluster_alb_zone_id as target_dns_name/target_zone_id, but there are no preconditions validating that these are non-null when custom domains are present. The sibling ravion_certificate.svc resource guards ravion_aws_account_id and cluster_https_listener_arn, but the two ALB variables are left unchecked. A user who provides custom domains and forgets these variables will get a cryptic provider-side null error instead of a clear Terraform message.

Suggested change
precondition {
condition = length(local.custom_domains) == 0 || (var.cluster_https_listener_arn != null && var.cluster_https_listener_arn != "")
error_message = "cluster_https_listener_arn is required when the domains list includes a custom (non-wildcard) domain."
}
precondition {
condition = length(local.custom_domains) == 0 || (var.cluster_https_listener_arn != null && var.cluster_https_listener_arn != "")
error_message = "cluster_https_listener_arn is required when the domains list includes a custom (non-wildcard) domain."
}
precondition {
condition = length(local.custom_domains) == 0 || (var.cluster_alb_dns_name != null && var.cluster_alb_dns_name != "")
error_message = "cluster_alb_dns_name is required when the domains list includes a custom (non-wildcard) domain."
}
precondition {
condition = length(local.custom_domains) == 0 || (var.cluster_alb_zone_id != null && var.cluster_alb_zone_id != "")
error_message = "cluster_alb_zone_id is required when the domains list includes a custom (non-wildcard) domain."
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: compute/ecs_service/ravion_domains.tf
Line: 136-139

Comment:
`ravion_domain.custom` uses `var.cluster_alb_dns_name` and `var.cluster_alb_zone_id` as `target_dns_name`/`target_zone_id`, but there are no preconditions validating that these are non-null when custom domains are present. The sibling `ravion_certificate.svc` resource guards `ravion_aws_account_id` and `cluster_https_listener_arn`, but the two ALB variables are left unchecked. A user who provides custom domains and forgets these variables will get a cryptic provider-side null error instead of a clear Terraform message.

```suggestion
    precondition {
      condition     = length(local.custom_domains) == 0 || (var.cluster_https_listener_arn != null && var.cluster_https_listener_arn != "")
      error_message = "cluster_https_listener_arn is required when the domains list includes a custom (non-wildcard) domain."
    }
    precondition {
      condition     = length(local.custom_domains) == 0 || (var.cluster_alb_dns_name != null && var.cluster_alb_dns_name != "")
      error_message = "cluster_alb_dns_name is required when the domains list includes a custom (non-wildcard) domain."
    }
    precondition {
      condition     = length(local.custom_domains) == 0 || (var.cluster_alb_zone_id != null && var.cluster_alb_zone_id != "")
      error_message = "cluster_alb_zone_id is required when the domains list includes a custom (non-wildcard) domain."
    }
```

How can I resolve this? If you propose a fix, please make it concise.

Comment thread hosting/static_site/ravion_domains.tf Outdated
Comment on lines +34 to +43
lifecycle {
precondition {
condition = !var.use_ravion_managed_domains || (var.ravion_aws_account_id != null && var.ravion_aws_account_id != "")
error_message = "ravion_aws_account_id (aws_*) is required when use_ravion_managed_domains = true."
}
precondition {
condition = length(var.domains) <= 10
error_message = "A static site may declare at most 10 custom domains."
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 ravion_distribution_arn and ravion_distribution_domain both use try(...[0], null), which silently returns null if the module.cdn distribution maps are empty (i.e., no distributions are configured). These null values are then passed as target_arn to ravion_certificate.site and as target_dns_name to ravion_domain.custom with no guard, producing a cryptic provider-side error instead of a clear Terraform message. A precondition on ravion_certificate.site would surface this early.

Suggested change
lifecycle {
precondition {
condition = !var.use_ravion_managed_domains || (var.ravion_aws_account_id != null && var.ravion_aws_account_id != "")
error_message = "ravion_aws_account_id (aws_*) is required when use_ravion_managed_domains = true."
}
precondition {
condition = length(var.domains) <= 10
error_message = "A static site may declare at most 10 custom domains."
}
}
lifecycle {
precondition {
condition = !var.use_ravion_managed_domains || (var.ravion_aws_account_id != null && var.ravion_aws_account_id != "")
error_message = "ravion_aws_account_id (aws_*) is required when use_ravion_managed_domains = true."
}
precondition {
condition = length(var.domains) <= 10
error_message = "A static site may declare at most 10 custom domains."
}
precondition {
condition = !var.use_ravion_managed_domains || local.ravion_distribution_arn != null
error_message = "use_ravion_managed_domains = true requires at least one CloudFront distribution in var.distributions."
}
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: hosting/static_site/ravion_domains.tf
Line: 34-43

Comment:
`ravion_distribution_arn` and `ravion_distribution_domain` both use `try(...[0], null)`, which silently returns `null` if the `module.cdn` distribution maps are empty (i.e., no distributions are configured). These null values are then passed as `target_arn` to `ravion_certificate.site` and as `target_dns_name` to `ravion_domain.custom` with no guard, producing a cryptic provider-side error instead of a clear Terraform message. A precondition on `ravion_certificate.site` would surface this early.

```suggestion
  lifecycle {
    precondition {
      condition     = !var.use_ravion_managed_domains || (var.ravion_aws_account_id != null && var.ravion_aws_account_id != "")
      error_message = "ravion_aws_account_id (aws_*) is required when use_ravion_managed_domains = true."
    }
    precondition {
      condition     = length(var.domains) <= 10
      error_message = "A static site may declare at most 10 custom domains."
    }
    precondition {
      condition     = !var.use_ravion_managed_domains || local.ravion_distribution_arn != null
      error_message = "use_ravion_managed_domains = true requires at least one CloudFront distribution in var.distributions."
    }
  }
```

How can I resolve this? If you propose a fix, please make it concise.

siddhsuresh and others added 3 commits June 1, 2026 23:35
ravion_certificate/ravion_domain now require module_instance_id so the resources
work outside a Ravion stack run (service-account API key) as well as inside it.
Add a module_instance_id variable to ecs_cluster + ecs_service and forward it to
every ravion_certificate/ravion_domain block (cluster wildcard cert; service
wildcard/custom domains + instance cert).

Inside a stack run the runner injects TF_VAR_module_instance_id, so this is
populated automatically; external/API-key runs set it explicitly. The control
plane still prefers the signed token's instance when a stack-run JWT is present.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Conflict resolution + cross-repo reconciliation:
- alb/ecs_cluster listener config re-expressed in main's renamed variables (http_listener_enabled, https_listener_enabled, http_to_https_redirect_enabled, public/private_alb_enabled, *_https_enabled) while keeping this branch's cluster-owned HTTPS listener architecture and force_http_to_https_redirect
- target_groups.tf taken from main: its tg_1/tg_2 + ignore_changes=[name] design subsumes this branch's stable-name comment; ravion_target_group_arn now reads tg_1
- dropped ravion_dns_collision_check / ravion_apex_dependents / ravion_parent_apex_check data sources and the ravion_cluster_dependent_domains output: the provider now runs these checks in each resource's ModifyPlan (PR 6456 review rework) and removed the data sources
- dropped role= on ravion_aws_acm_certificate (now computed from wildcard)
- tofu validate passes for networking/alb, compute/ecs_cluster, compute/ecs_service against the provider built from merged domains-restore

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown

Ravion Module Publish Plan

Dry run only. No Ravion API mutations were made.

Module Current Version New Version Description
rvn-aws-alb 0.1.0 0.1.1 Ship the managed-domains groundwork in the module source: force_http_to_https_redirect removed in favor of listener-owned redirects, HTTPS listener certificate precondition, and the https_listener_certificate_arn output.
rvn-aws-static 0.3.5 0.3.6 Surface the Domains section (aliases + ACM certificate) right after the hosting basics instead of inside CloudFront settings.
rvn-ecs-cluster 0.5.0 0.6.2 Managed domains keeps every BYO certificate attached via SNI when the Ravion wildcard takes over as the default certificate, so enabling it never drops TLS for existing custom hostnames.
rvn-ecs-nlb 0.3.1 0.3.2 Pick up the shared ecs_service module source updates from the managed-domains work (no NLB-facing input changes).
rvn-ecs-web 0.8.4 0.9.1 Add Ravion-managed domains: service domains ride the cluster wildcard certificate automatically, and custom domains get a dedicated certificate with DNS validation, when the selected cluster has managed domains enabled. The Domains section sits right after the service basics.
rvn-ecs-worker 0.3.3 0.3.4 Pick up the shared ecs_service module source updates from the managed-domains work (no worker-facing input changes).

Diffs

rvn-aws-alb 0.1.0 -> 0.1.1

--- remote
+++ compiled
 
   The load balancer intentionally serves no traffic by itself. Services that reference this module, such as EC2 services, create their own target groups and listener rules on the shared listeners.
 
-  Terraform source: [flightcontrolhq/modules/networking/alb](https://github.com/flightcontrolhq/modules/tree/rvn-aws-alb@0.1.0/networking/alb)
+  Terraform source: [flightcontrolhq/modules/networking/alb](https://github.com/flightcontrolhq/modules/tree/rvn-aws-alb@0.1.1/networking/alb)
 
   ## Use cases
 
@@
         base_path: networking/alb
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-aws-alb@0.1.0
+        ref: rvn-aws-alb@0.1.1
         repo: https://github.com/flightcontrolhq/modules
         stack_id: <<stack.id>>
         terraform_variables:

rvn-aws-static 0.3.5 -> 0.3.6

--- remote
+++ compiled
     label: Default version prefix
     required: true
     type: string
+  - id: section_domains
+    label: Domains
+    type: section
+  - add_button_label: Add domain alias
+    default: []
+    description: Custom domain names like app.example.com. Leave empty to use the default cloudfront.net domain.
+    id: distribution_aliases
+    label: Domain aliases
+    type: string_array
+  - description: Required if using domain aliases. The certificate module must be in us-east-1.
+    id: distribution_acm_certificate
+    label: ACM certificate
+    mapped_inputs:
+      - default: <<ref.stack.output.certificate_arn>>
+        id: distribution_acm_certificate_arn
+        label: CloudFront certificate ARN
+        type: string
+    required: false
+    type: $ref:rvn-acm-certificate
   - id: section_build
     label: Build config
     type: section
@@
   - id: section_cloudfront
     label: CloudFront settings
     type: section
-  - description: Required if using domain aliases. The certificate module must be in us-east-1.
-    id: distribution_acm_certificate
-    label: ACM certificate
-    mapped_inputs:
-      - default: <<ref.stack.output.certificate_arn>>
-        id: distribution_acm_certificate_arn
-        label: CloudFront certificate ARN
-        type: string
-    required: false
-    type: $ref:rvn-acm-certificate
-  - add_button_label: Add domain alias
-    default: []
-    description: Custom domain names like app.example.com. Leave empty to use the default cloudfront.net domain.
-    id: distribution_aliases
-    label: Domain aliases
-    type: string_array
   - default: PriceClass_All
     description: You can reduce edge locations for some cost savings if it becomes an issue.
     id: price_class
@@
 
   Every deployment is versioned. The deploy step promotes an S3 directory by updating the CloudFront KeyValueStore active pointer. CloudFront rewrites viewer requests to the active version prefix before it reads from S3.
 
-  Terraform source: [flightcontrolhq/modules/hosting/static_site](https://github.com/flightcontrolhq/modules/tree/rvn-aws-static@0.3.5/hosting/static_site)
+  Terraform source: [flightcontrolhq/modules/hosting/static_site](https://github.com/flightcontrolhq/modules/tree/rvn-aws-static@0.3.6/hosting/static_site)
 
   ## Use cases
 
@@
         base_path: hosting/static_site
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-aws-static@0.3.5
+        ref: rvn-aws-static@0.3.6
         repo: https://github.com/flightcontrolhq/modules
         stack_id: <<stack.id>>
         terraform_variables:

rvn-ecs-cluster 0.5.0 -> 0.6.2

--- remote
+++ compiled
         value: enabled
       - label: Disabled
         value: disabled
+  - id: section_managed_domains
+    label: Managed domains
+    type: section
+  - default: false
+    description: Have Ravion issue and manage a shared wildcard TLS certificate and DNS for this cluster. The selected ALB HTTPS listener serves the wildcard certificate, and services get automatic domains under the cluster apex. Requires exactly one HTTPS-enabled ALB.
+    id: use_ravion_managed_domains
+    label: Ravion-managed domains
+    type: boolean
+  - description: Subdomain for the cluster's wildcard domain. Defaults to the module given ID when empty.
+    id: ravion_cluster_name
+    label: Cluster subdomain
+    patterns:
+      - message: The subdomain must contain only lowercase letters, numbers, and hyphens, and start and end with a letter or number.
+        pattern: ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$
+    required: false
+    show_when:
+      use_ravion_managed_domains: true
+    suffix: .<< platform.apex >>
+    type: string
   - id: section_capacity
     label: Capacity providers
     type: section
@@
     show_when:
       public_alb_enabled: true
       public_alb_https_enabled: true
+      use_ravion_managed_domains: false
     type: $ref:rvn-acm-certificate
   - add_button_label: Add certificate ARN
     collapsible: true
@@
     show_when:
       public_alb_enabled: true
       public_alb_https_enabled: true
+      use_ravion_managed_domains: false
     type: string_array
   - collapsible: true
     description: SSL policy for public ALB HTTPS.
@@
     show_when:
       private_alb_enabled: true
       private_alb_https_enabled: true
+      use_ravion_managed_domains: false
     type: $ref:rvn-acm-certificate
   - add_button_label: Add certificate ARN
     collapsible: true
@@
     show_when:
       private_alb_enabled: true
       private_alb_https_enabled: true
+      use_ravion_managed_domains: false
     type: string_array
   - collapsible: true
     description: SSL policy for private ALB HTTPS.
@@
   - **Public and private Network Load Balancers** for TCP/UDP and static IP use cases
   - **CloudWatch Container Insights** dashboard metrics for production visibility
 
-  Terraform source: [flightcontrolhq/modules/compute/ecs_cluster](https://github.com/flightcontrolhq/modules/tree/rvn-ecs-cluster@0.5.0/compute/ecs_cluster)
+  Terraform source: [flightcontrolhq/modules/compute/ecs_cluster](https://github.com/flightcontrolhq/modules/tree/rvn-ecs-cluster@0.6.2/compute/ecs_cluster)
 
   ## Use cases
 
@@
         base_path: compute/ecs_cluster
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-ecs-cluster@0.5.0
+        ref: rvn-ecs-cluster@0.6.2
         repo: https://github.com/flightcontrolhq/modules
         stack_id: <<stack.id>>
         terraform_variables:
@@
           public_nlb_enabled: << module.input.public_nlb_enabled >>
           public_nlb_security_group_ids: << module.input.public_nlb_security_group_ids >>
           public_subnet_ids: << module.input.public_subnet_ids || [] >>
+          ravion_aws_account_id: << module.input.aws_account_id >>
+          ravion_aws_region: << module.input.aws_region >>
+          ravion_cluster_name: << module.input.ravion_cluster_name >>
           region: << module.input.aws_region >>
           tags:
             ...overrides: << module.input.tags >>
@@
             ModuleId: <<module.id>>
             Owner: Ravion
             ProjectGivenId: <<project.given_id>>
+          use_ravion_managed_domains: << module.input.use_ravion_managed_domains >>
           vpc_id: << module.input.vpc_id >>
         tool: opentofu
         tool_version: << module.input.opentofu_version || defaults.opentofu_version >>

rvn-ecs-nlb 0.3.1 -> 0.3.2

--- remote
+++ compiled
 
   The module is intentionally focused on Layer 4 services behind a Network Load Balancer. Use ECS Web Service for HTTP host and path routing through an Application Load Balancer.
 
-  Terraform source: [flightcontrolhq/modules/compute/ecs_service](https://github.com/flightcontrolhq/modules/tree/rvn-ecs-nlb@0.3.1/compute/ecs_service)
+  Terraform source: [flightcontrolhq/modules/compute/ecs_service](https://github.com/flightcontrolhq/modules/tree/rvn-ecs-nlb@0.3.2/compute/ecs_service)
 
   ## Use cases
 
@@
         base_path: compute/ecs_service
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-ecs-nlb@0.3.1
+        ref: rvn-ecs-nlb@0.3.2
         repo: https://github.com/flightcontrolhq/modules
         stack_id: <<stack.id>>
         terraform_variables:

rvn-ecs-web 0.8.4 -> 0.9.1

--- remote
+++ compiled
         immutable: true
         label: Private ALB security group ID
         type: string
+      - collapsible: true
+        default: << ref.stack.output.ravion_managed_domains_enabled || false >>
+        description: Whether the selected cluster has Ravion-managed domains enabled (its ALB HTTPS listener serves the cluster wildcard certificate).
+        id: ravion_managed_domains_enabled
+        label: Cluster-managed domains
+        type: boolean
+      - collapsible: true
+        default: <<ref.stack.output.ravion_cluster_domain_fqdn>>
+        description: Wildcard apex of the selected cluster. Service domains one label under it ride the cluster wildcard certificate automatically.
+        id: cluster_parent_fqdn
+        label: Cluster domain apex
+        required: false
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.public_alb_dns_name>>
+        id: public_alb_dns_name
+        immutable: true
+        label: Public ALB DNS name
+        required: false
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.public_alb_zone_id>>
+        id: public_alb_zone_id
+        immutable: true
+        label: Public ALB hosted zone ID
+        required: false
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.private_alb_dns_name>>
+        id: private_alb_dns_name
+        immutable: true
+        label: Private ALB DNS name
+        required: false
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.private_alb_zone_id>>
+        id: private_alb_zone_id
+        immutable: true
+        label: Private ALB hosted zone ID
+        required: false
+        type: string
     required: true
     type: $ref:rvn-ecs-cluster
   - id: section_service
@@
     id: private_subnet_placement_enabled
     label: Run in private subnets
     type: boolean
+  - id: section_domains
+    label: Domains
+    show_when:
+      ravion_managed_domains_enabled: true
+    type: section
+  - add_button_label: Add domain
+    description: Fully-qualified domains for this service. A name one label under the cluster apex rides the cluster wildcard certificate automatically; any other name gets a dedicated certificate with DNS validation records you add at your DNS host. Empty = an automatic <service>.<cluster apex> domain.
+    id: domains
+    label: Domains
+    max_length: 10
+    placeholder: app.example.com
+    show_when:
+      ravion_managed_domains_enabled: true
+    type: string_array
   - id: section_build
     label: Build config
     type: section
@@
   - description: Add at least one domain host rule or path rule.
     id: section_routing
     label: HTTP listener rules
+    show_when:
+      ravion_managed_domains_enabled: false
     type: section
   - add_button_label: Add domain host
     default: null
@@
     label: Domain host rules
     placeholder: app.example.com
     required: false
+    show_when:
+      ravion_managed_domains_enabled: false
     type: string_array
   - add_button_label: Add path pattern
     collapsible: true
@@
     id: path_pattern_values
     label: Path rules
     required: false
+    show_when:
+      ravion_managed_domains_enabled: false
     type: string_array
   - collapsible: true
     description: Optional ALB listener rule priority. Leave blank to let AWS assign the next available priority.
@@
     label: Listener rule priority
     max: 50000
     min: 1
+    show_when:
+      ravion_managed_domains_enabled: false
     type: number
   - id: section_task
     label: Container resources
@@
 
   The module is intentionally focused on web services behind an Application Load Balancer. It uses the selected ECS cluster to inherit AWS account, region, VPC, subnets, capacity providers, load balancer listeners, and load balancer security groups.
 
-  Terraform source: [flightcontrolhq/modules/compute/ecs_service](https://github.com/flightcontrolhq/modules/tree/rvn-ecs-web@0.8.4/compute/ecs_service)
+  Terraform source: [flightcontrolhq/modules/compute/ecs_service](https://github.com/flightcontrolhq/modules/tree/rvn-ecs-web@0.9.1/compute/ecs_service)
 
   ## Use cases
 
@@
         base_path: compute/ecs_service
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-ecs-web@0.8.4
+        ref: rvn-ecs-web@0.9.1
         repo: https://github.com/flightcontrolhq/modules
         stack_id: <<stack.id>>
         terraform_variables:
@@
             - '...<< module.input.capacity_provider == "fargate" || module.input.additional_fargate_capacity_enabled ? [{capacity_provider: module.input.fargate_capacity_provider_name, weight: 1, base: 0}] : [] >>'
             - '...<< module.input.capacity_provider == "fargate_spot" || module.input.additional_fargate_spot_capacity_enabled ? [{capacity_provider: module.input.fargate_spot_capacity_provider_name, weight: 1, base: 0}] : [] >>'
             - '...<< module.input.capacity_provider == "ec2" || module.input.additional_ec2_capacity_enabled ? [{capacity_provider: module.input.ec2_capacity_provider_name, weight: 1, base: 0}] : [] >>'
+          cluster_alb_dns_name: "<< module.input.public_web_service_enabled ? module.input.public_alb_dns_name : module.input.private_alb_dns_name >>"
+          cluster_alb_zone_id: "<< module.input.public_web_service_enabled ? module.input.public_alb_zone_id : module.input.private_alb_zone_id >>"
           cluster_arn: << module.input.cluster_arn >>
+          cluster_https_listener_arn: "<< module.input.public_web_service_enabled ? module.input.public_alb_https_listener_arn : module.input.private_alb_https_listener_arn >>"
+          cluster_parent_fqdn: << module.input.cluster_parent_fqdn >>
           container_port: << module.input.container_port >>
           deployment_maximum_percent: << module.input.deployment_maximum_percent >>
           deployment_minimum_healthy_percent: << module.input.deployment_minimum_healthy_percent >>
           deployment_type: rolling
           desired_count: "<< module.input.auto_scaling_enabled ? module.input.min_capacity : module.input.desired_count >>"
+          domains: << module.input.domains || [] >>
           ecr_default_lifecycle_policy_enabled: true
           ecr_force_deletion_enabled: << module.input.ecr_force_deletion_enabled >>
           ecr_repository_creation_enabled: << module.input.build_source == "dockerfile" || module.input.build_source == "railpack" || module.input.build_source == "nixpacks" >>
@@
           network_mode: awsvpc
           new_deployment_forcing_enabled: << module.input.new_deployment_forcing_enabled >>
           public_ip_assignment_enabled: "<< module.input.private_subnet_placement_enabled ? false : true >>"
+          ravion_aws_account_id: << module.input.aws_account_id >>
+          ravion_aws_region: << module.input.aws_region >>
           region: << module.input.aws_region >>
           requires_compatibilities: '<< module.input.capacity_provider == "ec2" ? ["EC2"] : ["FARGATE"] >>'
           runtime_platform:

rvn-ecs-worker 0.3.3 -> 0.3.4

--- remote
+++ compiled
 
   The ECS Worker module creates an ECS service for background jobs, queue consumers, event processors, and other private workloads in an existing Ravion ECS cluster. It uses the same ECS service Terraform module as ECS Web Server, but does not create or attach a load balancer target group and does not expose a primary container port.
 
-  Terraform source: [flightcontrolhq/modules/compute/ecs_service](https://github.com/flightcontrolhq/modules/tree/rvn-ecs-worker@0.3.3/compute/ecs_service)
+  Terraform source: [flightcontrolhq/modules/compute/ecs_service](https://github.com/flightcontrolhq/modules/tree/rvn-ecs-worker@0.3.4/compute/ecs_service)
 
   ## Use cases
 
@@
         base_path: compute/ecs_service
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-ecs-worker@0.3.3
+        ref: rvn-ecs-worker@0.3.4
         repo: https://github.com/flightcontrolhq/modules
         stack_id: <<stack.id>>
         terraform_variables:

siddhsuresh and others added 4 commits July 29, 2026 13:33
- listeners.tftest.hcl: rename to main's *_enabled variable names (terraform
  test silently ignores undeclared vars, so all 8 runs were planning with the
  ALBs disabled and failing their assertions)
- hosting/static_site: port ravion_domains.tf off the pre-review provider API
  (ravion_certificate -> ravion_aws_acm_certificate, role removed, cert_arn/
  fqdn -> arn/domain_name) and add the now-required module_instance_id to the
  certificate and routing-record resources; tofu validate passes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d of indexing the suppressed alb rule

In managed mode aws_lb_listener_rule.alb is never created, so
advanced_configuration.production_listener_rule (and the
production_listener_rule_arn output) indexed an empty map and every
Ravion-managed ALB service failed at plan with 'Invalid index'.

- production listener rule in managed mode is now ravion chunk "0", so
  native traffic-shift deploys rewrite a rule that actually routes the
  managed hostnames
- new precondition: managed ALB services require cluster_https_listener_arn
  (previously a clean apply that 404'd every hostname)
- the listener_rules-required precondition no longer fires for managed
  services, which create their own rules from domains
- the single-production-rule traffic-shift cap now covers managed chunks:
  blue_green/linear/canary need all hostnames in one chunk (<=5); rolling
  is uncapped
- the green test rule is suppressed in managed mode (it mirrors caller
  listener_rules[0], which managed mode discards)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n YAMLs

Closes the repo-vs-API divergence: the managed-domains Terraform was only
reachable through API-published module versions, so the next repo publish
would have silently dropped the feature.

- rvn-ecs-cluster 0.6.0: Managed domains section (use_ravion_managed_domains
  toggle + ravion_cluster_name with a '.<< platform.apex >>' suffix
  adornment) wired to the stack terraform variables
- rvn-ecs-web 0.9.0: cluster-ref mapped inputs (ravion_managed_domains_enabled,
  cluster_parent_fqdn, ALB dns/zone outputs), a domains string_array gated on
  the cluster toggle, and terraform variables selecting the public/private
  HTTPS listener + ALB target to match the service placement
- rvn-aws-static 0.4.0: managed-domains toggle + domains, wired to the
  ported static_site variables

All three pass make publish-local-dev DRY_RUN=1 against local api-go.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ed-domains mode

Instead of documenting 'leave these empty', gate them with show_when:
- ecs_cluster: public/private ALB certificate inputs hide when
  use_ravion_managed_domains is on (the cluster serves the Ravion wildcard)
- ecs_web: the manual HTTP listener-rule inputs hide when the selected
  cluster manages domains (the module creates host-header rules from
  domains); the mapped ravion_managed_domains_enabled default gets a
  || false fallback so services on older cluster versions keep them
- static_site: CloudFront ACM certificate + domain aliases hide in
  managed mode

All three still pass make publish-local-dev DRY_RUN=1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@siddhsuresh

Copy link
Copy Markdown
Author

@greptile

siddhsuresh and others added 7 commits July 29, 2026 18:22
…ing that error

A cluster with use_ravion_managed_domains=true but *_alb_https_enabled=false
issued the wildcard certificate and then had nowhere to put it: the HTTPS
listener is gated on *_alb_https_enabled, so the cert was orphaned, the
*_alb_https_listener_arn outputs stayed null, and every service nesting under
the apex hit the cluster_https_listener_arn precondition with no hint that the
cluster was the problem.

- ecs_cluster: the managed-domains precondition now requires an ALB with HTTPS
  enabled, so this fails at the cluster with an actionable message instead of
  issuing a certificate that can never serve traffic
- ecs_service: production_listener_rule and the production_listener_rule_arn
  output degrade to null when the ravion rules are absent, instead of failing
  with 'Invalid index' and burying the precondition that explains the cause

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s-first form UX

- aws_lb_listener_rule.ravion now emits the same group-stickiness forward the
  BYO production rule has: ECS rewrites chunk 0 to a weighted forward during
  native traffic-shift deploys, and ELBv2 rejects that rewrite when a sticky
  target group lacks group-level stickiness on the action — managed-domains
  services with stickiness + blue/green failed where BYO worked
- ravion_domain.custom preconditions on cluster_alb_dns_name/zone_id: a null
  routing target previously produced a clean apply and a domain that never
  resolves; now it is a plan-time message like the sibling cert's listener guard
- module_instance_id preconditions on every ravion_* resource, mirroring the
  ravion_aws_account_id guard, so external runs get an actionable message
  instead of the provider's generic missing-required-argument
- definitions: Managed domains section moves directly under the cluster basics
  (rvn-ecs-cluster 0.6.1) and the Domains input directly under the service
  basics (rvn-ecs-web 0.9.1); release notes carry the managed-domains headline
  since these are the first published releases containing the feature

Suites: ecs_service 25/25, ecs_cluster managed_domains 6/6, defs compile +
guardrails clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…bling definitions

- ecs_cluster/ecs_service now floor the ravion provider at 1.0.2 (published to
  the dev registry), the first version carrying the Create aws-id stamping,
  Unknown backstops, JSON-gated poll fail-fast, orphan-free create timeout, and
  Configure env fallback; lockfiles re-pinned accordingly
- rvn-aws-alb 0.1.1 / rvn-ecs-nlb 0.3.2 / rvn-ecs-worker 0.3.4: their module
  source drifted since the last published versions and an identical version
  makes the publisher silently skip, so the source changes never ship

Suites re-run on 1.0.2: ecs_cluster managed_domains 6/6, ecs_service 25/25.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ally runs

The alb and ecs_cluster basic suites have been red on main since the variable
renames, and OpenTofu aborts a file on first failure — so 12 alb runs and 22
cluster runs (including the entire public/private ALB + HTTPS matrix that
managed domains rewires) were silently skipped, on main and here.

- alb tests: internal -> internal_load_balancer_enabled, preserve_host_header
  -> host_header_preservation_enabled, waf_enabled now sets the
  waf_association_enabled gate, and the security-group assertions read module
  OUTPUTS instead of child-module internals (never addressable from tftest)
- ecs_cluster tests: the ec2 egress/ingress assertions referenced root-module
  resources that never existed there (the rules live inside the security-groups
  child module); they now assert via module outputs, and the stale ALB
  security-group mock targets point into the alb module's nested
  security_group module so the sg- id validation is satisfied
- networking/security-groups gains all_egress_rule_ids, compute/autoscaling
  gains mixed_instances_policy_enabled + spot_instances_distribution — small
  plan-known outputs so parents and tests can assert behavior without reaching
  into module internals

Suites now: networking/alb 28/28 (was 13 pass / 3 fail / 12 skip),
compute/ecs_cluster 58/58 across all files (was 35/1/22).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…naged mode takes over

Enabling managed domains previously narrowed certificate_arns to just the
Ravion wildcard, so the alb submodule's SNI attachments (arns[1..]) went empty
and every hostname served off an existing BYO certificate lost TLS at cutover.
The wildcard now becomes the DEFAULT certificate while all BYO certificates are
carried forward as SNI attachments — the zero-downtime choice over refusing the
toggle, matching the in-place-swap design of the feature.

- networking/alb gains an additional_certificate_arns output so parents and
  tests can observe the SNI set without reaching into module internals
- new test: managed_toggle_keeps_byo_certificates_attached (wildcard default +
  both BYO certs in the SNI set)
- rvn-ecs-cluster 0.6.2

Suites: networking/alb 28/28, compute/ecs_cluster 59/59.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…g basics

distribution_aliases and the ACM certificate ref lived six sections deep inside
CloudFront settings, so setting a custom domain meant scrolling past the entire
build/Docker/Railpack block. They now form a Domains section (aliases first —
the certificate is only meaningful once an alias exists) directly after the
hosting basics, mirroring the cluster and web-service definitions. CloudFront
settings keeps its own header starting at price_class, so nothing is orphaned.

rvn-aws-static 0.3.6 (0.3.5 is already published).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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