' to add unique labels dynamically to runners. | `bool` | `false` | no |
| [eventbridge](#input\_eventbridge) | Enable the use of EventBridge by the module. By enabling this feature events will be put on the EventBridge by the webhook instead of directly dispatching to queues for scaling. `enable`: Enable the EventBridge feature. `accept_events`: List can be used to only allow specific events to be putted on the EventBridge. By default all events, empty list will be be interpreted as all events. | object({ enable = optional(bool, false) accept_events = optional(list(string), null) }) | n/a | yes |
| [github\_app\_parameters](#input\_github\_app\_parameters) | Parameter Store for GitHub App Parameters. | object({ webhook_secret = map(string) }) | n/a | yes |
| [kms\_key\_arn](#input\_kms\_key\_arn) | Optional CMK Key ARN to be used for Parameter Store. | `string` | `null` | no |
diff --git a/modules/webhook/direct/README.md b/modules/webhook/direct/README.md
index 55ca0473da..984e2fa88a 100644
--- a/modules/webhook/direct/README.md
+++ b/modules/webhook/direct/README.md
@@ -40,7 +40,7 @@ No modules.
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
-| [config](#input\_config) | Configuration object for all variables. | object({ prefix = string archive = optional(object({ enable = optional(bool, true) retention_days = optional(number, 7) }), {}) tags = optional(map(string), {}) lambda_subnet_ids = optional(list(string), []) lambda_security_group_ids = optional(list(string), []) sqs_job_queues_arns = list(string) lambda_zip = optional(string, null) lambda_memory_size = optional(number, 256) lambda_timeout = optional(number, 10) role_permissions_boundary = optional(string, null) role_path = optional(string, null) logging_retention_in_days = optional(number, 180) logging_kms_key_id = optional(string, null) log_class = optional(string, "STANDARD") lambda_s3_bucket = optional(string, null) lambda_s3_key = optional(string, null) lambda_s3_object_version = optional(string, null) lambda_apigateway_access_log_settings = optional(object({ destination_arn = string format = string }), null) repository_white_list = optional(list(string), []) kms_key_arn = optional(string, null) log_level = optional(string, "info") lambda_runtime = optional(string, "nodejs24.x") aws_partition = optional(string, "aws") lambda_architecture = optional(string, "arm64") github_app_parameters = object({ webhook_secret = map(string) }) tracing_config = optional(object({ mode = optional(string, null) capture_http_requests = optional(bool, false) capture_error = optional(bool, false) }), {}) lambda_tags = optional(map(string), {}) api_gw_source_arn = string ssm_parameter_runner_matcher_config = list(object({ name = string arn = string version = string })) }) | n/a | yes |
+| [config](#input\_config) | Configuration object for all variables. | object({ prefix = string archive = optional(object({ enable = optional(bool, true) retention_days = optional(number, 7) }), {}) tags = optional(map(string), {}) lambda_subnet_ids = optional(list(string), []) lambda_security_group_ids = optional(list(string), []) sqs_job_queues_arns = list(string) lambda_zip = optional(string, null) lambda_memory_size = optional(number, 256) lambda_timeout = optional(number, 10) role_permissions_boundary = optional(string, null) role_path = optional(string, null) logging_retention_in_days = optional(number, 180) logging_kms_key_id = optional(string, null) log_class = optional(string, "STANDARD") lambda_s3_bucket = optional(string, null) lambda_s3_key = optional(string, null) lambda_s3_object_version = optional(string, null) lambda_apigateway_access_log_settings = optional(object({ destination_arn = string format = string }), null) repository_white_list = optional(list(string), []) kms_key_arn = optional(string, null) log_level = optional(string, "info") lambda_runtime = optional(string, "nodejs24.x") aws_partition = optional(string, "aws") lambda_architecture = optional(string, "arm64") github_app_parameters = object({ webhook_secret = map(string) }) tracing_config = optional(object({ mode = optional(string, null) capture_http_requests = optional(bool, false) capture_error = optional(bool, false) }), {}) lambda_tags = optional(map(string), {}) api_gw_source_arn = string ssm_parameter_runner_matcher_config = list(object({ name = string arn = string version = string })) enable_dynamic_labels = optional(bool, false) }) | n/a | yes |
## Outputs
diff --git a/modules/webhook/direct/variables.tf b/modules/webhook/direct/variables.tf
index 4c4088eb1b..2283f37eb7 100644
--- a/modules/webhook/direct/variables.tf
+++ b/modules/webhook/direct/variables.tf
@@ -47,5 +47,6 @@ variable "config" {
arn = string
version = string
}))
+ enable_dynamic_labels = optional(bool, false)
})
}
diff --git a/modules/webhook/direct/webhook.tf b/modules/webhook/direct/webhook.tf
index 912829019a..91d41e4765 100644
--- a/modules/webhook/direct/webhook.tf
+++ b/modules/webhook/direct/webhook.tf
@@ -19,6 +19,7 @@ resource "aws_lambda_function" "webhook" {
environment {
variables = {
for k, v in {
+ ENABLE_DYNAMIC_LABELS = var.config.enable_dynamic_labels
LOG_LEVEL = var.config.log_level
POWERTOOLS_LOGGER_LOG_EVENT = var.config.log_level == "debug" ? "true" : "false"
POWERTOOLS_TRACE_ENABLED = var.config.tracing_config.mode != null ? true : false
diff --git a/modules/webhook/eventbridge/README.md b/modules/webhook/eventbridge/README.md
index fa6fa9b7f3..4929bfb935 100644
--- a/modules/webhook/eventbridge/README.md
+++ b/modules/webhook/eventbridge/README.md
@@ -54,7 +54,7 @@ No modules.
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
-| [config](#input\_config) | Configuration object for all variables. | object({ prefix = string archive = optional(object({ enable = optional(bool, true) retention_days = optional(number, 7) }), {}) tags = optional(map(string), {}) lambda_subnet_ids = optional(list(string), []) lambda_security_group_ids = optional(list(string), []) sqs_job_queues_arns = list(string) lambda_zip = optional(string, null) lambda_memory_size = optional(number, 256) lambda_timeout = optional(number, 10) role_permissions_boundary = optional(string, null) role_path = optional(string, null) logging_retention_in_days = optional(number, 180) logging_kms_key_id = optional(string, null) log_class = optional(string, "STANDARD") lambda_s3_bucket = optional(string, null) lambda_s3_key = optional(string, null) lambda_s3_object_version = optional(string, null) lambda_apigateway_access_log_settings = optional(object({ destination_arn = string format = string }), null) repository_white_list = optional(list(string), []) kms_key_arn = optional(string, null) log_level = optional(string, "info") lambda_runtime = optional(string, "nodejs24.x") aws_partition = optional(string, "aws") lambda_architecture = optional(string, "arm64") github_app_parameters = object({ webhook_secret = map(string) }) tracing_config = optional(object({ mode = optional(string, null) capture_http_requests = optional(bool, false) capture_error = optional(bool, false) }), {}) lambda_tags = optional(map(string), {}) api_gw_source_arn = string ssm_parameter_runner_matcher_config = list(object({ name = string arn = string version = string })) accept_events = optional(list(string), null) }) | n/a | yes |
+| [config](#input\_config) | Configuration object for all variables. | object({ prefix = string archive = optional(object({ enable = optional(bool, true) retention_days = optional(number, 7) }), {}) tags = optional(map(string), {}) lambda_subnet_ids = optional(list(string), []) lambda_security_group_ids = optional(list(string), []) sqs_job_queues_arns = list(string) lambda_zip = optional(string, null) lambda_memory_size = optional(number, 256) lambda_timeout = optional(number, 10) role_permissions_boundary = optional(string, null) role_path = optional(string, null) logging_retention_in_days = optional(number, 180) logging_kms_key_id = optional(string, null) log_class = optional(string, "STANDARD") lambda_s3_bucket = optional(string, null) lambda_s3_key = optional(string, null) lambda_s3_object_version = optional(string, null) lambda_apigateway_access_log_settings = optional(object({ destination_arn = string format = string }), null) repository_white_list = optional(list(string), []) kms_key_arn = optional(string, null) log_level = optional(string, "info") lambda_runtime = optional(string, "nodejs24.x") aws_partition = optional(string, "aws") lambda_architecture = optional(string, "arm64") github_app_parameters = object({ webhook_secret = map(string) }) tracing_config = optional(object({ mode = optional(string, null) capture_http_requests = optional(bool, false) capture_error = optional(bool, false) }), {}) lambda_tags = optional(map(string), {}) api_gw_source_arn = string ssm_parameter_runner_matcher_config = list(object({ name = string arn = string version = string })) accept_events = optional(list(string), null) enable_dynamic_labels = optional(bool, false) }) | n/a | yes |
## Outputs
diff --git a/modules/webhook/eventbridge/dispatcher.tf b/modules/webhook/eventbridge/dispatcher.tf
index f199e129e9..98fbb893ee 100644
--- a/modules/webhook/eventbridge/dispatcher.tf
+++ b/modules/webhook/eventbridge/dispatcher.tf
@@ -37,6 +37,7 @@ resource "aws_lambda_function" "dispatcher" {
environment {
variables = {
for k, v in {
+ ENABLE_DYNAMIC_LABELS = var.config.enable_dynamic_labels
LOG_LEVEL = var.config.log_level
POWERTOOLS_LOGGER_LOG_EVENT = var.config.log_level == "debug" ? "true" : "false"
POWERTOOLS_SERVICE_NAME = "${var.config.prefix}-dispatcher"
diff --git a/modules/webhook/eventbridge/variables.tf b/modules/webhook/eventbridge/variables.tf
index 907523d67d..9f9ab7ba56 100644
--- a/modules/webhook/eventbridge/variables.tf
+++ b/modules/webhook/eventbridge/variables.tf
@@ -47,6 +47,7 @@ variable "config" {
arn = string
version = string
}))
- accept_events = optional(list(string), null)
+ accept_events = optional(list(string), null)
+ enable_dynamic_labels = optional(bool, false)
})
}
diff --git a/modules/webhook/variables.tf b/modules/webhook/variables.tf
index a7b8f8173e..bf50ceeb41 100644
--- a/modules/webhook/variables.tf
+++ b/modules/webhook/variables.tf
@@ -225,3 +225,10 @@ EOF
accept_events = optional(list(string), null)
})
}
+
+variable "enable_dynamic_labels" {
+ description = "Experimental! Can be removed / changed without trigger a major release. Enable dynamic labels with 'ghr-' prefix. When enabled, jobs can use 'ghr-ec2-:' labels to dynamically configure EC2 instances (e.g., 'ghr-ec2-instance-type:t3.large') and 'ghr-run-' to add unique labels dynamically to runners."
+ type = bool
+ default = false
+}
+
diff --git a/modules/webhook/webhook.tf b/modules/webhook/webhook.tf
index 0516a98c21..6c8fe88c97 100644
--- a/modules/webhook/webhook.tf
+++ b/modules/webhook/webhook.tf
@@ -86,6 +86,7 @@ module "direct" {
version = p.version
}
]
+ enable_dynamic_labels = var.enable_dynamic_labels
}
}
@@ -128,7 +129,8 @@ module "eventbridge" {
version = p.version
}
]
- accept_events = var.eventbridge.accept_events
+ accept_events = var.eventbridge.accept_events
+ enable_dynamic_labels = var.enable_dynamic_labels
}
}
diff --git a/variables.tf b/variables.tf
index d739e916fb..fd6605230b 100644
--- a/variables.tf
+++ b/variables.tf
@@ -92,7 +92,7 @@ variable "runner_disable_default_labels" {
}
variable "runner_extra_labels" {
- description = "Extra (custom) labels for the runners (GitHub). Separate each label by a comma. Labels checks on the webhook can be enforced by setting `enable_workflow_job_labels_check`. GitHub read-only labels should not be provided."
+ description = "Extra (custom) labels for the runners (GitHub). Separate each label by a comma. Labels checks on the webhook can be enforced by setting `enable_workflow_job_labels_check`. GitHub read-only labels should not be provided. Note: labels starting with `ghr-` are ignored during webhook label matching when `enable_dynamic_labels` is enabled."
type = list(string)
default = []
@@ -673,6 +673,12 @@ variable "enable_ephemeral_runners" {
default = false
}
+variable "enable_dynamic_labels" {
+ description = "Experimental! Can be removed / changed without trigger a major release. Enable dynamic EC2 configs based on workflow job labels. When enabled, jobs can request specific configs via the 'gh-ec2-:' label (e.g., 'gh-ec2-instance-type:t3.large'). When enabled, labels starting with `ghr-` are ignored during webhook label matching."
+ type = bool
+ default = false
+}
+
variable "enable_job_queued_check" {
description = "Only scale if the job event received by the scale up lambda is in the queued state. By default enabled for non ephemeral runners and disabled for ephemeral. Set this variable to overwrite the default behavior."
type = bool