Skip to content

EKS modules: rvn-eks composite, selectable add-ons, services, and observability - #114

Open
mabadir wants to merge 74 commits into
mainfrom
mabadir/eks-observability
Open

EKS modules: rvn-eks composite, selectable add-ons, services, and observability#114
mabadir wants to merge 74 commits into
mainfrom
mabadir/eks-observability

Conversation

@mabadir

@mabadir mabadir commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

The module-side half of EKS deployment support (pairs with ravionhq/flightcontrol#6973).

Cluster and add-ons

  • compute/eks composite with the rvn-eks module definition
  • Selectable add-ons stack (compute/eks/addons): Karpenter (controller + default node pool), EBS CSI, AWS Load Balancer Controller (installed automatically with any shared load balancer), shared load balancers
  • Runner authenticates to the cluster via EKS access entries: self-registered Terraform runner entry plus an assumable Ravion Runner role with cluster-admin; orphaned Helm releases adopted via upgrade_install
  • Ravion Beacon agent shipped through the add-ons chart, defaulting to the public a8z1i1r2 registry (rvn-eks-addons 0.6.1)

Services

  • EKS service modules with container image builds

Observability

  • Workload metrics: Amazon Managed Prometheus + OTel collector + Grafana role in rvn-eks-addons
  • Logs: in-cluster Loki on S3 (replacing Container Insights), covered in tests, docs, and the module definition
  • UI wiring: workload and cluster metrics to AMP, logs to Loki

Greptile Summary

The PR adds a composite EKS platform, selectable cluster add-ons, AWS-side EKS workload infrastructure, reusable Helm charts, observability integrations, module definitions, and integration tests.

  • Provisions EKS clusters, node capacity, runner access, and optional Karpenter, storage, load-balancing, secrets, metrics, logs, and Beacon components.
  • Adds web, worker, and cron workload definitions with image builds and Helm deployments.
  • Adds shared ALB target-group routing and chart-based Kubernetes workload resources.
  • Adds chart CI and AWS/Terraform test coverage.

Confidence Score: 4/5

The target-group naming collision should be fixed before merging because two valid web workload names can make infrastructure creation fail.

Load-balanced workloads whose names share the retained 24-character prefix resolve to the same account-and-region target group name, while the workflow action pinning issue is independently non-blocking.

Files Needing Attention: compute/eks_service/locals.tf and .github/workflows/helm-charts.yml

Security Review

The new Helm workflow uses mutable action tags. Its permissions are limited to repository read access, but pinning these actions to full commit SHAs would prevent upstream tag movement from changing executed CI code.

Important Files Changed

Filename Overview
compute/eks_service/locals.tf Enables optional load balancing and derives target group names, but truncation can collide for workloads sharing a long prefix.
compute/eks_service/target_group.tf Creates an IP-mode target group consumed by the chart's TargetGroupBinding.
compute/eks/addons/beacon.tf Provisions Beacon credentials and deployment configuration; no changed-code blocking defect was established.
charts/rvn-eks-web/templates/targetgroupbinding.yaml Renders one TargetGroupBinding per supplied target group ARN for pod-IP registration.
.github/workflows/helm-charts.yml Adds chart lint/template CI with minimal permissions, but its action dependencies are referenced through mutable tags.
compute/eks/eks_cluster.tf Composes the cluster module and forwards networking, authentication, encryption, add-on, and Pod Identity settings.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Definition["Ravion EKS module definitions"] --> Cluster["compute/eks composite"]
  Cluster --> EKS["EKS control plane"]
  Cluster --> Nodes["System and optional node groups"]
  Cluster --> Addons["compute/eks/addons"]
  Addons --> Controllers["Karpenter, EBS CSI, LB controller, ESO"]
  Addons --> Observability["AMP, OTel, Loki, Alloy, Grafana"]
  Definition --> Service["compute/eks_service"]
  Service --> ECR["Optional ECR repository"]
  Service --> TG["ALB target group and listener rule"]
  Definition --> Charts["Web, worker, and cron Helm charts"]
  Charts --> Workloads["Kubernetes workloads"]
  Workloads --> TG
Loading
Prompt To Fix All With AI
### Issue 1
compute/eks_service/locals.tf:24
**Truncated target-group names collide**

When two load-balanced EKS workloads in the same account and region share the first 24 characters of their names, both resolve to the same target-group name, causing AWS to reject creation of the second target group because that name already exists.

### Issue 2
.github/workflows/helm-charts.yml:26-36
**Action tags remain mutable**

The new workflow references `actions/checkout`, `azure/setup-helm`, and `mikefarah/yq` through mutable tags, allowing upstream tag movement to change the code executed on the runner with access to the checked-out source and read-only repository token. Pin each action to a full commit SHA, matching the repository's existing workflows.

**How this was verified:** Every pre-existing workflow pins action references to full commit SHAs, while these three new references use tags.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "Wire EKS workload and cluster UI metrics..." | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

Context used (4)

mabadir and others added 30 commits July 20, 2026 21:27
Co-authored-by: Cursor <cursoragent@cursor.com>
…finition

Co-authored-by: Cursor <cursoragent@cursor.com>
…e/eks

Co-authored-by: Cursor <cursoragent@cursor.com>
…e/eks root

Module-level depends_on defers submodule data sources on fresh creates,
making managed policy ARNs unknown at plan time and failing
toset(var.managed_policy_arns) in security/iam. Pass the partition from a
root-level data source into the node group, addons, karpenter, and
fargate profile submodules so policy ARNs stay known during plan.

Co-authored-by: Cursor <cursoragent@cursor.com>
…pute/eks

Installs the amazon-cloudwatch-observability add-on (Container Insights) by
default with a shared Pod Identity role for both cloudwatch-agent and
fluent-bit, and surfaces control plane and Container Insights metrics plus
application/dataplane log groups in the rvn-eks definition UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Keeps compute/eks pure AWS API so the cluster provisions in a single
apply; the Karpenter controller, CRDs, and default NodePool move to a
new compute/eks/components stack with its own rvn-eks-components
definition referencing rvn-eks. Adds a default Ravion Runner security
group so runners can reach private API endpoints.

Co-authored-by: Cursor <cursoragent@cursor.com>
Inputs hidden by show_when resolve to nil; fall back to the exact
Terraform defaults for public_access_cidrs and the Karpenter
namespace/service account per the updated config conventions.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
… addons stack, gate Karpenter

Co-authored-by: Cursor <cursoragent@cursor.com>
…ation

Co-authored-by: Cursor <cursoragent@cursor.com>
…ons authenticate via get-token --role-arn

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds public/private ALB and NLB toggles composing the networking/alb and
networking/nlb modules, mirroring the rvn-ecs-cluster shared-LB pattern.
Each enabled load balancer gets an ingress rule admitting its security
group on the EKS cluster security group so it can reach pod IPs, and
listener/security-group/DNS outputs are exposed for workload modules to
attach target groups via the ALB controller's TargetGroupBinding. The
cluster module now passes public_subnet_ids through for public LBs.
…alancer

The controller is no longer a form toggle: it installs when any of the
four load balancer toggles is on, since workload target registration
(TargetGroupBinding) depends on it. lb_controller_enabled now defaults
to false and remains as an advanced-variable opt-in for Ingress-driven
provisioning without shared load balancers. Also merges the two ALB
form sections into one with public/private toggles mirroring the NLB
section, and groups all load balancer fields together after the AWS-API
add-ons.
The controller has no toggle; its chart version field moves next to
deletion protection as 'Load balancer controller chart version'.
A release left in the cluster by a deleted module instance made fresh
installs fail with 'cannot re-use a name that is still in use'. All
addons Helm releases now use upgrade --install semantics so an apply
adopts an existing same-named release instead of erroring.
# Conflicts:
#	Makefile
#	README.md
#	compute/eks/addons/modules/eks_karpenter/README.md
#	compute/eks/modules/eks_cluster/README.md
#	compute/eks/modules/eks_fargate_profile/README.md
#	compute/eks/modules/eks_node_group/README.md
rvn-eks-web, rvn-eks-worker, and rvn-eks-cron could only deploy a
pre-built image, which is the ECS build_source: image_registry path
only. They now offer Dockerfile, Railpack, or registry image, matching
the ECS service family.

Builds need somewhere to push, so compute/eks_service gains an optional
ECR repository gated on ecr_repository_creation_enabled, mirroring
compute/ecs_service. To let worker and cron share that root module, the
load balancer is now gated on a nullable listener_arn via
local.enable_load_balancer, and the target group, listener rule, and
load balancer data sources are counted off it. All load balancer
outputs return null when it is disabled.

Worker and cron were previously deploy-only. They gain a Terraform
stack that creates the ECR repository and nothing else.

Also fixes vpc_id on the workload cluster reference, which read
ref.stack.output.vpc_id and so resolved only after the cluster stack had
applied, leaving the required field empty while adding a workload. It
now reads ref.input.vpc_id, matching ECS.

Adds Terratest coverage for compute/eks_service across the four
configurations: load balancer only, ECR only, both, and repository name
override.
…role

metrics_enabled turns on a Prometheus pipeline that lives entirely in the
customer's account: an Amazon Managed Prometheus workspace (created, or brought
with amp_workspace_id), kube-state-metrics, and a single-replica OpenTelemetry
collector running the ADOT image. The collector scrapes cAdvisor and the
kubelet's resource endpoint through the API server proxy - so it works unchanged
on private-endpoint clusters - plus kube-state-metrics in-cluster, keeps a
curated ~34-family allow-list with a `keep` action in metric_relabel_configs,
and remote-writes the survivors signed with SigV4 through the sigv4auth
extension. Write identity is EKS Pod Identity scoped to aps:RemoteWrite on the
single workspace ARN.

The allow-list is the load-bearing part: AMP bills per sample, so everything
outside locals.metrics_*_allowlist is dropped before it enters collector memory.
cAdvisor's id/name/image labels are dropped, and its empty-container aggregate
rows are dropped for the CPU/memory/OOM families but kept for the network
families, which only exist on those rows.

With metrics on, the amazon-cloudwatch-observability add-on is trimmed to logs
only ({"containerInsights":{"enabled":false},"applicationSignals":{"enabled":
false},"containerLogs":{"enabled":true}}) - the two pipelines measure the same
containers, and the coarser one is the one billed per metric. An explicit
cloudwatch_observability_addon_configuration_values always wins, and a
precondition catches add-on versions older than v6.0.0, whose schema has no such
keys. The log destinations become part of the module contract:
container_log_group, dataplane_log_group, and log_stream_template - which
records that Fluent Bit writes node-first stream names, so a stream prefix
cannot scope to a workload.

grafana_role_enabled adds a read-only role trusted by grafana.amazonaws.com with
an aws:SourceAccount condition: PromQL against the workspace, Logs Insights
against the cluster's log groups. No Grafana workspace is provisioned - that
needs organization-level identity wiring.

Definition YAML gains a "Metrics (Amazon Managed Prometheus)" section and a
0.5.0 release. Tests cover the toggle matrix, allow-list composition, endpoint
derivation, the Container Insights default and its override, and IAM scoping.
Replaces the Container-Insights-logs-only trim from 905cd2f. logs_enabled now
installs Grafana Alloy as a DaemonSet reading every container's stdout off its
own node, and Loki in single-binary mode indexing it with every chunk stored in
an S3 bucket in the customer's account. cloudwatch_observability_enabled flips
to false and stays as a legacy toggle: with Loki for logs and AMP for metrics it
duplicates both halves at CloudWatch prices.

Loki is never exposed — no ingress, no load balancer, not even the chart's nginx
gateway. Ravion reads it by asking Beacon to proxy a query over the WebSocket it
already holds, which is why loki_endpoint is an in-cluster Service URL and why
there is no certificate, no auth layer and no inbound path to open.

The label set is the contract the dashboard's LogQL layer is written against:
namespace, app and workload as labels, level as structured metadata, and
deliberately nothing per-pod — a pod-name label turns one stream per workload
into one per replica per restart. Alloy also drops the filename label
loki.source.file adds, because the path contains the pod UID and would smuggle
the same cardinality back in through the side door.

Retention is enforced twice on purpose. Loki's compactor is the authority
(retention_enabled is off in stock Loki, which is why a Loki bucket usually
grows forever, and why the IAM role carries s3:DeleteObject). The bucket's
lifecycle rule expires a week later, so it never races the compactor into
deleting an index still being read.

Two things found while rendering the charts rather than reading them: with
persistence off the loki chart mounts nothing at /var/loki and the container has
a read-only root filesystem, so Loki cannot write its WAL at all — an emptyDir
now fills that gap; and grafana/grafana on grafana.github.io is deprecated as of
January 2026, so the in-cluster Grafana pulls the maintained chart from
grafana-community instead.

grafana_enabled adds that Grafana, preprovisioned with AMP over SigV4 (its own
Pod Identity role, plus the grafana.ini flag without which SigV4 silently fails)
and Loki over in-cluster HTTP. grafana_role_enabled stays for Amazon Managed
Grafana, which can query AMP but cannot reach a ClusterIP Service.

Beacon's proxy allowlist is wired from this module but the chart has no value
key for it yet — see the PENDING BEACON CHART CONTRACT comment in loki.tf.
tests/logs.tftest.hcl adds the toggle matrix for the logs half: logs off renders
no bucket, no releases and no IAM; a bring-your-own bucket suppresses creation
while every derived value still resolves; retention reaches both the compactor
and the bucket rule; Loki really is single-binary with the caches, gateway and
MinIO off and no static credentials; and the Alloy label contract is asserted
name by name, including the absence of a pod label — that assertion is the point
of the file, because breaking it breaks the dashboard silently and expensively.

tests/metrics.tftest.hcl drops the Container Insights runs and instead asserts
the add-on is off by default.

