Skip to content

Commit 8512ab0

Browse files
fix(runner-stack): preserve multi-app credentials
1 parent 210fec2 commit 8512ab0

23 files changed

Lines changed: 298 additions & 179 deletions

modules/multi-runner/tests/provider-routing.tftest.hcl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,21 @@ run "experimental_v2_routes_through_provider_stack" {
147147
command = plan
148148

149149
variables {
150+
additional_github_apps = [{
151+
id_ssm = {
152+
name = "/github-runner/additional-app-id"
153+
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/github-runner/additional-app-id"
154+
}
155+
key_base64_ssm = {
156+
name = "/github-runner/additional-key-base64"
157+
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/github-runner/additional-key-base64"
158+
}
159+
installation_id_ssm = {
160+
name = "/github-runner/additional-installation-id"
161+
arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/github-runner/additional-installation-id"
162+
}
163+
}]
164+
150165
experimental = {
151166
multi_runner_config_v2 = {
152167
linux = {
@@ -246,6 +261,16 @@ run "experimental_v2_routes_through_provider_stack" {
246261
error_message = "Experimental multi_runner_config_v2 entries must dispatch through module.runner_stacks."
247262
}
248263

264+
assert {
265+
condition = (
266+
length(local.github_app_parameters.id) == 2
267+
&& module.runner_stacks["linux"].scale_up.lambda.environment[0].variables["PARAMETER_GITHUB_APP_ID_NAME"] == join(":", [for p in local.github_app_parameters.id : p.name])
268+
&& module.runner_stacks["linux"].scale_down.lambda.environment[0].variables["PARAMETER_GITHUB_APP_KEY_BASE64_NAME"] == join(":", [for p in local.github_app_parameters.key_base64 : p.name])
269+
&& module.runner_stacks["linux"].pool.lambda.environment[0].variables["PARAMETER_GITHUB_APP_INSTALLATION_ID_NAME"] == join(":", [for p in local.github_app_parameters.installation_id : p != null ? p.name : ""])
270+
)
271+
error_message = "Experimental v2 control-plane Lambdas must preserve the complete multi-app parameter lists from the shared multi-runner configuration."
272+
}
273+
249274
assert {
250275
condition = keys(aws_sqs_queue.queued_builds) == ["linux"]
251276
error_message = "Common queue ownership must preserve the experimental runner configuration key."

modules/runner-stack/README.md

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

modules/runner-stack/job-retry/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ No modules.
5050

5151
| Name | Description | Type | Default | Required |
5252
|------|-------------|------|---------|:--------:|
53-
| <a name="input_config"></a> [config](#input\_config) | Provider-neutral job-retry configuration assembled by runner-stack.<br/><br/>- `prefix`: Prefix used to name job-retry resources.<br/>- `aws_partition`: AWS partition used to construct the Lambda VPC managed-policy ARN.<br/>- `lambda.artifact.zip`: Resolved local control-plane archive.<br/>- `lambda.artifact.s3.bucket`: Optional S3 bucket containing the Lambda archive.<br/>- `lambda.artifact.s3.key`: Object key of the Lambda archive.<br/>- `lambda.artifact.s3.object_version`: Optional object version of the Lambda archive.<br/>- `lambda.runtime`: Runtime used by the job-retry Lambda.<br/>- `lambda.architecture`: Instruction-set architecture used by the job-retry Lambda.<br/>- `lambda.memory_size`: Memory allocated to the job-retry Lambda.<br/>- `lambda.timeout`: Lambda timeout and retry-queue visibility timeout in seconds.<br/>- `lambda.reserved_concurrent_executions`: Reserved concurrency for the Lambda. Use `-1` for unreserved concurrency.<br/>- `lambda.environment_variables`: Additional Lambda environment variables. Required job-retry variables override matching keys.<br/>- `lambda.vpc.subnet_ids`: Subnets used for Lambda VPC configuration.<br/>- `lambda.vpc.security_group_ids`: Security groups used for Lambda VPC configuration.<br/>- `lambda.role.path`: IAM path used for the job-retry Lambda role.<br/>- `lambda.role.permissions_boundary`: Optional permissions boundary for the Lambda role.<br/>- `lambda.role.principals`: Extra principals allowed to assume the Lambda role, for example during local testing.<br/>- `runner.name_prefix`: Prefix used to identify runners belonging to this runner configuration.<br/>- `github.organization_runners`: Enables organization runners.<br/>- `github.enterprise_server.url`: Optional GitHub Enterprise Server URL.<br/>- `github.user_agent`: Optional User-Agent sent to GitHub.<br/>- `github.app_parameters.key_base64`: Name and ARN of the GitHub App private-key parameter.<br/>- `github.app_parameters.id`: Name and ARN of the GitHub App ID parameter.<br/>- `queue.build`: URL and ARN of the build queue to which retry messages are published.<br/>- `queue.event_source_mapping.batch_size`: Maximum records delivered per job-retry invocation.<br/>- `queue.event_source_mapping.maximum_batching_window_in_seconds`: Maximum event batching window.<br/>- `queue.encryption`: Server-side encryption configuration for the retry queue.<br/>- `ssm.kms_key`: Optional KMS key used by the job-retry IAM policy.<br/>- `observability.logs`: Logging level, retention, encryption, and log-class configuration.<br/>- `observability.tracing`: Lambda X-Ray and tracing-helper configuration.<br/>- `observability.metrics`: Metrics enablement, namespace, and job-retry metric configuration.<br/>- `tags.resources`: Tags for the job-retry Lambda role and component resources.<br/>- `tags.lambda`: Tags for the job-retry Lambda function.<br/>- `tags.log_group`: Tags for the job-retry log group.<br/>- `tags.queue`: Tags for the retry queue.<br/>- `tags.event_source_mapping`: Tags for the retry-queue event-source mapping. | <pre>object({<br/> prefix = string<br/> aws_partition = string<br/> lambda = object({<br/> artifact = object({<br/> zip = string<br/> s3 = object({<br/> bucket = optional(string, null)<br/> key = optional(string, null)<br/> object_version = optional(string, null)<br/> })<br/> })<br/> runtime = string<br/> architecture = string<br/> memory_size = number<br/> timeout = number<br/> reserved_concurrent_executions = number<br/> environment_variables = map(string)<br/> vpc = object({<br/> subnet_ids = list(string)<br/> security_group_ids = list(string)<br/> })<br/> role = object({<br/> path = string<br/> permissions_boundary = optional(string, null)<br/> principals = list(object({<br/> type = string<br/> identifiers = list(string)<br/> }))<br/> })<br/> })<br/> runner = object({<br/> name_prefix = string<br/> })<br/> github = object({<br/> organization_runners = bool<br/> enterprise_server = object({<br/> url = optional(string, null)<br/> })<br/> user_agent = optional(string, null)<br/> app_parameters = object({<br/> key_base64 = object({<br/> name = string<br/> arn = string<br/> })<br/> id = object({<br/> name = string<br/> arn = string<br/> })<br/> })<br/> })<br/> queue = object({<br/> build = object({<br/> url = string<br/> arn = string<br/> })<br/> event_source_mapping = object({<br/> batch_size = number<br/> maximum_batching_window_in_seconds = number<br/> })<br/> encryption = object({<br/> sqs_managed_sse_enabled = bool<br/> kms_master_key_id = optional(string, null)<br/> kms_data_key_reuse_period_seconds = optional(number, null)<br/> })<br/> })<br/> ssm = object({<br/> kms_key = optional(object({<br/> arn = string<br/> }), null)<br/> })<br/> observability = object({<br/> logs = object({<br/> level = string<br/> retention_in_days = number<br/> kms_key_id = optional(string, null)<br/> class = string<br/> })<br/> tracing = object({<br/> mode = optional(string, null)<br/> capture_http_requests = bool<br/> capture_error = bool<br/> })<br/> metrics = object({<br/> enable = bool<br/> namespace = string<br/> metric = object({<br/> enable_github_app_rate_limit = bool<br/> enable_job_retry = bool<br/> })<br/> })<br/> })<br/> tags = object({<br/> resources = map(string)<br/> lambda = map(string)<br/> log_group = map(string)<br/> queue = map(string)<br/> event_source_mapping = map(string)<br/> })<br/> })</pre> | n/a | yes |
53+
| <a name="input_config"></a> [config](#input\_config) | Provider-neutral job-retry configuration assembled by runner-stack.<br/><br/>- `prefix`: Prefix used to name job-retry resources.<br/>- `aws_partition`: AWS partition used to construct the Lambda VPC managed-policy ARN.<br/>- `lambda.artifact.zip`: Resolved local control-plane archive.<br/>- `lambda.artifact.s3.bucket`: Optional S3 bucket containing the Lambda archive.<br/>- `lambda.artifact.s3.key`: Object key of the Lambda archive.<br/>- `lambda.artifact.s3.object_version`: Optional object version of the Lambda archive.<br/>- `lambda.runtime`: Runtime used by the job-retry Lambda.<br/>- `lambda.architecture`: Instruction-set architecture used by the job-retry Lambda.<br/>- `lambda.memory_size`: Memory allocated to the job-retry Lambda.<br/>- `lambda.timeout`: Lambda timeout and retry-queue visibility timeout in seconds.<br/>- `lambda.reserved_concurrent_executions`: Reserved concurrency for the Lambda. Use `-1` for unreserved concurrency.<br/>- `lambda.environment_variables`: Additional Lambda environment variables. Required job-retry variables override matching keys.<br/>- `lambda.vpc.subnet_ids`: Subnets used for Lambda VPC configuration.<br/>- `lambda.vpc.security_group_ids`: Security groups used for Lambda VPC configuration.<br/>- `lambda.role.path`: IAM path used for the job-retry Lambda role.<br/>- `lambda.role.permissions_boundary`: Optional permissions boundary for the Lambda role.<br/>- `lambda.role.principals`: Extra principals allowed to assume the Lambda role, for example during local testing.<br/>- `runner.name_prefix`: Prefix used to identify runners belonging to this runner configuration.<br/>- `github.organization_runners`: Enables organization runners.<br/>- `github.enterprise_server.url`: Optional GitHub Enterprise Server URL.<br/>- `github.user_agent`: Optional User-Agent sent to GitHub.<br/>- `github.app_parameters.key_base64`: Ordered Parameter Store references for GitHub App private keys.<br/>- `github.app_parameters.id`: Ordered Parameter Store references for GitHub App IDs.<br/>- `github.app_parameters.installation_id`: Ordered optional Parameter Store references for GitHub App installation IDs.<br/>- `queue.build`: URL and ARN of the build queue to which retry messages are published.<br/>- `queue.event_source_mapping.batch_size`: Maximum records delivered per job-retry invocation.<br/>- `queue.event_source_mapping.maximum_batching_window_in_seconds`: Maximum event batching window.<br/>- `queue.encryption`: Server-side encryption configuration for the retry queue.<br/>- `ssm.kms_key`: Optional KMS key used by the job-retry IAM policy.<br/>- `observability.logs`: Logging level, retention, encryption, and log-class configuration.<br/>- `observability.tracing`: Lambda X-Ray and tracing-helper configuration.<br/>- `observability.metrics`: Metrics enablement, namespace, and job-retry metric configuration.<br/>- `tags.resources`: Tags for the job-retry Lambda role and component resources.<br/>- `tags.lambda`: Tags for the job-retry Lambda function.<br/>- `tags.log_group`: Tags for the job-retry log group.<br/>- `tags.queue`: Tags for the retry queue.<br/>- `tags.event_source_mapping`: Tags for the retry-queue event-source mapping. | <pre>object({<br/> prefix = string<br/> aws_partition = string<br/> lambda = object({<br/> artifact = object({<br/> zip = string<br/> s3 = object({<br/> bucket = optional(string, null)<br/> key = optional(string, null)<br/> object_version = optional(string, null)<br/> })<br/> })<br/> runtime = string<br/> architecture = string<br/> memory_size = number<br/> timeout = number<br/> reserved_concurrent_executions = number<br/> environment_variables = map(string)<br/> vpc = object({<br/> subnet_ids = list(string)<br/> security_group_ids = list(string)<br/> })<br/> role = object({<br/> path = string<br/> permissions_boundary = optional(string, null)<br/> principals = list(object({<br/> type = string<br/> identifiers = list(string)<br/> }))<br/> })<br/> })<br/> runner = object({<br/> name_prefix = string<br/> })<br/> github = object({<br/> organization_runners = bool<br/> enterprise_server = object({<br/> url = optional(string, null)<br/> })<br/> user_agent = optional(string, null)<br/> app_parameters = object({<br/> key_base64 = list(map(string))<br/> id = list(map(string))<br/> installation_id = list(object({ name = string, arn = string }))<br/> })<br/> })<br/> queue = object({<br/> build = object({<br/> url = string<br/> arn = string<br/> })<br/> event_source_mapping = object({<br/> batch_size = number<br/> maximum_batching_window_in_seconds = number<br/> })<br/> encryption = object({<br/> sqs_managed_sse_enabled = bool<br/> kms_master_key_id = optional(string, null)<br/> kms_data_key_reuse_period_seconds = optional(number, null)<br/> })<br/> })<br/> ssm = object({<br/> kms_key = optional(object({<br/> arn = string<br/> }), null)<br/> })<br/> observability = object({<br/> logs = object({<br/> level = string<br/> retention_in_days = number<br/> kms_key_id = optional(string, null)<br/> class = string<br/> })<br/> tracing = object({<br/> mode = optional(string, null)<br/> capture_http_requests = bool<br/> capture_error = bool<br/> })<br/> metrics = object({<br/> enable = bool<br/> namespace = string<br/> metric = object({<br/> enable_github_app_rate_limit = bool<br/> enable_job_retry = bool<br/> })<br/> })<br/> })<br/> tags = object({<br/> resources = map(string)<br/> lambda = map(string)<br/> log_group = map(string)<br/> queue = map(string)<br/> event_source_mapping = map(string)<br/> })<br/> })</pre> | n/a | yes |
5454

5555
## Outputs
5656

modules/runner-stack/job-retry/iam-policies.tf

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,11 @@ data "aws_iam_policy_document" "job_retry" {
5757
"ssm:GetParameters",
5858
]
5959

60-
resources = [
61-
var.config.github.app_parameters.key_base64.arn,
62-
var.config.github.app_parameters.id.arn,
63-
]
60+
resources = concat(
61+
[for p in var.config.github.app_parameters.id : p.arn],
62+
[for p in var.config.github.app_parameters.key_base64 : p.arn],
63+
[for p in var.config.github.app_parameters.installation_id : p.arn if p != null],
64+
)
6465
}
6566

6667
statement {

modules/runner-stack/job-retry/job-retry.tf

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@ locals {
1919
}
2020

2121
job_retry_environment_variables = {
22-
ENABLE_ORGANIZATION_RUNNERS = var.config.github.organization_runners
23-
ENABLE_METRIC_JOB_RETRY = var.config.observability.metrics.enable && var.config.observability.metrics.metric.enable_job_retry
24-
ENABLE_METRIC_GITHUB_APP_RATE_LIMIT = var.config.observability.metrics.enable && var.config.observability.metrics.metric.enable_github_app_rate_limit
25-
GHES_URL = var.config.github.enterprise_server.url
26-
USER_AGENT = var.config.github.user_agent
27-
JOB_QUEUE_SCALE_UP_URL = var.config.queue.build.url
28-
PARAMETER_GITHUB_APP_ID_NAME = var.config.github.app_parameters.id.name
29-
PARAMETER_GITHUB_APP_KEY_BASE64_NAME = var.config.github.app_parameters.key_base64.name
30-
RUNNER_NAME_PREFIX = var.config.runner.name_prefix
22+
ENABLE_ORGANIZATION_RUNNERS = var.config.github.organization_runners
23+
ENABLE_METRIC_JOB_RETRY = var.config.observability.metrics.enable && var.config.observability.metrics.metric.enable_job_retry
24+
ENABLE_METRIC_GITHUB_APP_RATE_LIMIT = var.config.observability.metrics.enable && var.config.observability.metrics.metric.enable_github_app_rate_limit
25+
GHES_URL = var.config.github.enterprise_server.url
26+
USER_AGENT = var.config.github.user_agent
27+
JOB_QUEUE_SCALE_UP_URL = var.config.queue.build.url
28+
PARAMETER_GITHUB_APP_ID_NAME = join(":", [for p in var.config.github.app_parameters.id : p.name])
29+
PARAMETER_GITHUB_APP_KEY_BASE64_NAME = join(":", [for p in var.config.github.app_parameters.key_base64 : p.name])
30+
PARAMETER_GITHUB_APP_INSTALLATION_ID_NAME = join(":", [for p in var.config.github.app_parameters.installation_id : p != null ? p.name : ""])
31+
RUNNER_NAME_PREFIX = var.config.runner.name_prefix
3132
}
3233

3334
environment_variables = merge(

0 commit comments

Comments
 (0)