README gains the Loki/Alloy/S3 and Grafana sections — the label contract, the
two-place retention, why persistence is opt-in, and the split between in-cluster
Grafana and Amazon Managed Grafana — plus updated inputs and outputs tables.
The definition YAML gains Logs and Grafana sections, drops Container Insights to
off, and bumps to 0.6.0.
A map literal in predicate position must be parenthesised; the bare form
threw a syntax error the moment a service set image_pull_secret_names.
@github-actions

github-actions Bot commented Aug 18, 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-aurora 1.2.0 1.2.1 Prevent selecting an older major engine version when updating a database.
rvn-aws-static 1.1.1 1.1.2 Use consistent Dockerfile and builder field names and keep default build policies in advanced builder settings so routine build forms stay focused.
rvn-ec2-service 1.4.1 1.4.2 Use consistent health check and builder field names, keep default build policies in advanced builder settings, and remove contradictory listener-rule guidance.
rvn-ecs-cluster 1.0.1 1.0.2 Clarify ECS cluster labels and identify additional Network Load Balancer security groups in module forms.
rvn-ecs-nlb 1.1.1 1.1.2 Clarify ECS cluster labels, use consistent health check and builder field names, and keep default build policies in advanced builder settings.
rvn-ecs-web 1.1.0 1.1.1 Clarify ECS cluster labels, use consistent routing, health check, and builder field names, add configurable target group deregistration delay, keep default build policies in advanced builder settings, and remove contradictory listener-rule guidance.
rvn-ecs-worker 1.1.0 1.1.1 Clarify ECS cluster labels, use consistent builder field names, and keep default build policies in advanced builder settings.
rvn-eks-addons n/a 0.8.4 Clarify which settings create managed resources and distinguish AWS account records, bucket names, excluded namespaces, and enhanced observability. Configure the default Karpenter NodePool's On-demand and Spot capacity, instance categories, architectures, CPU limit, and node lifetime directly in the module form. Ravion Operator chart 0.4.1, and beacon_image_tag is a plain pin. Every release so far ignored the tag after its first apply (the original "floor, not a pin" design), which froze whatever tag was first applied into the state for good: a cluster once given a since-retired tag was rolled back to it on every upgrade and wedged when that image could not start. Now the pin is asserted for exactly as long as it is configured and removing it hands the version back to the control plane on the next apply. The 0.4.1 chart preserves the running image whole (registry included, so a stale image.repository in beacon_helm_values no longer re-renders a tag that registry never held) and only when the release's rollout has settled; a wedged release takes the chart's floor, so a plain re-apply repairs it. If your instance has beacon_image_tag or an image.repository override in its advanced variables from before 0.8.0, remove both when upgrading. Previously (0.8.3): Ravion Operator chart 0.4.0 - an add-ons apply no longer moves the agent version; the chart re-emits the running image on every helm upgrade, and gains httpProxy.credentials for rendering Grafana Cloud and in-cluster Prometheus through the agent. Previously (0.8.2): the pre-0.8.0 logs_enabled / metrics_enabled / cloudwatch_observability_enabled Terraform variables are gone; the provider lists are the only switch. An instance still on 0.7.x should upgrade to 0.8.1 first, which is what reads them. Form guidance now uses concise, field-specific instructions and documents accepted version, duration, storage, endpoint, and credential formats. Shared load balancer settings now appear directly below Ravion EKS Management. User-facing module text and form field IDs now use the Ravion Operator name. New configurations enable Ravion Operator, operator-run deployments, and the public Application Load Balancer by default. Default NodePool creation and log retention now stay collapsed until customized. Load balancer, Loki, AMP, and metrics credential fields now use names that reflect their exact scope.
rvn-eks-cluster n/a 0.2.0 Configure default and additional capacity together with a ten-node scaling ceiling, manage API endpoint and IAM access together, define Fargate profiles and cluster access entries with guided forms instead of raw JSON, use consistent endpoint and control-plane logging field names, clarify node group and controller settings, keep the Ravion Runner role in advanced settings, manage the Ravion Runner security group automatically, prevent Kubernetes version downgrades, and remove empty Container Insights charts from the cluster Metrics tab.
rvn-eks-web n/a 1.0.0 Simplify health configuration and form layout, use consistent routing, scaling, release, and builder field names, clarify target group and ECR settings, keep default build policies in advanced settings, and let workloads target automatic, EC2 on-demand, EC2 Spot, or on-demand Fargate compute.
rvn-eks-worker n/a 0.4.0 Follow the selected observability providers, group add-ons with cluster selection, use consistent scaling, release, and builder field names, clarify ECR settings, keep default build policies in advanced settings, and let workloads target automatic, EC2 on-demand, EC2 Spot, or on-demand Fargate compute.
rvn-lambda 1.1.0 1.1.1 Use consistent Dockerfile and builder field names and keep default build policies in advanced builder settings so routine build forms stay focused.
rvn-rds 1.2.0 1.2.1 Allow major engine upgrades while preventing selection of an older major version.

Diffs

rvn-aurora 1.2.0 -> 1.2.1

--- remote
+++ compiled
   - description: "Examples: 16 for Aurora PostgreSQL or 8.0 for Aurora MySQL."
     id: engine_major_version
     label: Engine major version
+    min_current_value: true
     placeholder: "16"
     required: true
     type: string
@@
   - [Aurora Serverless v2](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.html)
   - [Aurora global databases](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-global-database.html)
   - [Aurora monitoring](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/CHAP_Monitoring.html)
-  - [Terraform source](https://github.com/ravionhq/modules/tree/rvn-aurora@1.2.0/database/aurora)
+  - [Terraform source](https://github.com/ravionhq/modules/tree/rvn-aurora@1.2.1/database/aurora)
 stack:
   pipelines:
     change:
@@
         base_path: database/aurora
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-aurora@1.2.0
+        ref: rvn-aurora@1.2.1
         repo: https://github.com/ravionhq/modules
         stack_id: <<stack.id>>
         terraform_variables:

rvn-aws-static 1.1.1 -> 1.1.2

--- remote
+++ compiled
 build:
-  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_inject_env_variables, output_directory: module.input.output_directory} : (module.input.build_source == "railpack" || module.input.build_source == "nixpacks") ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, output_directory: module.input.output_directory} : {type: "disabled"} >>'
+  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_environment_variable_injection_enabled, output_directory: module.input.output_directory} : (module.input.build_source == "railpack" || module.input.build_source == "nixpacks") ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, output_directory: module.input.output_directory} : {type: "disabled"} >>'
   destinations:
     - bucket: << stack.output.hosting_bucket_id >>
       id: hosting-bucket
@@
       type: s3
   environment_variables: << module.input.build_environment_variables >>
   infrastructure:
-    ami: << module.input.build_ami || nil >>
+    ami: << module.input.build_ami_id || nil >>
     aws_account_id: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_account_id >>"
     execution_environment_id: << module.input.build_execution_environment_id || module.input.execution_environment_id >>
-    instance_size: << module.input.build_instance_size >>
+    instance_size: << module.input.build_instance_type >>
     permissions: '<< module.input.build_iam_policy_arns ? (module.input.build_default_policies_enabled ? {"attach": module.input.build_iam_policy_arns} : {"replace": module.input.build_iam_policy_arns}) : nil >>'
     region: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_region >>"
-    type: << module.input.build_infrastructure_type >>
+    type: << module.input.build_capacity_type >>
   inputs:
     - description: Defaults to repo default branch
       id: branch
@@
     type: object
   - default: false
     description: Pass build environment variables into Dockerfile builds as build arguments.
-    id: dockerfile_inject_env_variables
+    id: dockerfile_environment_variable_injection_enabled
     label: Inject environment variables in Dockerfile
     show_when:
       build_source: dockerfile
@@
     type: section
   - default: ec2
     description: Use on-demand EC2 for predictable availability or EC2 Spot for lower cost with possible capacity delays or interruption.
-    id: build_infrastructure_type
-    label: Builder instance type
+    id: build_capacity_type
+    label: Builder capacity type
     required: true
     show_when:
       build_source:
@@
         value: ec2-spot
   - default: c7a.4xlarge
     description: EC2 instance type for builds. Start with the default value, then increase or decrease it based on the resource usage report at the end of builds.
-    id: build_instance_size
-    label: Builder instance size
+    id: build_instance_type
+    label: Builder instance type
     no_options_message: Select an AWS account and region to load available EC2 instance types.
     required: true
     show_when:
@@
     values: $values:ravion/execution_environments
   - collapsible: true
     description: Optional AMI ID for build runners. Leave empty to use the default runner image.
-    id: build_ami
+    id: build_ami_id
     label: Builder AMI
     required: false
     show_when:
@@
         - railpack
         - nixpacks
     type: string
-  - default: true
+  - collapsible: true
+    default: true
     description: The step's built-in policies (ECR/S3 access, CloudWatch agent) stay attached alongside your Builder IAM policies. Turn off to run the build with only the policies listed below.
     id: build_default_policies_enabled
     label: Include default build policies
@@
 
   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: [ravionhq/modules/hosting/static_site](https://github.com/ravionhq/modules/tree/rvn-aws-static@1.1.1/hosting/static_site)
+  Terraform source: [ravionhq/modules/hosting/static_site](https://github.com/ravionhq/modules/tree/rvn-aws-static@1.1.2/hosting/static_site)
 
   ## Use cases
 
@@
         base_path: hosting/static_site
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-aws-static@1.1.1
+        ref: rvn-aws-static@1.1.2
         repo: https://github.com/ravionhq/modules
         stack_id: <<stack.id>>
         terraform_variables:

rvn-ec2-service 1.4.1 -> 1.4.2

--- remote
+++ compiled
 build:
-  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_inject_env_variables, cache_from: {tag: "dockerfile"}} : (module.input.build_source == "railpack" || module.input.build_source == "nixpacks") ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, start_cmd: module.input.railpack_start_cmd, cache_from: {tag: "railpack"}} : {type: "disabled"} >>'
+  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_environment_variable_injection_enabled, cache_from: {tag: "dockerfile"}} : (module.input.build_source == "railpack" || module.input.build_source == "nixpacks") ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, start_cmd: module.input.railpack_start_cmd, cache_from: {tag: "railpack"}} : {type: "disabled"} >>'
   destinations:
     - id: ecr
       repository_arn: << stack.output.ecr_repository_arn >>
@@
       type: ecr
   environment_variables: << module.input.build_environment_variables >>
   infrastructure:
-    ami: << module.input.build_ami || nil >>
+    ami: << module.input.build_ami_id || nil >>
     aws_account_id: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_account_id >>"
     execution_environment_id: << module.input.build_execution_environment_id || module.input.execution_environment_id >>
-    instance_size: << module.input.build_instance_size >>
+    instance_size: << module.input.build_instance_type >>
     permissions: '<< module.input.build_iam_policy_arns ? (module.input.build_default_policies_enabled ? {"attach": module.input.build_iam_policy_arns} : {"replace": module.input.build_iam_policy_arns}) : nil >>'
     region: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_region >>"
-    type: << module.input.build_infrastructure_type >>
+    type: << module.input.build_capacity_type >>
   inputs:
     - description: Defaults to repo default branch
       id: branch
@@
     show_when:
       http_traffic_enabled: true
     type: number
-  - description: Add at least one domain host rule or path rule.
-    id: section_routing
+  - id: section_routing
     label: HTTP listener rules
     show_when:
       http_traffic_enabled: true
@@
   - collapsible: true
     default: 2
     description: Consecutive successful ALB checks required before an instance is healthy.
-    id: healthy_threshold
+    id: health_check_healthy_threshold
     label: Healthy threshold
     max: 10
     min: 2
@@
   - collapsible: true
     default: 2
     description: Consecutive failed ALB checks required before an instance is unhealthy.
-    id: unhealthy_threshold
+    id: health_check_unhealthy_threshold
     label: Unhealthy threshold
     max: 10
     min: 2
@@
     type: object
   - default: false
     description: Pass build environment variables into Dockerfile builds as build arguments.
-    id: dockerfile_inject_env_variables
+    id: dockerfile_environment_variable_injection_enabled
     label: Inject environment variables in Dockerfile
     show_when:
       build_source: dockerfile
@@
     type: section
   - default: ec2
     description: Use on-demand EC2 for predictable availability or EC2 Spot for lower cost with possible capacity delays or interruption.
-    id: build_infrastructure_type
-    label: Builder instance type
+    id: build_capacity_type
+    label: Builder capacity type
     required: true
     show_when:
       build_source:
@@
         value: ec2-spot
   - default: c7a.4xlarge
     description: EC2 instance type for builds. Start with the default value, then increase or decrease it based on the resource usage report at the end of builds.
-    id: build_instance_size
-    label: Builder instance size
+    id: build_instance_type
+    label: Builder instance type
     no_options_message: Select a VPC Network, or enter an AWS account and region, to load available EC2 instance types.
     required: true
     show_when:
@@
     values: $values:ravion/execution_environments
   - collapsible: true
     description: Optional AMI ID for build runners. Leave empty to use the default runner image.
-    id: build_ami
+    id: build_ami_id
     label: Builder AMI
     required: false
     show_when:
@@
         - railpack
       deploy_type: container
     type: string
-  - default: true
+  - collapsible: true
+    default: true
     description: The step's built-in policies (ECR/S3 access, CloudWatch agent) stay attached alongside your Builder IAM policies. Turn off to run the build with only the policies listed below.
     id: build_default_policies_enabled
     label: Include default build policies
@@
 
   Instances are as stable as an EC2 instance you launch yourself in the AWS console. Deploys, app restarts, and stack updates do not replace them, so each instance keeps its root and optional data volume, and everything on those disks, for its whole life. Even changing the AMI leaves running instances alone: the change becomes a new launch template version that only applies to instances launched later, because the module does not run an instance refresh. An instance is replaced when you deliberately terminate or recycle it, for example to roll out that new AMI, when the group scales in, or when it fails its Auto Scaling health check (EC2 by default, or load balancer health when `health_check_type` is set to `ELB`). Replacement is what destroys the volumes, so take regular EBS snapshots or back up off-instance if critical data lives on the disk.
 
-  Terraform source: [ravionhq/modules/compute/ec2_service](https://github.com/ravionhq/modules/tree/rvn-ec2-service@1.4.1/compute/ec2_service)
+  Terraform source: [ravionhq/modules/compute/ec2_service](https://github.com/ravionhq/modules/tree/rvn-ec2-service@1.4.2/compute/ec2_service)
 
   ## Use cases
 
@@
         base_path: compute/ec2_service
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-ec2-service@1.4.1
+        ref: rvn-ec2-service@1.4.2
         repo: https://github.com/ravionhq/modules
         stack_id: <<stack.id>>
         terraform_variables:
@@
               deregistration_delay: << module.input.deregistration_delay >>
               health_check:
                 enabled: true
-                healthy_threshold: << module.input.healthy_threshold >>
+                healthy_threshold: << module.input.health_check_healthy_threshold >>
                 interval: << module.input.health_check_interval >>
                 matcher: << module.input.health_check_matcher >>
                 path: << module.input.health_check_path >>
                 timeout: << module.input.health_check_timeout >>
-                unhealthy_threshold: << module.input.unhealthy_threshold >>
+                unhealthy_threshold: << module.input.health_check_unhealthy_threshold >>
               port: << module.input.app_port >>
               slow_start: << module.input.target_group_slow_start >>
               stickiness: |-

rvn-ecs-cluster 1.0.1 -> 1.0.2

--- remote
+++ compiled
     description: Name prefix for all resources. Terraform requires 1-28 characters so generated ALB names fit AWS limits.
     id: name
     immutable: true
-    label: Name slug
+    label: ECS cluster name
     patterns:
       - message: The name must be 1-28 characters, contain only lowercase letters, numbers, and hyphens, and start and end with a letter or number.
         pattern: ^[a-z0-9]([a-z0-9-]{0,26}[a-z0-9])?$
@@
     type: boolean
   - add_button_label: Add security group ID
     collapsible: true
-    description: Security groups for the public NLB.
-    id: public_nlb_security_group_ids
-    label: Security groups
+    description: Additional security groups for the public NLB.
+    id: public_nlb_additional_security_group_ids
+    label: Additional security groups
     placeholder: sg-...
     show_when:
       public_nlb_enabled: true
@@
     type: boolean
   - add_button_label: Add security group ID
     collapsible: true
-    description: Security groups for the private NLB.
-    id: private_nlb_security_group_ids
-    label: Security groups
+    description: Additional security groups for the private NLB.
+    id: private_nlb_additional_security_group_ids
+    label: Additional security groups
     placeholder: sg-...
     show_when:
       private_nlb_enabled: true
@@
   - **Public and private Network Load Balancers** for TCP/UDP and static IP use cases
   - **CloudWatch Container Insights** dashboard metrics for production visibility
 
-  Terraform source: [ravionhq/modules/compute/ecs_cluster](https://github.com/ravionhq/modules/tree/rvn-ecs-cluster@1.0.1/compute/ecs_cluster)
+  Terraform source: [ravionhq/modules/compute/ecs_cluster](https://github.com/ravionhq/modules/tree/rvn-ecs-cluster@1.0.2/compute/ecs_cluster)
 
   ## Use cases
 
@@
   | Field                 | Required | Default              | Description                                                   |
   | --------------------- | -------- | -------------------- | ------------------------------------------------------------- |
   | VPC network           | Yes      | —                    | Existing VPC, subnets, AWS account, and region                |
-  | Name slug             | Yes      | `{project}-{env}`    | Name prefix for ECS and load balancer resources               |
+  | ECS cluster name      | Yes      | `{project}-{env}`    | Name prefix for ECS and load balancer resources               |
   | Container insights    | No       | `enhanced`           | Collect enhanced task, service, cluster, and EC2 metrics in CloudWatch |
   | Fargate               | No       | `true`               | Allow services to use Fargate capacity                        |
   | Fargate Spot          | No       | `true`               | Allow services to use lower-cost interruptible Fargate Spot   |
@@
         base_path: compute/ecs_cluster
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-ecs-cluster@1.0.1
+        ref: rvn-ecs-cluster@1.0.2
         repo: https://github.com/ravionhq/modules
         stack_id: <<stack.id>>
         terraform_variables:
@@
           private_nlb_elastic_ip_allocation_ids: << module.input.private_nlb_elastic_ip_allocation_ids >>
           private_nlb_elastic_ips_enabled: << module.input.private_nlb_elastic_ips_enabled >>
           private_nlb_enabled: << module.input.private_nlb_enabled >>
-          private_nlb_security_group_ids: << module.input.private_nlb_security_group_ids >>
+          private_nlb_security_group_ids: << module.input.private_nlb_additional_security_group_ids >>
           private_subnet_ids: << module.input.private_subnet_ids >>
           public_alb_access_logs_bucket_arn: << module.input.public_alb_access_logs_bucket_arn >>
           public_alb_access_logs_enabled: << module.input.public_alb_access_logs_enabled >>
@@
           public_nlb_elastic_ip_allocation_ids: << module.input.public_nlb_elastic_ip_allocation_ids >>
           public_nlb_elastic_ips_enabled: << module.input.public_nlb_elastic_ips_enabled >>
           public_nlb_enabled: << module.input.public_nlb_enabled >>
-          public_nlb_security_group_ids: << module.input.public_nlb_security_group_ids >>
+          public_nlb_security_group_ids: << module.input.public_nlb_additional_security_group_ids >>
           public_subnet_ids: << module.input.public_subnet_ids || [] >>
           region: << module.input.aws_region >>
           tags:

rvn-ecs-nlb 1.1.1 -> 1.1.2

--- remote
+++ compiled
 build:
-  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_inject_env_variables, cache_from: {tag: "dockerfile"}} : (module.input.build_source == "railpack" || module.input.build_source == "nixpacks") ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, start_cmd: module.input.railpack_start_cmd, cache_from: {tag: "railpack"}} : {type: "disabled"} >>'
+  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_environment_variable_injection_enabled, cache_from: {tag: "dockerfile"}} : (module.input.build_source == "railpack" || module.input.build_source == "nixpacks") ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, start_cmd: module.input.railpack_start_cmd, cache_from: {tag: "railpack"}} : {type: "disabled"} >>'
   destinations:
     - id: ecr
       repository_arn: << stack.output.ecr_repository_arn >>
@@
       type: ecr
   environment_variables: << module.input.build_environment_variables >>
   infrastructure:
-    ami: << module.input.build_ami || nil >>
+    ami: << module.input.build_ami_id || nil >>
     aws_account_id: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_account_id >>"
     execution_environment_id: << module.input.build_execution_environment_id || module.input.execution_environment_id >>
-    instance_size: << module.input.build_instance_size >>
+    instance_size: << module.input.build_instance_type >>
     permissions: '<< module.input.build_iam_policy_arns ? (module.input.build_default_policies_enabled ? {"attach": module.input.build_iam_policy_arns} : {"replace": module.input.build_iam_policy_arns}) : nil >>'
     region: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_region >>"
-    type: << module.input.build_infrastructure_type >>
+    type: << module.input.build_capacity_type >>
   inputs:
     - description: Defaults to repo default branch
       id: branch
@@
     type: section
   - id: cluster
     immutable: true
-    label: ECS cluster
+    label: Cluster
     mapped_inputs:
       - default: <<ref.input.aws_account_id>>
         id: aws_account_id
@@
   - collapsible: true
     default: 3
     description: Number of consecutive successful checks required before an unhealthy target is considered healthy.
-    id: healthy_threshold
+    id: health_check_healthy_threshold
     label: Healthy threshold
     max: 10
     min: 2
@@
   - collapsible: true
     default: 3
     description: Number of consecutive failed checks required before a target is considered unhealthy.
-    id: unhealthy_threshold
+    id: health_check_unhealthy_threshold
     label: Unhealthy threshold
     max: 10
     min: 2
@@
     type: object
   - default: false
     description: Pass build environment variables into Dockerfile builds as build arguments.
-    id: dockerfile_inject_env_variables
+    id: dockerfile_environment_variable_injection_enabled
     label: Inject environment variables in Dockerfile
     show_when:
       build_source: dockerfile
@@
     type: section
   - default: ec2
     description: Use on-demand EC2 for predictable availability or EC2 Spot for lower cost with possible capacity delays or interruption.
-    id: build_infrastructure_type
-    label: Builder instance type
+    id: build_capacity_type
+    label: Builder capacity type
     required: true
     show_when:
       build_source:
@@
         value: ec2-spot
   - default: c7a.4xlarge
     description: EC2 instance type for builds. Start with the default value, then increase or decrease it based on the resource usage report at the end of builds.
-    id: build_instance_size
-    label: Builder instance size
+    id: build_instance_type
+    label: Builder instance type
     no_options_message: Select a VPC Network, or enter an AWS account and region, to load available EC2 instance types.
     required: true
     show_when:
@@
     values: $values:ravion/execution_environments
   - collapsible: true
     description: Optional AMI ID for build runners. Leave empty to use the default runner image.
-    id: build_ami
+    id: build_ami_id
     label: Builder AMI
     required: false
     show_when:
@@
         - railpack
         - nixpacks
     type: string
-  - default: true
+  - collapsible: true
+    default: true
     description: The step's built-in policies (ECR/S3 access, CloudWatch agent) stay attached alongside your Builder IAM policies. Turn off to run the build with only the policies listed below.
     id: build_default_policies_enabled
     label: Include default build policies
@@
 
   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: [ravionhq/modules/compute/ecs_service](https://github.com/ravionhq/modules/tree/rvn-ecs-nlb@1.1.1/compute/ecs_service)
+  Terraform source: [ravionhq/modules/compute/ecs_service](https://github.com/ravionhq/modules/tree/rvn-ecs-nlb@1.1.2/compute/ecs_service)
 
   ## Use cases
 
@@
 
   | Field                            | Required | Default                  | Description                                      |
   | -------------------------------- | -------- | ------------------------ | ------------------------------------------------ |
-  | ECS cluster                      | Yes      | -                        | Existing rvn-ecs-cluster module instance         |
+  | Cluster                          | Yes      | -                        | Existing rvn-ecs-cluster module instance         |
   | Service name                     | Yes      | {project}-{env}-{module} | Name for the ECS service and related resources   |
   | Public network service           | No       | true                     | Use the public NLB; turn off for the private NLB |
   | Run in private subnets           | No       | true                     | Run tasks in private subnets without public IPs  |
@@
         base_path: compute/ecs_service
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-ecs-nlb@1.1.1
+        ref: rvn-ecs-nlb@1.1.2
         repo: https://github.com/ravionhq/modules
         stack_id: <<stack.id>>
         terraform_variables:
@@
               deregistration_delay: << module.input.deregistration_delay >>
               health_check:
                 enabled: true
-                healthy_threshold: << module.input.healthy_threshold >>
+                healthy_threshold: << module.input.health_check_healthy_threshold >>
                 interval: << module.input.health_check_interval >>
                 matcher: '<< module.input.health_check_protocol == "HTTP" || module.input.health_check_protocol == "HTTPS" ? module.input.health_check_matcher : nil >>'
                 path: '<< module.input.health_check_protocol == "HTTP" || module.input.health_check_protocol == "HTTPS" ? module.input.health_check_path : nil >>'
                 port: traffic-port
                 protocol: << module.input.health_check_protocol >>
                 timeout: << module.input.health_check_timeout >>
-                unhealthy_threshold: << module.input.unhealthy_threshold >>
+                unhealthy_threshold: << module.input.health_check_unhealthy_threshold >>
               port: << module.input.listeners[0].container_port >>
               protocol: '<< module.input.listeners[0].listener_protocol == "TLS" ? module.input.listeners[0].tls_target_protocol : module.input.listeners[0].listener_protocol >>'
               stickiness:

rvn-ecs-web 1.1.0 -> 1.1.1

--- remote
+++ compiled
 build:
-  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_inject_env_variables, cache_from: {tag: "dockerfile"}} : (module.input.build_source == "railpack" || module.input.build_source == "nixpacks") ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, start_cmd: module.input.railpack_start_cmd, cache_from: {tag: "railpack"}} : {type: "disabled"} >>'
+  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_environment_variable_injection_enabled, cache_from: {tag: "dockerfile"}} : (module.input.build_source == "railpack" || module.input.build_source == "nixpacks") ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, start_cmd: module.input.railpack_start_cmd, cache_from: {tag: "railpack"}} : {type: "disabled"} >>'
   destinations:
     - id: ecr
       repository_arn: << stack.output.ecr_repository_arn >>
@@
       type: ecr
   environment_variables: << module.input.build_environment_variables >>
   infrastructure:
-    ami: << module.input.build_ami || nil >>
+    ami: << module.input.build_ami_id || nil >>
     aws_account_id: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_account_id >>"
     execution_environment_id: << module.input.build_execution_environment_id || module.input.execution_environment_id >>
-    instance_size: << module.input.build_instance_size >>
+    instance_size: << module.input.build_instance_type >>
     permissions: '<< module.input.build_iam_policy_arns ? (module.input.build_default_policies_enabled ? {"attach": module.input.build_iam_policy_arns} : {"replace": module.input.build_iam_policy_arns}) : nil >>'
     region: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_region >>"
-    type: << module.input.build_infrastructure_type >>
+    type: << module.input.build_capacity_type >>
   inputs:
     - description: Defaults to repo default branch
       id: branch
@@
     type: section
   - id: cluster
     immutable: true
-    label: ECS cluster
+    label: Cluster
     mapped_inputs:
       - default: <<ref.input.aws_account_id>>
         id: aws_account_id
@@
     type: string
   - default: true
     description: Expose this service through the public ALB. Turn off to use the private ALB.
-    id: public_web_service_enabled
+    id: public_alb_routing_enabled
     label: Public web service
     type: boolean
   - default: true
@@
   - collapsible: true
     default: 2
     description: Number of consecutive successful checks required before an unhealthy target is considered healthy.
-    id: healthy_threshold
+    id: health_check_healthy_threshold
     label: Healthy threshold
     max: 10
     min: 2
@@
   - collapsible: true
     default: 2
     description: Number of consecutive failed checks required before a target is considered unhealthy.
-    id: unhealthy_threshold
+    id: health_check_unhealthy_threshold
     label: Unhealthy threshold
     max: 10
     min: 2
@@
     min: 0
     type: number
   - collapsible: true
+    default: 300
+    description: Seconds the load balancer allows in-flight requests to complete after a task starts deregistering.
+    id: target_group_deregistration_delay
+    label: Deregistration delay (secs)
+    max: 3600
+    min: 0
+    type: number
+  - collapsible: true
     default: 0
     description: Gradually ramps traffic to newly registered targets. Use 0 to disable.
     id: target_group_slow_start
@@
     show_when:
       target_group_stickiness_type: app_cookie
     type: string
-  - description: Add at least one domain host rule or path rule.
-    id: section_routing
+  - id: section_routing
     label: HTTP listener rules
     type: section
   - add_button_label: Add domain host
@@
     type: object
   - default: false
     description: Pass build environment variables into Dockerfile builds as build arguments.
-    id: dockerfile_inject_env_variables
+    id: dockerfile_environment_variable_injection_enabled
     label: Inject environment variables in Dockerfile
     show_when:
       build_source: dockerfile
@@
     type: section
   - default: ec2
     description: Use on-demand EC2 for predictable availability or EC2 Spot for lower cost with possible capacity delays or interruption.
-    id: build_infrastructure_type
-    label: Builder instance type
+    id: build_capacity_type
+    label: Builder capacity type
     required: true
     show_when:
       build_source:
@@
         value: ec2-spot
   - default: c7a.4xlarge
     description: EC2 instance type for builds. Start with the default value, then increase or decrease it based on the resource usage report at the end of builds.
-    id: build_instance_size
-    label: Builder instance size
+    id: build_instance_type
+    label: Builder instance type
     no_options_message: Select a VPC Network, or enter an AWS account and region, to load available EC2 instance types.
     required: true
     show_when:
@@
     values: $values:ravion/execution_environments
   - collapsible: true
     description: Optional AMI ID for build runners. Leave empty to use the default runner image.
-    id: build_ami
+    id: build_ami_id
     label: Builder AMI
     required: false
     show_when:
@@
         - railpack
         - nixpacks
     type: string
-  - default: true
+  - collapsible: true
+    default: true
     description: The step's built-in policies (ECR/S3 access, CloudWatch agent) stay attached alongside your Builder IAM policies. Turn off to run the build with only the policies listed below.
     id: build_default_policies_enabled
     label: Include default build policies
@@
 
   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: [ravionhq/modules/compute/ecs_service](https://github.com/ravionhq/modules/tree/rvn-ecs-web@1.1.0/compute/ecs_service)
+  Terraform source: [ravionhq/modules/compute/ecs_service](https://github.com/ravionhq/modules/tree/rvn-ecs-web@1.1.1/compute/ecs_service)
 
   ## Use cases
 
@@
   | Healthy threshold                | 2       | Successful checks needed to mark a target healthy              |
   | Unhealthy threshold              | 2       | Failed checks needed to mark a target unhealthy                |
   | Health check grace period (secs) | 0       | Startup window where ECS ignores load balancer health failures |
+  | Deregistration delay (secs)      | 300     | Drain window for a task that is deregistering                   |
 
   Increase the grace period for apps with slow boot times. Keep health check endpoints lightweight and unauthenticated.
 
@@
   | Public web service              | No       | true                       | Use the public ALB; turn off for the private ALB   |
   | Run in private subnets          | No       | true                       | Run tasks in private subnets without public IPs    |
   | Service name                    | Yes      | {project}-{env}-{module}   | Name for the ECS service and related resources     |
-  | ECS cluster                     | Yes      | -                          | Existing rvn-ecs-cluster module instance           |
+  | Cluster                         | Yes      | -                          | Existing rvn-ecs-cluster module instance           |
   | Build source                    | Yes      | dockerfile                 | Dockerfile, Railpack, Pull from image registry, or Disabled |
   | Git repository                  | Yes*     | -                          | Required for Railpack and Dockerfile builds |
   | Git branch                      | Yes*     | -                          | Required for Railpack and Dockerfile builds |
@@
   | Start command                   | No       | []                         | Command arguments that override an image default CMD |
   | Container port                  | Yes      | 80                         | Port exposed by the app container                  |
   | Health check path               | Yes      | /                          | HTTP path used by the target group health check    |
+  | Deregistration delay (secs)     | No       | 300                        | Drain window for a task that is deregistering      |
   | Sticky sessions                 | No       | true                       | Keep clients on the same task, and on the same traffic-shift target group when enabled |
   | Domain host rules               | No       | -                          | Hostnames such as app.example.com or *.example.com |
   | Path rules                      | No       | -                          | Path patterns such as /*, /api/*, or /app/*        |
@@
         base_path: compute/ecs_service
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-ecs-web@1.1.0
+        ref: rvn-ecs-web@1.1.1
         repo: https://github.com/ravionhq/modules
         stack_id: <<stack.id>>
         terraform_variables:
@@
               - conditions:
                   - '...<< module.input.host_header_values != nil && module.input.host_header_values != [] ? [{type: "host-header", values: module.input.host_header_values}] : [] >>'
                   - '...<< module.input.path_pattern_values != nil && module.input.path_pattern_values != [] ? [{type: "path-pattern", values: module.input.path_pattern_values}] : module.input.host_header_values != nil && module.input.host_header_values != [] ? [] : [{type: "path-pattern", values: ["/*"]}] >>'
-                listener_arn: "<< module.input.public_web_service_enabled ? (module.input.public_alb_https_listener_arn || module.input.public_alb_http_listener_arn) : (module.input.private_alb_https_listener_arn || module.input.private_alb_http_listener_arn) >>"
+                listener_arn: "<< module.input.public_alb_routing_enabled ? (module.input.public_alb_https_listener_arn || module.input.public_alb_http_listener_arn) : (module.input.private_alb_https_listener_arn || module.input.private_alb_http_listener_arn) >>"
                 priority: << module.input.listener_rule_priority >>
             target_group:
+              deregistration_delay: << module.input.target_group_deregistration_delay >>
               health_check:
                 enabled: true
-                healthy_threshold: << module.input.healthy_threshold >>
+                healthy_threshold: << module.input.health_check_healthy_threshold >>
                 interval: << module.input.health_check_interval >>
                 matcher: << module.input.health_check_matcher >>
                 path: << module.input.health_check_path >>
                 timeout: << module.input.health_check_timeout >>
-                unhealthy_threshold: << module.input.unhealthy_threshold >>
+                unhealthy_threshold: << module.input.health_check_unhealthy_threshold >>
               port: << module.input.container_port >>
               protocol: HTTP
               slow_start: << module.input.target_group_slow_start >>
@@
                 enabled: << module.input.target_group_stickiness_enabled >>
                 type: '<< module.input.target_group_stickiness_enabled ? module.input.target_group_stickiness_type : "lb_cookie"
... diff truncated ...

rvn-ecs-worker 1.1.0 -> 1.1.1

--- remote
+++ compiled
 build:
-  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_inject_env_variables, cache_from: {tag: "dockerfile"}} : (module.input.build_source == "railpack" || module.input.build_source == "nixpacks") ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, start_cmd: module.input.railpack_start_cmd, cache_from: {tag: "railpack"}} : {type: "disabled"} >>'
+  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_environment_variable_injection_enabled, cache_from: {tag: "dockerfile"}} : (module.input.build_source == "railpack" || module.input.build_source == "nixpacks") ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, start_cmd: module.input.railpack_start_cmd, cache_from: {tag: "railpack"}} : {type: "disabled"} >>'
   destinations:
     - id: ecr
       repository_arn: << stack.output.ecr_repository_arn >>
@@
       type: ecr
   environment_variables: << module.input.build_environment_variables >>
   infrastructure:
-    ami: << module.input.build_ami || nil >>
+    ami: << module.input.build_ami_id || nil >>
     aws_account_id: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_account_id >>"
     execution_environment_id: << module.input.build_execution_environment_id || module.input.execution_environment_id >>
-    instance_size: << module.input.build_instance_size >>
+    instance_size: << module.input.build_instance_type >>
     permissions: '<< module.input.build_iam_policy_arns ? (module.input.build_default_policies_enabled ? {"attach": module.input.build_iam_policy_arns} : {"replace": module.input.build_iam_policy_arns}) : nil >>'
     region: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_region >>"
-    type: << module.input.build_infrastructure_type >>
+    type: << module.input.build_capacity_type >>
   inputs:
     - description: Defaults to repo default branch
       id: branch
@@
     type: section
   - id: cluster
     immutable: true
-    label: ECS cluster
+    label: Cluster
     mapped_inputs:
       - default: <<ref.input.aws_account_id>>
         id: aws_account_id
@@
     type: object
   - default: false
     description: Pass build environment variables into Dockerfile builds as build arguments.
-    id: dockerfile_inject_env_variables
+    id: dockerfile_environment_variable_injection_enabled
     label: Inject environment variables in Dockerfile
     show_when:
       build_source: dockerfile
@@
     type: section
   - default: ec2
     description: Use on-demand EC2 for predictable availability or EC2 Spot for lower cost with possible capacity delays or interruption.
-    id: build_infrastructure_type
-    label: Builder instance type
+    id: build_capacity_type
+    label: Builder capacity type
     required: true
     show_when:
       build_source:
@@
         value: ec2-spot
   - default: c7a.4xlarge
     description: EC2 instance type for builds. Start with the default value, then increase or decrease it based on the resource usage report at the end of builds.
-    id: build_instance_size
-    label: Builder instance size
+    id: build_instance_type
+    label: Builder instance type
     no_options_message: Select a VPC Network, or enter an AWS account and region, to load available EC2 instance types.
     required: true
     show_when:
@@
     values: $values:ravion/execution_environments
   - collapsible: true
     description: Optional AMI ID for build runners. Leave empty to use the default runner image.
-    id: build_ami
+    id: build_ami_id
     label: Builder AMI
     required: false
     show_when:
@@
         - railpack
         - nixpacks
     type: string
-  - default: true
+  - collapsible: true
+    default: true
     description: The step's built-in policies (ECR/S3 access, CloudWatch agent) stay attached alongside your Builder IAM policies. Turn off to run the build with only the policies listed below.
     id: build_default_policies_enabled
     label: Include default build policies
@@
 
   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: [ravionhq/modules/compute/ecs_service](https://github.com/ravionhq/modules/tree/rvn-ecs-worker@1.1.0/compute/ecs_service)
+  Terraform source: [ravionhq/modules/compute/ecs_service](https://github.com/ravionhq/modules/tree/rvn-ecs-worker@1.1.1/compute/ecs_service)
 
   ## Use cases
 
@@
 
   | Field | Required | Default | Description |
   | ----- | -------- | ------- | ----------- |
-  | ECS cluster | Yes | - | Existing rvn-ecs-cluster module instance |
+  | Cluster | Yes | - | Existing rvn-ecs-cluster module instance |
   | Service name | Yes | {project}-{env}-{module} | Name for the ECS service and related resources |
   | Run in private subnets | No | true | Run tasks in private subnets without public IPs |
   | Build source | Yes | dockerfile | Dockerfile, Railpack, or Pull from image registry |
@@
         base_path: compute/ecs_service
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-ecs-worker@1.1.0
+        ref: rvn-ecs-worker@1.1.1
         repo: https://github.com/ravionhq/modules
         stack_id: <<stack.id>>
         terraform_variables:

rvn-eks-addons n/a -> 0.8.4

--- remote
+++ compiled
-
+description: Selectable add-ons for an existing EKS cluster - Karpenter autoscaling, the AWS Load Balancer Controller, the External Secrets Operator, EBS CSI storage, workload logs and metrics shipped to any combination of destinations (an in-cluster log store on S3 and Amazon Managed Prometheus by default; CloudWatch, Grafana Cloud, Datadog, New Relic or a custom OTLP endpoint on request), Ravion EKS Management via the in-cluster Ravion Operator, and shared application/network load balancers, each toggled and configured independently.
+name: EKS Add-ons
+type: rvn-eks-addons

rvn-eks-addons n/a -> 0.8.4

--- remote
+++ compiled
+inputs:
+  - id: cluster
+    immutable: true
+    label: EKS cluster
+    mapped_inputs:
+      - id: section_aws
+        label: AWS account & region
+        type: section
+      - default: << ref.input.aws_account_id >>
+        id: aws_account_id
+        immutable: true
+        label: AWS account
+        type: string
+        values: $values:ravion/aws_accounts
+      - default: << ref.input.aws_region >>
+        id: aws_region
+        immutable: true
+        label: Region
+        type: string
+        values: $values:aws/regions
+      - collapsible: true
+        default: << ref.input.execution_environment_id >>
+        description: Execution environment used by Terraform. For a private endpoint, choose one in the cluster VPC with the Ravion Runner security group attached so Terraform can reach the Kubernetes API.
+        id: execution_environment_id
+        label: Terraform execution environment
+        type: string
+        values: $values:ravion/execution_environments
+      - id: section_cluster
+        label: Cluster details
+        type: section
+      - default: <<ref.stack.output.cluster_name>>
+        id: cluster_name
+        immutable: true
+        label: EKS cluster name
+        placeholder: my-eks-cluster
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.ravion_runner_role_arn>>
+        description: IAM role Terraform assumes when authenticating to the Kubernetes API.
+        id: ravion_runner_role_arn
+        label: Ravion Runner role ARN
+        placeholder: arn:aws:iam::123456789012:role/my-eks-cluster-ravion-runner
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.cluster_security_group_id>>
+        description: EKS-managed security group used by Karpenter nodes and shared load balancers. Required when the default NodePool or any shared load balancer is enabled.
+        id: cluster_security_group_id
+        label: Cluster security group ID
+        placeholder: sg-0123456789abcdef0
+        type: string
+      - add_button_label: Add subnet ID
+        collapsible: true
+        default: <<ref.stack.output.node_subnet_ids>>
+        description: Subnets the default Karpenter NodePool launches nodes into. Also used by internal shared load balancers.
+        id: node_subnet_ids
+        label: Node subnet IDs
+        placeholder: subnet-0123456789abcdef0
+        type: string_array
+      - add_button_label: Add subnet ID
+        collapsible: true
+        default: <<ref.stack.output.public_subnet_ids>>
+        description: Public subnets for internet-facing shared load balancers.
+        id: public_subnet_ids
+        label: Public subnet IDs
+        placeholder: subnet-0fedcba9876543210
+        type: string_array
+    required: true
+    type: $ref:rvn-eks-cluster
+  - description: Ravion Operator connects outbound to Ravion for workload, rollout, and node visibility.
+    id: section_ravion_operator
+    label: Ravion EKS Management
+    type: section
+  - default: true
+    description: Register the cluster with Ravion and install Ravion Operator for cluster visibility and in-cluster deployments.
+    id: ravion_operator_enabled
+    label: Ravion EKS Management
+    moved_from:
+      - beacon_enabled
+    type: boolean
+  - default: true
+    description: Run Ravion deployments through Ravion Operator inside the cluster. Ravion Operator may create, update, and delete workload resources only in the selected namespaces; it cannot modify RBAC, namespaces, or cluster-scoped resources.
+    id: ravion_operator_deploy_enabled
+    label: Ravion Operator deployments
+    moved_from:
+      - beacon_deploy_enabled
+    show_when:
+      ravion_operator_enabled: true
+    type: boolean
+  - add_button_label: Add namespace
+    collapsible: true
+    description: Namespaces Ravion Operator may deploy into. If empty, the advanced operator observation scope is used. Installation fails if neither list contains a namespace.
+    id: ravion_operator_deploy_namespaces
+    label: Deployment namespaces
+    moved_from:
+      - beacon_deploy_namespaces
+    placeholder: default
+    required: true
+    show_when:
+      ravion_operator_deploy_enabled: true
+    type: string_array
+  - description: Shared Application Load Balancers for HTTP and HTTPS workloads. EKS Web services attach through TargetGroupBinding.
+    id: section_alb
+    label: Application load balancers
+    type: section
+  - default: true
+    description: Create an internet-facing Application Load Balancer for traffic from the public internet.
+    id: public_alb_creation_enabled
+    label: Public ALB
+    type: boolean
+  - default: true
+    description: Add an HTTPS listener and redirect HTTP requests to it.
+    id: public_alb_https_enabled
+    label: HTTPS
+    show_when:
+      public_alb_creation_enabled: true
+    type: boolean
+  - description: ACM certificate module that supplies the default certificate for the public HTTPS listener.
+    id: public_alb_certificate
+    label: Certificate
+    mapped_inputs:
+      - add_button_label: Add certificate ARN
+        default:
+          - <<ref.stack.output.certificate_arn>>
+        description: ACM certificate ARNs supplied by the selected module. The first certificate is used by default.
+        id: public_alb_certificate_arns
+        label: Certificate ARNs
+        placeholder: arn:aws:acm:...
+        required: true
+        type: string_array
+    required: true
+    show_when:
+      public_alb_creation_enabled: true
+      public_alb_https_enabled: true
+    type: $ref:rvn-acm-certificate
+  - add_button_label: Add certificate ARN
+    collapsible: true
+    default: []
+    description: Additional ACM certificate ARNs attached to the public ALB HTTPS listener for SNI.
+    id: public_alb_additional_certificate_arns
+    label: Additional certificate ARNs
+    placeholder: arn:aws:acm:...
+    show_when:
+      public_alb_creation_enabled: true
+      public_alb_https_enabled: true
+    type: string_array
+  - collapsible: true
+    description: AWS ELB security policy name for the public HTTPS listener.
+    id: public_alb_ssl_policy
+    label: SSL policy
+    placeholder: ELBSecurityPolicy-TLS13-1-2-2021-06
+    show_when:
+      public_alb_creation_enabled: true
+      public_alb_https_enabled: true
+    type: string
+  - collapsible: true
+    id: public_alb_idle_timeout
+    label: Idle timeout (seconds)
+    max: 4000
+    min: 1
+    placeholder: "60"
+    show_when:
+      public_alb_creation_enabled: true
+    type: number
+  - collapsible: true
+    description: WAFv2 Web ACL to associate with the public ALB.
+    id: public_alb_web_acl_arn
+    label: WAF web ACL ARN
+    placeholder: arn:aws:wafv2:...
+    show_when:
+      public_alb_creation_enabled: true
+    type: string
+  - collapsible: true
+    default: false
+    description: Write public ALB request logs to S3.
+    id: public_alb_access_logs_enabled
+    label: Access logs
+    show_when:
+      public_alb_creation_enabled: true
+    type: boolean
+  - collapsible: true
+    description: Existing S3 bucket ARN for access logs. Leave blank to create a private bucket with 90-day retention.
+    id: public_alb_access_logs_bucket_arn
+    label: Access logs bucket ARN
+    placeholder: arn:aws:s3:::my-bucket
+    show_when:
+      public_alb_access_logs_enabled: true
+      public_alb_creation_enabled: true
+    type: string
+  - default: false
+    description: Create an internal Application Load Balancer reachable only inside the VPC, for internal APIs, admin tools, and service-to-service traffic.
+    id: private_alb_creation_enabled
+    label: Private ALB
+    type: boolean
+  - default: false
+    description: Add an HTTPS listener and redirect HTTP requests to it.
+    id: private_alb_https_enabled
+    label: HTTPS
+    show_when:
+      private_alb_creation_enabled: true
+    type: boolean
+  - description: ACM certificate module that supplies the default certificate for the private HTTPS listener.
+    id: private_alb_certificate
+    label: Certificate
+    mapped_inputs:
+      - add_button_label: Add certificate ARN
+        default:
+          - <<ref.stack.output.certificate_arn>>
+        description: ACM certificate ARNs supplied by the selected module. The first certificate is used by default.
+        id: private_alb_certificate_arns
+        label: Certificate ARNs
+        placeholder: arn:aws:acm:...
+        required: true
+        type: string_array
+    required: true
+    show_when:
+      private_alb_creation_enabled: true
+      private_alb_https_enabled: true
+    type: $ref:rvn-acm-certificate
+  - add_button_label: Add certificate ARN
+    collapsible: true
+    default: []
+    description: Additional ACM certificate ARNs attached to the private ALB HTTPS listener for SNI.
+    id: private_alb_additional_certificate_arns
+    label: Additional certificate ARNs
+    placeholder: arn:aws:acm:...
+    show_when:
+      private_alb_creation_enabled: true
+      private_alb_https_enabled: true
+    type: string_array
+  - collapsible: true
+    description: AWS ELB security policy name for the private HTTPS listener.
+    id: private_alb_ssl_policy
+    label: SSL policy
+    placeholder: ELBSecurityPolicy-TLS13-1-2-2021-06
+    show_when:
+      private_alb_creation_enabled: true
+      private_alb_https_enabled: true
+    type: string
+  - add_button_label: Add CIDR block
+    collapsible: true
+    description: IPv4 CIDR blocks allowed to reach the private ALB. Leave empty to use the RFC1918 private ranges.
+    id: private_alb_ingress_cidr_blocks
+    label: Allowed IPv4 CIDRs
+    placeholder: 10.0.0.0/8
+    show_when:
+      private_alb_creation_enabled: true
+    type: string_array
+  - add_button_label: Add IPv6 CIDR block
+    collapsible: true
+    description: IPv6 CIDR blocks allowed to reach the private ALB. Leave empty to allow no IPv6 ingress.
+    id: private_alb_ingress_ipv6_cidr_blocks
+    label: Allowed IPv6 CIDRs
+    placeholder: fd00::/8
+    show_when:
+      private_alb_creation_enabled: true
+    type: string_array
+  - add_button_label: Add security group
+    collapsible: true
+    description: Security groups whose members can access the private ALB. Useful for sources without static CIDRs, such as CloudFront VPC origins.
+    id: private_alb_ingress_security_group_ids
+    label: Allowed security group IDs
+    placeholder: sg-...
+    show_when:
+      private_alb_creation_enabled: true
+    type: string_array
+  - collapsible: true
+    id: private_alb_idle_timeout
+    label: Idle timeout (seconds)
+    max: 4000
+    min: 1
+    placeholder: "60"
+    show_when:
+      private_alb_creation_enabled: true
+    type: number
+  - collapsible: true
+    default: false
+    description: Write private ALB request logs to S3.
+    id: private_alb_access_logs_enabled
+    label: Access logs
+    show_when:
+      private_alb_creation_enabled: true
+    type: boolean
+  - collapsible: true
+    description: Existing S3 bucket ARN for access logs. Leave blank to create a private bucket with 90-day retention.
+    id: private_alb_access_logs_bucket_arn
+    label: Access logs bucket ARN
+    placeholder: arn:aws:s3:::my-bucket
+    show_when:
+      private_alb_access_logs_enabled: true
+      private_alb_creation_enabled: true
+    type: string
+  - description: Network Load Balancers support TCP/UDP traffic, static IPs, and protocols that do not use HTTP routing. Use an Application Load Balancer for HTTP host or path routing.
+    id: section_nlb
+    label: Network load balancers
+    type: section
+  - default: false
+    description: Create an internet-facing Network Load Balancer.
+    id: public_nlb_creation_enabled
+    label: Public NLB
+    type: boolean
+  - add_button_label: Add security group ID
+    collapsible: true
+    description: Addit
... diff truncated ...

rvn-eks-cluster n/a -> 0.2.0

--- remote
+++ compiled
-
+description: Production-ready Amazon EKS cluster with default managed capacity, core add-ons, and optional Fargate compute. Extend with the EKS Add-ons module (Karpenter, load balancer controller, EBS CSI, Container Insights).
+name: EKS Cluster
+type: rvn-eks-cluster

rvn-eks-cluster n/a -> 0.2.0

--- remote
+++ compiled
+inputs:
+  - id: network
+    immutable: true
+    label: VPC network
+    mapped_inputs:
+      - id: section_aws
+        label: AWS account & region
+        type: section
+      - default: << ref.input.aws_account_id >>
+        id: aws_account_id
+        immutable: true
+        label: AWS account
+        type: string
+        values: $values:ravion/aws_accounts
+      - default: << ref.input.aws_region >>
+        id: aws_region
+        immutable: true
+        label: Region
+        type: string
+        values: $values:aws/regions
+      - collapsible: true
+        default: << ref.input.execution_environment_id >>
+        description: Override the VPC, subnet, and security group for Pipeline Terraform runners. Must use the same AWS account as selected above.
+        id: execution_environment_id
+        label: Terraform execution environment
+        type: string
+        values: $values:ravion/execution_environments
+      - id: section_vpc
+        label: VPC
+        type: section
+      - default: <<ref.stack.output.vpc_id>>
+        id: vpc_id
+        immutable: true
+        label: VPC ID
+        placeholder: vpc-0123456789abcdef0
+        required: true
+        type: string
+      - add_button_label: Add private subnet ID
+        default: <<ref.stack.output.private_subnet_ids>>
+        description: Subnets for the EKS control plane and default node placement. Use private subnets in at least two availability zones.
+        id: subnet_ids
+        immutable: true
+        label: Private subnet IDs
+        placeholder: subnet-0123456789abcdef0
+        required: true
+        type: string_array
+      - add_button_label: Add public subnet ID
+        collapsible: true
+        default: <<ref.stack.output.public_subnet_ids>>
+        description: Public subnets made available to dependent modules, such as EKS Add-ons shared load balancers. Not used by the cluster itself.
+        id: public_subnet_ids
+        label: Public subnet IDs
+        placeholder: subnet-0fedcba9876543210
+        type: string_array
+    required: true
+    type: $ref:rvn-aws-network
+  - id: section_cluster
+    label: EKS cluster
+    type: section
+  - default: <<project.given_id>>-<<environment.given_id>>
+    description: Name and prefix for related resources.
+    id: name
+    immutable: true
+    label: EKS cluster name
+    patterns:
+      - message: 1-100 letters, numbers, hyphens, and underscores. Start with a letter or number.
+        pattern: ^[0-9A-Za-z][A-Za-z0-9-_]{0,99}$
+    required: true
+    type: string
+  - default: $values:first
+    description: Kubernetes version for the EKS cluster.
+    id: kubernetes_version
+    label: Kubernetes version
+    min_current_value: true
+    required: true
+    type: string
+    values: $values:aws/eks-versions?region=<<module.input.aws_region>>&currentVersion=<<instance.input.kubernetes_version>>
+  - default: true
+    description: Prevent the cluster from being deleted via the AWS API. Must be turned off before this module can be destroyed.
+    id: deletion_protection_enabled
+    label: Deletion protection
+    type: boolean
+  - collapsible: true
+    default: true
+    description: Envelope-encrypt Kubernetes secrets with a KMS key. A key is created automatically unless an existing key ARN is provided below.
+    id: secrets_encryption_enabled
+    label: Secrets encryption
+    type: boolean
+  - collapsible: true
+    description: Existing KMS key for Kubernetes secrets encryption. Leave blank to create a dedicated key.
+    id: secrets_kms_key_arn
+    label: Secrets KMS key ARN
+    placeholder: arn:aws:kms:...
+    show_when:
+      secrets_encryption_enabled: true
+    type: string
+  - description: Reserve roughly 0.5 vCPU and 1 GiB of node capacity as a starting allowance for baseline cluster services such as CoreDNS, networking agents, and Ravion add-ons. The EKS control plane itself runs on AWS-managed infrastructure.
+    id: section_capacity
+    label: Default capacity
+    type: section
+  - default: ON_DEMAND
+    description: On-demand is stable default capacity; Spot is lower cost but nodes can be interrupted.
+    id: system_node_capacity_type
+    label: Capacity type
+    type: string
+    values:
+      - label: On-demand
+        value: ON_DEMAND
+      - label: Spot
+        value: SPOT
+  - default:
+      - t3.medium
+    description: EC2 instance types AWS may use for this node group. Multiple types improve Spot availability.
+    id: system_node_instance_types
+    label: Instance types
+    placeholder: Select an instance type
+    required: true
+    type: string_array
+    values: $values:aws/ec2/instances?awsAccountId=<<module.input.aws_account_id>>&region=<<module.input.aws_region>>
+  - default: 2
+    description: Minimum nodes in the default managed node group. Set it high enough to run cluster components and leave spare capacity for workloads and rolling node updates.
+    id: system_node_min_size
+    label: Minimum nodes
+    min: 1
+    type: number
+  - default: 10
+    description: Maximum nodes in the default managed node group. Set it high enough for peak workloads and replacement capacity during rolling node updates, otherwise pods can remain pending.
+    id: system_node_max_size
+    label: Maximum nodes
+    min: 1
+    type: number
+  - collapsible: true
+    description: Root EBS volume size for default capacity nodes. Leave blank for the AMI default.
+    id: system_node_disk_size
+    label: Disk size (GB)
+    min: 20
+    placeholder: "20"
+    type: number
+  - default: {}
+    description: Add independently sized On-demand or Spot managed node groups when workloads need more or separate capacity. Create one of each to make both capacity types available.
+    id: node_groups
+    item_inputs:
+      - default: ON_DEMAND
+        description: On-demand is stable capacity; Spot is lower cost but can be interrupted by AWS.
+        id: capacity_type
+        label: Capacity type
+        required: true
+        type: string
+        values:
+          - label: On-demand
+            value: ON_DEMAND
+          - label: Spot
+            value: SPOT
+      - default:
+          - t3.medium
+        description: EC2 instance types AWS may use for this node group. Multiple types improve Spot availability.
+        id: instance_types
+        label: Instance types
+        placeholder: Select an instance type
+        required: true
+        type: string_array
+        values: $values:aws/ec2/instances?awsAccountId=<<module.input.aws_account_id>>&region=<<module.input.aws_region>>
+      - default: 1
+        description: Minimum nodes in this managed node group. Set it high enough to leave spare capacity for workloads and rolling node updates.
+        id: min_size
+        label: Minimum nodes
+        min: 0
+        required: true
+        type: number
+      - default: 3
+        description: Maximum nodes in this managed node group. Set it high enough for peak workloads and replacement capacity during rolling node updates, otherwise pods can remain pending.
+        id: max_size
+        label: Maximum nodes
+        min: 1
+        required: true
+        type: number
+      - collapsible: true
+        description: Root EBS volume size for nodes. Leave blank for the AMI default.
+        id: disk_size
+        label: Root volume size (GB)
+        min: 20
+        type: number
+      - collapsible: true
+        default: {}
+        description: Kubernetes labels applied to nodes in this group.
+        id: labels
+        label: Node labels
+        type: keyvalue
+      - collapsible: true
+        default: []
+        description: Kubernetes taints that restrict which pods can use this group.
+        id: taints
+        item_inputs:
+          - id: key
+            label: Key
+            required: true
+            type: string
+          - id: value
+            label: Value
+            type: string
+          - id: effect
+            label: Effect
+            required: true
+            type: string
+            values:
+              - label: No schedule
+                value: NO_SCHEDULE
+              - label: Prefer no schedule
+                value: PREFER_NO_SCHEDULE
+              - label: No execute
+                value: NO_EXECUTE
+        item_label: Taint
+        item_title:
+          fallback: Taint
+          template: "{key}"
+        label: Taints
+        type: object_array
+    item_label: Managed node group
+    item_title:
+      template: "{key}"
+    key:
+      description: Unique EKS managed node group name.
+      label: Node group name
+      patterns:
+        - message: 1-63 letters, numbers, hyphens, and underscores. Start with a letter or number.
+          pattern: ^[0-9A-Za-z][A-Za-z0-9-_]{0,62}$
+      placeholder: applications-spot
+    label: Additional node groups
+    required: false
+    type: object_map
+  - id: section_fargate
+    label: Fargate
+    type: section
+  - collapsible: true
+    default: {}
+    description: Run pods from selected namespaces on AWS Fargate instead of EC2 nodes.
+    id: fargate_profiles
+    item_inputs:
+      - description: Namespaces whose pods run on this profile. At least one selector is required.
+        id: selectors
+        item_inputs:
+          - description: Kubernetes namespace matched by this selector.
+            id: namespace
+            label: Namespace
+            placeholder: my-namespace
+            required: true
+            type: string
+          - collapsible: true
+            default: {}
+            description: Optional pod labels that narrow the match to specific pods in the namespace. Leave empty to match every pod.
+            id: labels
+            label: Pod labels
+            type: keyvalue
+        item_label: Selector
+        item_title:
+          fallback: Selector
+          template: "{namespace}"
+        label: Selectors
+        required: true
+        type: object_array
+      - add_button_label: Add subnet ID
+        collapsible: true
+        description: Private subnets for Fargate pods in this profile. Leave empty to use the cluster's private subnets. Public subnets are not supported by Fargate.
+        id: subnet_ids
+        label: Subnet IDs
+        placeholder: subnet-0123456789abcdef0
+        type: string_array
+      - collapsible: true
+        description: Existing pod execution role for this profile. Leave blank to create one automatically.
+        id: pod_execution_role_arn
+        label: Pod execution role ARN
+        placeholder: arn:aws:iam::123456789012:role/my-fargate-pod-execution-role
+        type: string
+    item_label: Fargate profile
+    item_title:
+      template: "{key}"
+    key:
+      description: Unique Fargate profile name.
+      label: Profile name
+      patterns:
+        - message: 1-63 letters, numbers, hyphens, and underscores. Start with a letter or number.
+          pattern: ^[A-Za-z0-9][A-Za-z0-9-_]{0,62}$
+      placeholder: serverless-jobs
+    label: Fargate profiles
+    required: false
+    type: object_map
+  - id: section_access
+    label: Cluster access
+    type: section
+  - default: true
+    description: Allow access to the Kubernetes API server from inside the VPC.
+    id: endpoint_private_access_enabled
+    label: Private endpoint access
+    type: boolean
+  - default: false
+    description: Allow access to the Kubernetes API server from the public internet.
+    id: endpoint_public_access_enabled
+    label: Public endpoint access
+    type: boolean
+  - add_button_label: Add CIDR block
+    description: IPv4 CIDR blocks allowed to reach the public API server endpoint. Terraform defaults to 0.0.0.0/0.
+    id: endpoint_public_access_cidrs
+    label: Public access CIDRs
+    placeholder: 0.0.0.0/0
+    show_when:
+      endpoint_public_access_enabled: true
+    type: string_array
+  - collapsible: true
+    defaul
... diff truncated ...

rvn-eks-web n/a -> 1.0.0

--- remote
+++ compiled
-
+description: Web server on EKS for running any HTTP application on your Kubernetes cluster behind a shared load balancer, with no Kubernetes manifests or Helm charts to write.
+name: EKS Web Service
+type: rvn-eks-web

rvn-eks-web n/a -> 1.0.0

--- remote
+++ compiled
+build:
+  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_environment_variable_injection_enabled, cache_from: {tag: "dockerfile"}} : module.input.build_source == "railpack" ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, start_cmd: module.input.railpack_start_cmd, cache_from: {tag: "railpack"}} : {type: "disabled"} >>'
+  destinations:
+    - id: ecr
+      repository_arn: << stack.output.ecr_repository_arn >>
+      tags:
+        - <<pipeline.run.id>>-<< module.input.build_source >>
+        - << module.input.build_source >>
+      type: ecr
+  environment_variables: << module.input.build_environment_variables >>
+  infrastructure:
+    ami: << module.input.build_ami_id || nil >>
+    aws_account_id: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_account_id >>"
+    execution_environment_id: << module.input.build_execution_environment_id || module.input.execution_environment_id >>
+    instance_size: << module.input.build_instance_type >>
+    permissions: '<< module.input.build_iam_policy_arns ? (module.input.build_default_policies_enabled ? {"attach": module.input.build_iam_policy_arns} : {"replace": module.input.build_iam_policy_arns}) : nil >>'
+    region: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_region >>"
+    type: << module.input.build_capacity_type >>
+  inputs:
+    - description: Defaults to repo default branch
+      id: branch
+      label: Git branch
+      required: false
+      type: string
+    - description: Optional commit SHA, tag, or ref to build. Defaults to the configured branch head.
+      id: ref
+      label: Git ref (commit or tag)
+      required: false
+      type: string
+  source:
+    base_path: << module.input.source_base_path || "." >>
+    branch: << build.input.branch >>
+    ref: << build.input.ref >>
+    repo: << module.input.source_repo >>
+    type: git
+  type: '<< module.input.build_source == "image_registry" ? "disabled" : "image" >>'
+deploy:
+  concurrency:
+    queue_overflow: oldest
+    queue_size: 1
+  definition:
+    create_namespace: "<< module.input.namespace_creation_enabled != nil ? module.input.namespace_creation_enabled : true >>"
+    namespace: << module.input.namespace >>
+    release_name: << module.input.name >>
+    secrets: "<< module.input.secrets != nil ? module.input.secrets : [] >>"
+    source:
+      base_path: charts/rvn-eks-web
+      branch: main
+      ref: rvn-eks-web@1.0.0
+      repo_url: https://github.com/ravionhq/modules
+      type: git
+    type: helm
+    values:
+      affinity: '<< module.input.compute_target == "on_demand" || module.input.compute_target == "spot" ? {"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"eks.amazonaws.com/capacityType","operator":"In","values":[module.input.compute_target == "spot" ? "SPOT" : "ON_DEMAND"]}]},{"matchExpressions":[{"key":"karpenter.sh/capacity-type","operator":"In","values":[module.input.compute_target == "spot" ? "spot" : "on-demand"]}]}]}}} : {} >>'
+      args: "<< module.input.start_command_args != nil ? module.input.start_command_args : [] >>"
+      autoscaling:
+        enabled: << module.input.autoscaling_enabled >>
+        maxReplicas: "<< module.input.autoscaling_max_replicas != nil ? module.input.autoscaling_max_replicas : 3 >>"
+        minReplicas: "<< module.input.autoscaling_min_replicas != nil ? module.input.autoscaling_min_replicas : 1 >>"
+        targetCPUUtilizationPercentage: "<< module.input.autoscaling_cpu_target != nil ? module.input.autoscaling_cpu_target : 70 >>"
+        targetMemoryUtilizationPercentage: << module.input.autoscaling_memory_target >>
+      command: "<< module.input.start_command != nil ? module.input.start_command : [] >>"
+      containerPort: << module.input.container_port >>
+      env: "<< module.input.environment_variables != nil ? module.input.environment_variables : [] >>"
+      fullnameOverride: << module.input.name >>
+      image:
+        digest: '<< deploy.input.image_ref contains "sha256:" ? deploy.input.image_ref : "" >>'
+        repository: '<< module.input.build_source == "image_registry" ? module.input.image_repository : stack.output.ecr_repository_url >>'
+        tag: '<< deploy.input.image_ref contains "sha256:" ? "" : deploy.input.image_ref >>'
+      imagePullSecrets: '<< module.input.image_pull_secret_names != nil ? map(module.input.image_pull_secret_names, ({"name": #})) : [] >>'
+      podAnnotations: '<< module.input.compute_target == "on_demand" || module.input.compute_target == "spot" ? {"eks.amazonaws.com/compute-type": "ec2"} : {} >>'
+      podLabels: '<< module.input.compute_target == "fargate" ? {"eks.amazonaws.com/fargate-profile": module.input.name + "-fargate"} : {} >>'
+      probes:
+        liveness:
+          enabled: << module.input.liveness_probe_enabled >>
+          initialDelaySeconds: "<< module.input.probe_initial_delay_seconds != nil ? module.input.probe_initial_delay_seconds : 5 >>"
+          path: << module.input.liveness_probe_path || module.input.health_check_path >>
+        readiness:
+          enabled: true
+          initialDelaySeconds: "<< module.input.probe_initial_delay_seconds != nil ? module.input.probe_initial_delay_seconds : 5 >>"
+          path: << module.input.health_check_path >>
+        startup:
+          enabled: << module.input.startup_probe_enabled >>
+          failureThreshold: "<< module.input.startup_timeout_seconds != nil ? int((module.input.startup_timeout_seconds + 4) / 5) : 30 >>"
+          path: << module.input.startup_probe_path || module.input.liveness_probe_path || module.input.health_check_path >>
+      replicaCount: "<< module.input.autoscaling_enabled ? (module.input.autoscaling_min_replicas != nil ? module.input.autoscaling_min_replicas : 1) : (module.input.replica_count != nil ? module.input.replica_count : 1) >>"
+      resources:
+        limits: '<< module.input.cpu_limit ? {"cpu": module.input.cpu_limit, "memory": module.input.memory_limit} : {"memory": module.input.memory_limit} >>'
+        requests:
+          cpu: << module.input.cpu_request >>
+          memory: << module.input.memory_request >>
+      service:
+        port: << module.input.container_port >>
+      targetGroupArns:
+        - << stack.output.target_group_arn >>
+      targetGroupBinding:
+        targetType: ip
+        vpcId: << module.input.vpc_id >>
+  infrastructure:
+    cluster_arn: << module.input.cluster_arn >>
+    cluster_certificate_authority_data: << module.input.cluster_certificate_authority_data >>
+    cluster_endpoint: << module.input.cluster_endpoint >>
+    cluster_name: << module.input.cluster_name >>
+    execution_environment_id: << deploy.input.execution_environment_id || module.input.execution_environment_id >>
+    execution_environment_overrides:
+      security_group: << module.input.ravion_runner_security_group_id >>
+    ravion_runner_role_arn: << module.input.ravion_runner_role_arn >>
+  inputs:
+    - description: Tag or digest to deploy from the configured image repository. A value starting with "sha256:" is used as a digest, anything else as a tag. Do not pass a full image URI.
+      id: image_ref
+      label: Image tag or digest
+      placeholder: sha256:... or latest
+      required: true
+      type: string
+    - collapsible: true
+      default: << module.input.execution_environment_id >>
+      description: Execution environment the deploy runner launches into to reach the Kubernetes API. Leave empty to use the environment inherited from the EKS cluster, or the default environment of the account that owns the cluster. Its region must match the cluster region.
+      id: execution_environment_id
+      label: Execution environment
+      required: false
+      type: string
+      values: $values:ravion/execution_environments
+  timeout: 1800
+  type: aws:eks
+inputs:
+  - id: section_cluster
+    label: EKS cluster
+    type: section
+  - id: cluster
+    immutable: true
+    label: Cluster
+    mapped_inputs:
+      - id: section_aws
+        label: AWS account & region
+        type: section
+      - default: << ref.input.aws_account_id >>
+        id: aws_account_id
+        immutable: true
+        label: AWS account
+        type: string
+        values: $values:ravion/aws_accounts
+      - default: << ref.input.aws_region >>
+        description: Region of the selected cluster. Must match the region in the cluster ARN, which Ravion cross-checks on every deploy.
+        id: aws_region
+        immutable: true
+        label: Region
+        type: string
+        values: $values:aws/regions
+      - collapsible: true
+        default: << ref.input.execution_environment_id >>
+        description: Terraform execution environment inherited from the selected EKS cluster.
+        id: execution_environment_id
+        label: Terraform execution environment
+        type: string
+        values: $values:ravion/execution_environments
+      - id: section_cluster_identity
+        label: EKS cluster
+        type: section
+      - default: <<ref.stack.output.cluster_name>>
+        id: cluster_name
+        immutable: true
+        label: EKS cluster name
+        placeholder: my-eks-cluster
+        required: true
+        type: string
+      - default: <<ref.stack.output.cluster_arn>>
+        description: Ravion resolves the owning AWS account and region from this ARN, and rejects a deploy whose cluster name or region disagrees with it.
+        id: cluster_arn
+        immutable: true
+        label: Cluster ARN
+        placeholder: arn:aws:eks:us-east-1:123456789012:cluster/my-eks-cluster
+        required: true
+        type: string
+      - default: <<ref.stack.output.cluster_endpoint>>
+        description: HTTPS endpoint of the Kubernetes API server. May be private-only; the deploy runner executes inside the cluster VPC.
+        id: cluster_endpoint
+        immutable: true
+        label: Cluster API endpoint
+        placeholder: https://ABCDEF0123456789ABCDEF0123456789.gr7.us-east-1.eks.amazonaws.com
+        required: true
+        type: string
+      - default: <<ref.stack.output.cluster_certificate_authority_data>>
+        description: Base64-encoded CA bundle used to verify the API server's TLS certificate. Public key material, not a credential.
+        id: cluster_certificate_authority_data
+        immutable: true
+        label: Cluster certificate authority data
+        placeholder: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCg...
+        required: true
+        type: string
+      - default: <<ref.stack.output.ravion_runner_role_arn>>
+        description: Stable IAM role the deploy runner assumes to obtain a cluster token. Registered as an EKS access entry by the cluster module.
+        id: ravion_runner_role_arn
+        immutable: true
+        label: Ravion Runner role ARN
+        placeholder: arn:aws:iam::123456789012:role/my-eks-cluster-ravion-runner
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.ravion_runner_security_group_id>>
+        description: Security group the deploy runner's network interface joins so it can reach the cluster API endpoint. Null when the cluster module did not create one, which is only workable if the endpoint is public or the execution environment supplies its own group.
+        id: ravion_runner_security_group_id
+        immutable: true
+        label: Ravion Runner security group ID
+        placeholder: sg-0123456789abcdef0
+        req
... diff truncated ...

rvn-eks-worker n/a -> 0.4.0

--- remote
+++ compiled
-
+description: Background worker on EKS for running a long-lived private process with no exposed port, and no Kubernetes manifests or Helm charts to write.
+name: EKS Worker
+type: rvn-eks-worker

rvn-eks-worker n/a -> 0.4.0

--- remote
+++ compiled
+build:
+  builder: '<< module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_environment_variable_injection_enabled, cache_from: {tag: "dockerfile"}} : module.input.build_source == "railpack" ? {type: "railpack", railpack_version: module.input.railpack_version, install_cmd: module.input.railpack_install_cmd, build_cmd: module.input.railpack_build_cmd, start_cmd: module.input.railpack_start_cmd, cache_from: {tag: "railpack"}} : {type: "disabled"} >>'
+  destinations:
+    - id: ecr
+      repository_arn: << stack.output.ecr_repository_arn >>
+      tags:
+        - <<pipeline.run.id>>-<< module.input.build_source >>
+        - << module.input.build_source >>
+      type: ecr
+  environment_variables: << module.input.build_environment_variables >>
+  infrastructure:
+    ami: << module.input.build_ami_id || nil >>
+    aws_account_id: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_account_id >>"
+    execution_environment_id: << module.input.build_execution_environment_id || module.input.execution_environment_id >>
+    instance_size: << module.input.build_instance_type >>
+    permissions: '<< module.input.build_iam_policy_arns ? (module.input.build_default_policies_enabled ? {"attach": module.input.build_iam_policy_arns} : {"replace": module.input.build_iam_policy_arns}) : nil >>'
+    region: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_region >>"
+    type: << module.input.build_capacity_type >>
+  inputs:
+    - description: Defaults to repo default branch
+      id: branch
+      label: Git branch
+      required: false
+      type: string
+    - description: Optional commit SHA, tag, or ref to build. Defaults to the configured branch head.
+      id: ref
+      label: Git ref (commit or tag)
+      required: false
+      type: string
+  source:
+    base_path: << module.input.source_base_path || "." >>
+    branch: << build.input.branch >>
+    ref: << build.input.ref >>
+    repo: << module.input.source_repo >>
+    type: git
+  type: '<< module.input.build_source == "image_registry" ? "disabled" : "image" >>'
+deploy:
+  concurrency:
+    queue_overflow: oldest
+    queue_size: 1
+  definition:
+    create_namespace: "<< module.input.namespace_creation_enabled != nil ? module.input.namespace_creation_enabled : true >>"
+    namespace: << module.input.namespace >>
+    release_name: << module.input.name >>
+    secrets: "<< module.input.secrets != nil ? module.input.secrets : [] >>"
+    source:
+      base_path: charts/rvn-eks-worker
+      branch: main
+      ref: rvn-eks-worker@0.4.0
+      repo_url: https://github.com/ravionhq/modules
+      type: git
+    type: helm
+    values:
+      affinity: '<< module.input.compute_target == "on_demand" || module.input.compute_target == "spot" ? {"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"eks.amazonaws.com/capacityType","operator":"In","values":[module.input.compute_target == "spot" ? "SPOT" : "ON_DEMAND"]}]},{"matchExpressions":[{"key":"karpenter.sh/capacity-type","operator":"In","values":[module.input.compute_target == "spot" ? "spot" : "on-demand"]}]}]}}} : {} >>'
+      args: "<< module.input.start_command_args != nil ? module.input.start_command_args : [] >>"
+      autoscaling:
+        enabled: "<< module.input.autoscaling_enabled != nil ? module.input.autoscaling_enabled : false >>"
+        maxReplicas: "<< module.input.autoscaling_max_replicas != nil ? module.input.autoscaling_max_replicas : 3 >>"
+        minReplicas: "<< module.input.autoscaling_min_replicas != nil ? module.input.autoscaling_min_replicas : 1 >>"
+        targetCPUUtilizationPercentage: "<< module.input.autoscaling_cpu_target != nil ? module.input.autoscaling_cpu_target : 70 >>"
+        targetMemoryUtilizationPercentage: << module.input.autoscaling_memory_target >>
+      command: "<< module.input.start_command != nil ? module.input.start_command : [] >>"
+      env: "<< module.input.environment_variables != nil ? module.input.environment_variables : [] >>"
+      fullnameOverride: << module.input.name >>
+      image:
+        digest: '<< deploy.input.image_ref contains "sha256:" ? deploy.input.image_ref : "" >>'
+        repository: '<< module.input.build_source == "image_registry" ? module.input.image_repository : stack.output.ecr_repository_url >>'
+        tag: '<< deploy.input.image_ref contains "sha256:" ? "" : deploy.input.image_ref >>'
+      imagePullSecrets: '<< module.input.image_pull_secret_names != nil ? map(module.input.image_pull_secret_names, ({"name": #})) : [] >>'
+      podAnnotations: '<< module.input.compute_target == "on_demand" || module.input.compute_target == "spot" ? {"eks.amazonaws.com/compute-type": "ec2"} : {} >>'
+      podLabels: '<< module.input.compute_target == "fargate" ? {"eks.amazonaws.com/fargate-profile": module.input.name + "-fargate"} : {} >>'
+      replicaCount: "<< module.input.autoscaling_enabled ? (module.input.autoscaling_min_replicas != nil ? module.input.autoscaling_min_replicas : 1) : (module.input.replica_count != nil ? module.input.replica_count : 1) >>"
+      resources:
+        limits: '<< module.input.cpu_limit ? {"cpu": module.input.cpu_limit, "memory": module.input.memory_limit} : {"memory": module.input.memory_limit} >>'
+        requests:
+          cpu: << module.input.cpu_request >>
+          memory: << module.input.memory_request >>
+      terminationGracePeriodSeconds: "<< module.input.termination_grace_period_seconds != nil ? module.input.termination_grace_period_seconds : 30 >>"
+  infrastructure:
+    cluster_arn: << module.input.cluster_arn >>
+    cluster_certificate_authority_data: << module.input.cluster_certificate_authority_data >>
+    cluster_endpoint: << module.input.cluster_endpoint >>
+    cluster_name: << module.input.cluster_name >>
+    execution_environment_id: << deploy.input.execution_environment_id || module.input.execution_environment_id >>
+    execution_environment_overrides:
+      security_group: << module.input.ravion_runner_security_group_id >>
+    ravion_runner_role_arn: << module.input.ravion_runner_role_arn >>
+  inputs:
+    - description: Tag or digest to deploy from the configured image repository. A value starting with "sha256:" is used as a digest, anything else as a tag. Do not pass a full image URI.
+      id: image_ref
+      label: Image tag or digest
+      placeholder: sha256:... or latest
+      required: true
+      type: string
+    - collapsible: true
+      default: << module.input.execution_environment_id >>
+      description: Execution environment the deploy runner launches into to reach the Kubernetes API. Leave empty to use the environment inherited from the EKS cluster, or the default environment of the account that owns the cluster. Its region must match the cluster region.
+      id: execution_environment_id
+      label: Execution environment
+      required: false
+      type: string
+      values: $values:ravion/execution_environments
+  timeout: 1800
+  type: aws:eks
+inputs:
+  - id: section_cluster
+    label: EKS cluster
+    type: section
+  - id: cluster
+    immutable: true
+    label: Cluster
+    mapped_inputs:
+      - id: section_aws
+        label: AWS account & region
+        type: section
+      - default: << ref.input.aws_account_id >>
+        id: aws_account_id
+        immutable: true
+        label: AWS account
+        type: string
+        values: $values:ravion/aws_accounts
+      - default: << ref.input.aws_region >>
+        description: Region of the selected cluster. Must match the region in the cluster ARN, which Ravion cross-checks on every deploy.
+        id: aws_region
+        immutable: true
+        label: Region
+        type: string
+        values: $values:aws/regions
+      - collapsible: true
+        default: << ref.input.execution_environment_id >>
+        description: Terraform execution environment inherited from the selected EKS cluster.
+        id: execution_environment_id
+        label: Terraform execution environment
+        type: string
+        values: $values:ravion/execution_environments
+      - id: section_cluster_identity
+        label: EKS cluster
+        type: section
+      - default: <<ref.stack.output.cluster_name>>
+        id: cluster_name
+        immutable: true
+        label: EKS cluster name
+        placeholder: my-eks-cluster
+        required: true
+        type: string
+      - default: <<ref.stack.output.cluster_arn>>
+        description: Ravion resolves the owning AWS account and region from this ARN, and rejects a deploy whose cluster name or region disagrees with it.
+        id: cluster_arn
+        immutable: true
+        label: Cluster ARN
+        placeholder: arn:aws:eks:us-east-1:123456789012:cluster/my-eks-cluster
+        required: true
+        type: string
+      - default: <<ref.stack.output.cluster_endpoint>>
+        description: HTTPS endpoint of the Kubernetes API server. May be private-only; the deploy runner executes inside the cluster VPC.
+        id: cluster_endpoint
+        immutable: true
+        label: Cluster API endpoint
+        placeholder: https://ABCDEF0123456789ABCDEF0123456789.gr7.us-east-1.eks.amazonaws.com
+        required: true
+        type: string
+      - default: <<ref.stack.output.cluster_certificate_authority_data>>
+        description: Base64-encoded CA bundle used to verify the API server's TLS certificate. Public key material, not a credential.
+        id: cluster_certificate_authority_data
+        immutable: true
+        label: Cluster certificate authority data
+        placeholder: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCg...
+        required: true
+        type: string
+      - default: <<ref.stack.output.ravion_runner_role_arn>>
+        description: Stable IAM role the deploy runner assumes to obtain a cluster token. Registered as an EKS access entry by the cluster module.
+        id: ravion_runner_role_arn
+        immutable: true
+        label: Ravion Runner role ARN
+        placeholder: arn:aws:iam::123456789012:role/my-eks-cluster-ravion-runner
+        required: true
+        type: string
+      - collapsible: true
+        default: <<ref.stack.output.ravion_runner_security_group_id>>
+        description: Security group the deploy runner's network interface joins so it can reach the cluster API endpoint. Null when the cluster module did not create one, which is only workable if the endpoint is public or the execution environment supplies its own group.
+        id: ravion_runner_security_group_id
+        immutable: true
+        label: Ravion Runner security group ID
+        placeholder: sg-0123456789abcdef0
+        required: false
+        type: string
+      - default: <<ref.input.vpc_id>>
+        description: VPC the cluster runs in. Load balancer target groups must live in the same VPC as the pods they register.
+        id: vpc_id
+        immutable: true
+        label: VPC ID
+        placeholder: vpc-0123456789abcdef0
+        required: true
+        type: string
+      - default: <<ref.input.subnet_ids>>
+        description: Private subnets from the selected EKS cluster. A workload targeting Fargate launches pod network interfaces in these subnets; EKS Fargate does not support public subnets.
+        id: cluster_private_subnet_ids
+        immutable: true
+        label: Cluster private subnet IDs
+        placeholder: subnet-0123456789abcdef0
+        required: true
+        show_when:
+          compute_target: fargate
+        type: string_array
+    required: true
+    type: $ref:rvn-eks-cluster
+  - description: Select the EKS Add-ons module attached to the 
... diff truncated ...

rvn-lambda 1.1.0 -> 1.1.1

--- remote
+++ compiled
 build:
-  builder: '<< module.input.lambda_type != "edge" && module.input.package_type == "Image" && module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_inject_env_variables, cache_from: {tag: "dockerfile"}} : module.input.lambda_type != "edge" && module.input.package_type == "Image" && module.input.build_source == "nixpacks" ? {type: "nixpacks", install_cmd: module.input.nixpacks_install_cmd, build_cmd: module.input.nixpacks_build_cmd, start_cmd: module.input.nixpacks_start_cmd, config_file_path: module.input.nixpacks_config_file_path, build_path: module.input.nixpacks_build_path, nixpacks_version: module.input.nixpacks_version, nix_pkgs: module.input.nixpacks_nix_pkgs, apt_pkgs: module.input.nixpacks_apt_pkgs, nix_libs: module.input.nixpacks_nix_libs, cache_from: {tag: "nixpacks"}} : module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_inject_env_variables, output_directory: module.input.output_directory} : module.input.build_source == "nixpacks" ? {type: "nixpacks", install_cmd: module.input.nixpacks_install_cmd, build_cmd: module.input.nixpacks_build_cmd, config_file_path: module.input.nixpacks_config_file_path, build_path: module.input.nixpacks_build_path, nixpacks_version: module.input.nixpacks_version, nix_pkgs: module.input.nixpacks_nix_pkgs, apt_pkgs: module.input.nixpacks_apt_pkgs, nix_libs: module.input.nixpacks_nix_libs, output_directory: module.input.output_directory} : {type: "disabled"} >>'
+  builder: '<< module.input.lambda_type != "edge" && module.input.package_type == "Image" && module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_environment_variable_injection_enabled, cache_from: {tag: "dockerfile"}} : module.input.lambda_type != "edge" && module.input.package_type == "Image" && module.input.build_source == "nixpacks" ? {type: "nixpacks", install_cmd: module.input.nixpacks_install_cmd, build_cmd: module.input.nixpacks_build_cmd, start_cmd: module.input.nixpacks_start_cmd, config_file_path: module.input.nixpacks_config_file_path, build_path: module.input.nixpacks_build_path, nixpacks_version: module.input.nixpacks_version, nix_pkgs: module.input.nixpacks_nix_pkgs, apt_pkgs: module.input.nixpacks_apt_pkgs, nix_libs: module.input.nixpacks_nix_libs, cache_from: {tag: "nixpacks"}} : module.input.build_source == "dockerfile" ? {type: "dockerfile", dockerfile: module.input.dockerfile || "Dockerfile", context: module.input.dockerfile_context || ".", inject_env_variables_in_dockerfile: module.input.dockerfile_environment_variable_injection_enabled, output_directory: module.input.output_directory} : module.input.build_source == "nixpacks" ? {type: "nixpacks", install_cmd: module.input.nixpacks_install_cmd, build_cmd: module.input.nixpacks_build_cmd, config_file_path: module.input.nixpacks_config_file_path, build_path: module.input.nixpacks_build_path, nixpacks_version: module.input.nixpacks_version, nix_pkgs: module.input.nixpacks_nix_pkgs, apt_pkgs: module.input.nixpacks_apt_pkgs, nix_libs: module.input.nixpacks_nix_libs, output_directory: module.input.output_directory} : {type: "disabled"} >>'
   destinations: '<< module.input.lambda_type != "edge" && module.input.package_type == "Image" ? [{id: "ecr", type: "ecr", repository_arn: stack.output.ecr_repository_arn, tags: [pipeline.run.id + "-" + module.input.build_source, module.input.build_source]}] : [{id: "lambda-package", type: "s3", bucket: stack.output.code_bucket_id, directory: pipeline.run.id, region: stack.output.region}] >>'
   environment_variables: << module.input.build_environment_variables >>
   infrastructure:
-    ami: << module.input.build_ami || nil >>
+    ami: << module.input.build_ami_id || nil >>
     aws_account_id: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_account_id >>"
     execution_environment_id: << module.input.build_execution_environment_id || module.input.execution_environment_id >>
-    instance_size: << module.input.build_instance_size >>
+    instance_size: << module.input.build_instance_type >>
     permissions: '<< module.input.build_iam_policy_arns ? (module.input.build_default_policies_enabled ? {"attach": module.input.build_iam_policy_arns} : {"replace": module.input.build_iam_policy_arns}) : nil >>'
     region: "<< module.input.build_execution_environment_id || module.input.execution_environment_id ? nil : module.input.aws_region >>"
-    type: << module.input.build_infrastructure_type >>
+    type: << module.input.build_capacity_type >>
   inputs:
     - description: Defaults to repo default branch
       id: branch
@@
     type: object
   - default: false
     description: Pass build environment variables into Dockerfile builds as build arguments.
-    id: dockerfile_inject_env_variables
+    id: dockerfile_environment_variable_injection_enabled
     label: Inject environment variables in Dockerfile
     show_when:
       build_source: dockerfile
@@
     type: section
   - default: ec2
     description: Use on-demand EC2 for predictable availability or EC2 Spot for lower cost with possible capacity delays or interruption.
-    id: build_infrastructure_type
-    label: Builder instance type
+    id: build_capacity_type
+    label: Builder capacity type
     required: true
     show_when:
       build_source:
@@
         value: ec2-spot
   - default: c7a.4xlarge
     description: EC2 instance type for builds. Start with the default value, then increase or decrease it based on the resource usage report at the end of builds.
-    id: build_instance_size
-    label: Builder instance size
+    id: build_instance_type
+    label: Builder instance type
     no_options_message: Select an AWS account and region to load available EC2 instance types.
     required: true
     show_when:
@@
     values: $values:ravion/execution_environments
   - collapsible: true
     description: Optional AMI ID for build runners. Leave empty to use the default runner image.
-    id: build_ami
+    id: build_ami_id
     label: Builder AMI
     required: false
     show_when:
@@
         - railpack
         - nixpacks
     type: string
-  - default: true
+  - collapsible: true
+    default: true
     description: The step's built-in policies (ECR/S3 access, CloudWatch agent) stay attached alongside your Builder IAM policies. Turn off to run the build with only the policies listed below.
     id: build_default_policies_enabled
     label: Include default build policies
@@
 
   The Lambda Function module creates an AWS Lambda function, execution role, CloudWatch log group, optional artifact bucket, and a live alias that Ravion updates during deployments. Terraform provisions the long-lived function infrastructure with either a bootstrap zip package or a bootstrap container image. Deployments publish a new function version and move the live alias.
 
-  Terraform source: [ravionhq/modules/compute/lambda](https://github.com/ravionhq/modules/tree/rvn-lambda@1.1.0/compute/lambda)
+  Terraform source: [ravionhq/modules/compute/lambda](https://github.com/ravionhq/modules/tree/rvn-lambda@1.1.1/compute/lambda)
 
   ## Use cases
 
@@
         base_path: compute/lambda
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-lambda@1.1.0
+        ref: rvn-lambda@1.1.1
         repo: https://github.com/ravionhq/modules
         stack_id: <<stack.id>>
         terraform_variables:

rvn-rds 1.2.0 -> 1.2.1

--- remote
+++ compiled
         value: sqlserver-web
   - description: "Examples: 15 for PostgreSQL or SQL Server, 8.0 for MySQL, 19 for Oracle."
     id: engine_major_version
-    immutable: true
     label: Engine major version
+    min_current_value: true
     placeholder: "15"
     required: true
     type: string
@@
   - [RDS DB instance classes](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html)
   - [RDS security](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.html)
   - [RDS monitoring](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Monitoring.html)
-  - [Terraform source](https://github.com/ravionhq/modules/tree/rvn-rds@1.2.0/database/rds)
+  - [Terraform source](https://github.com/ravionhq/modules/tree/rvn-rds@1.2.1/database/rds)
 stack:
   pipelines:
     change:
@@
         base_path: database/rds
         branch: main
         execution_environment_id: << module.input.execution_environment_id >>
-        ref: rvn-rds@1.2.0
+        ref: rvn-rds@1.2.1
         repo: https://github.com/ravionhq/modules
         stack_id: <<stack.id>>
         terraform_variables:

Module Category Changes

diff --git a/tools/ravion-modules/src/module-categories.ts b/tools/ravion-modules/src/module-categories.ts
index eb0382c..737a97c 100644
--- a/tools/ravion-modules/src/module-categories.ts
+++ b/tools/ravion-modules/src/module-categories.ts
@@ -13,7 +13,7 @@ export const MODULE_CATEGORIES: readonly ModuleCategorySpec[] = [
     name: "Web server",
     description: "For websites, HTTP APIs, and services reached through a browser or web client.",
     sortOrder: 10,
-    definitionTypes: ["rvn-ec2-service", "rvn-ecs-nlb", "rvn-ecs-web"],
+    definitionTypes: ["rvn-ec2-service", "rvn-ecs-nlb", "rvn-ecs-web", "rvn-eks-web"],
   },
   {
     givenId: "tcp-udp-server",
@@ -28,7 +28,7 @@ export const MODULE_CATEGORIES: readonly ModuleCategorySpec[] = [
     name: "Worker",
     description: "For queue consumers, scheduled jobs, and background processes without public endpoints.",
     sortOrder: 30,
-    definitionTypes: ["rvn-ec2-service", "rvn-ecs-worker"],
+    definitionTypes: ["rvn-ec2-service", "rvn-ecs-worker", "rvn-eks-cron", "rvn-eks-worker"],
   },
   {
     givenId: "function",
@@ -70,7 +70,7 @@ export const MODULE_CATEGORIES: readonly ModuleCategorySpec[] = [
     name: "Cluster",
     description: "For services that share container capacity, load balancers, and placement configuration.",
     sortOrder: 90,
-    definitionTypes: ["rvn-ecs-cluster"],
+    definitionTypes: ["rvn-ecs-cluster", "rvn-eks-cluster", "rvn-eks-addons"],
   },
   {
     givenId: "network",

…sion

The chart (0.4.0+) re-emits the running image on upgrade; the module
pins the chart, not the agent. beacon_image_tag is documented as the
one deliberate pin.
The chart now keeps the running agent image across helm upgrades, so an
add-ons apply never moves the agent version, and it carries
httpProxy.credentials for rendering Grafana Cloud and in-cluster
Prometheus through the agent.
… a plain pin

The release no longer ignores changes to `set`. That lifecycle rule, there
since Beacon was added, froze the first image tag ever applied into the
state for good: an instance whose advanced variables once carried
beacon_image_tag=v0.2.0 was rolled back to that image on every upgrade,
and the last two applies wedged on it (helm wait timed out) because the
registry it named no longer holds that tag. A pin is now asserted while
configured and released when removed.

Chart 0.4.1 pins: it preserves the running image whole (registry and
tag) and only for a settled rollout, so a stale image.repository override
cannot make it re-render a tag that registry never held, and a wedged
release takes the floor so a plain re-apply repairs it.
@flybayer
flybayer self-requested a review August 20, 2026 15:24
Stop forcing isGlobalPublished on later publishes; only set global on initial publication when global is true (default). Mark EKS definitions global: false.
Align the cluster definition type, file name, refs, docs, and category metadata with the cluster naming pattern used by ECS.

@flybayer flybayer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

  • change capacity provider to support fargate better like ecs?

  • add support to use $values in string array for ec2 instance types

  • 'Ravion Runner security group' field and description is confusing. feels like it shouldn't even be a field option

  • add defined fields for fargate profiles and access entries instead of plain objects

    image.png

Chart source is git with repo_url/branch/ref/base_path, the definition
discriminator is type, region is derived from cluster_arn, metric and log
sources are amp / eks_prometheus / eks_loki with links under source, and
the dynamic values key is aws/eks-versions.
A terraform_data resource with a destroy-time provisioner runs helm
uninstall against the cluster, authenticated with the cluster's
ravion-runner role, before the target group, listener rule and repository
are removed. Wired into every EKS workload stack under the same release
identity the deploy block installs with.
…lity

# Conflicts:
#	tools/ravion-modules/src/authoring-schema.ts
#	tools/ravion-modules/src/compiler.ts
#	tools/ravion-modules/src/publish.ts
#	tools/ravion-modules/test/authoring-schema.test.ts
#	tools/ravion-modules/test/compiler.test.ts
#	tools/ravion-modules/test/publish.test.ts
#	tools/ravion-modules/test/readme.test.ts
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.

2 participants