Skip to content
This repository was archived by the owner on Jan 16, 2025. It is now read-only.

Commit 859fa38

Browse files
authored
feat: Ignore github managed labels and add check disable option (#1244)
1 parent 570949a commit 859fa38

File tree

9 files changed

+82
-20
lines changed

9 files changed

+82
-20
lines changed

Diff for: README.md

+19-2
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,23 @@ No requirements.
342342
| aws | n/a |
343343
| random | n/a |
344344

345+
## Modules
346+
347+
| Name | Source | Version |
348+
|------|--------|---------|
349+
| runner_binaries | ./modules/runner-binaries-syncer | |
350+
| runners | ./modules/runners | |
351+
| ssm | ./modules/ssm | |
352+
| webhook | ./modules/webhook | |
353+
354+
## Resources
355+
356+
| Name |
357+
|------|
358+
| [aws_resourcegroups_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/resourcegroups_group) |
359+
| [aws_sqs_queue](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue) |
360+
| [random_string](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) |
361+
345362
## Inputs
346363

347364
| Name | Description | Type | Default | Required |
@@ -353,12 +370,13 @@ No requirements.
353370
| cloudwatch\_config | (optional) Replaces the module default cloudwatch log config. See https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html for details. | `string` | `null` | no |
354371
| create\_service\_linked\_role\_spot | (optional) create the serviced linked role for spot instances that is required by the scale-up lambda. | `bool` | `false` | no |
355372
| delay\_webhook\_event | The number of seconds the event accepted by the webhook is invisible on the queue before the scale up lambda will receive the event. | `number` | `30` | no |
373+
| disable\_check\_wokflow\_job\_labels | Disable the the check of workflow labels for received workflow job events. | `bool` | `false` | no |
356374
| enable\_cloudwatch\_agent | Enabling the cloudwatch agent on the ec2 runner instances, the runner contains default config. Configuration can be overridden via `cloudwatch_config`. | `bool` | `true` | no |
357375
| enable\_organization\_runners | Register runners to organization, instead of repo level | `bool` | `false` | no |
358376
| enable\_ssm\_on\_runners | Enable to allow access the runner instances for debugging purposes via SSM. Note that this adds additional permissions to the runner instances. | `bool` | `false` | no |
359377
| environment | A name that identifies the environment, used as prefix and for tagging. | `string` | n/a | yes |
378+
| ghes\_ssl\_verify | GitHub Enterprise SSL verification. Set to 'false' when custom certificate (chains) is used for GitHub Enterprise Server (insecure). | `bool` | `true` | no |
360379
| ghes\_url | GitHub Enterprise Server URL. Example: https://github.internal.co - DO NOT SET IF USING PUBLIC GITHUB | `string` | `null` | no |
361-
| ghes\_ssl\_verify | GitHub Enterprise SSL verification. Set to `false` when custom certificate (chains) is used for GitHub Enterprise Server (insecure). | `bool` | `true` | no |
362380
| github\_app | GitHub app parameters, see your github app. Ensure the key is the base64-encoded `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem`). | <pre>object({<br> key_base64 = string<br> id = string<br> client_id = string<br> client_secret = string<br> webhook_secret = string<br> })</pre> | n/a | yes |
363381
| idle\_config | List of time period that can be defined as cron expression to keep a minimum amount of runners active instead of scaling down to 0. By defining this list you can ensure that in time periods that match the cron expression within 5 seconds a runner is kept idle. | <pre>list(object({<br> cron = string<br> timeZone = string<br> idleCount = number<br> }))</pre> | `[]` | no |
364382
| instance\_profile\_path | The path that will be added to the instance\_profile, if not set the environment name will be used. | `string` | `null` | no |
@@ -415,7 +433,6 @@ No requirements.
415433
| runners | n/a |
416434
| ssm\_parameters | n/a |
417435
| webhook | n/a |
418-
419436
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
420437

421438
## Contribution

Diff for: main.tf

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ module "webhook" {
6060
lambda_timeout = var.webhook_lambda_timeout
6161
logging_retention_in_days = var.logging_retention_in_days
6262
runner_extra_labels = var.runner_extra_labels
63+
disable_check_wokflow_job_labels = var.disable_check_wokflow_job_labels
6364

6465
role_path = var.role_path
6566
role_permissions_boundary = var.role_permissions_boundary

Diff for: modules/webhook/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ No Modules.
6868
| Name | Description | Type | Default | Required |
6969
|------|-------------|------|---------|:--------:|
7070
| aws\_region | AWS region. | `string` | n/a | yes |
71+
| disable\_check\_wokflow\_job\_labels | Disable the the check of workflow labels. | `bool` | `false` | no |
7172
| environment | A name that identifies the environment, used as prefix and for tagging. | `string` | n/a | yes |
7273
| github\_app\_webhook\_secret\_arn | n/a | `string` | n/a | yes |
7374
| kms\_key\_arn | Optional CMK Key ARN to be used for Parameter Store. | `string` | `null` | no |
@@ -76,7 +77,7 @@ No Modules.
7677
| lambda\_zip | File location of the lambda zip file. | `string` | `null` | no |
7778
| logging\_retention\_in\_days | Specifies the number of days you want to retain log events for the lambda log group. Possible values are: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. | `number` | `7` | no |
7879
| repository\_white\_list | List of repositories allowed to use the github app | `list(string)` | `[]` | no |
79-
| role\_path | The path that will be added to the role, if not set the environment name will be used. | `string` | `null` | no |
80+
| role\_path | The path that will be added to the role; if not set, the environment name will be used. | `string` | `null` | no |
8081
| role\_permissions\_boundary | Permissions boundary that will be added to the created role for the lambda. | `string` | `null` | no |
8182
| runner\_extra\_labels | Extra labels for the runners (GitHub). Separate each label by a comma | `string` | `""` | no |
8283
| sqs\_build\_queue | SQS queue to publish accepted build events. | <pre>object({<br> id = string<br> arn = string<br> })</pre> | n/a | yes |

Diff for: modules/webhook/lambdas/webhook/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,4 @@
4242
"@octokit/webhooks": "^9.12.0",
4343
"aws-lambda": "^1.0.6"
4444
}
45-
}
45+
}

Diff for: modules/webhook/lambdas/webhook/src/webhook/handler.test.ts

+26-6
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ describe('handler', () => {
4646
});
4747

4848
describe('Test for workflowjob event: ', () => {
49+
beforeEach(() => {
50+
process.env.DISABLE_CHECK_WORKFLOW_JOB_LABELS = 'false';
51+
});
4952
it('handles workflow job events', async () => {
5053
const event = JSON.stringify(workflowjob_event);
5154
const resp = await handle(
@@ -139,8 +142,8 @@ describe('handler', () => {
139142
expect(sendActionRequest).toBeCalled();
140143
});
141144

142-
it('Check runner a runner with multiple labels accept a job with a subset of labels.', async () => {
143-
process.env.RUNNER_LABELS = '["test", "linux"]';
145+
it('Check runner a self hosted runner will run a job marked with only self-hosted', async () => {
146+
process.env.RUNNER_LABELS = '["test", "test2"]';
144147
const event = JSON.stringify({
145148
...workflowjob_event,
146149
workflow_job: {
@@ -156,13 +159,13 @@ describe('handler', () => {
156159
expect(sendActionRequest).toBeCalled();
157160
});
158161

159-
it('Check runner labels in mixed order', async () => {
160-
process.env.RUNNER_LABELS = '["test", "linux"]';
162+
it('Check runner labels for a strict job (2 labels should match)', async () => {
163+
process.env.RUNNER_LABELS = '["test", "test2"]';
161164
const event = JSON.stringify({
162165
...workflowjob_event,
163166
workflow_job: {
164167
...workflowjob_event.workflow_job,
165-
labels: ['self-hosted', 'linux', 'test'],
168+
labels: ['self-hosted', 'linux', 'test', 'test2'],
166169
},
167170
});
168171
const resp = await handle(
@@ -173,8 +176,25 @@ describe('handler', () => {
173176
expect(sendActionRequest).toBeCalled();
174177
});
175178

179+
it('Check event is accepted for disabled workflow check', async () => {
180+
process.env.DISABLE_CHECK_WORKFLOW_JOB_LABELS = 'true';
181+
process.env.RUNNER_LABELS = '["test", "no-check"]';
182+
const event = JSON.stringify({
183+
...workflowjob_event,
184+
workflow_job: {
185+
...workflowjob_event.workflow_job,
186+
labels: ['self-hosted', 'linux', 'test', 'test2'],
187+
},
188+
});
189+
const resp = await handle(
190+
{ 'X-Hub-Signature': await webhooks.sign(event), 'X-GitHub-Event': 'workflow_job' },
191+
event,
192+
);
193+
expect(resp).toBe(200);
194+
expect(sendActionRequest).toBeCalled();
195+
});
176196
it('Check not allowed runner label is declined', async () => {
177-
process.env.RUNNER_LABELS = '["test", "linux"]';
197+
process.env.RUNNER_LABELS = '["test"]';
178198
const event = JSON.stringify({
179199
...workflowjob_event,
180200
workflow_job: {

Diff for: modules/webhook/lambdas/webhook/src/webhook/handler.ts

+16-6
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ async function handleWorkflowJob(body: WorkflowJob, githubEvent: string): Promis
7171
return 403;
7272
}
7373

74-
if (isRunnerNotAllowed(body)) {
74+
const disableCheckWorkflowJobLabelsEnv = process.env.DISABLE_CHECK_WORKFLOW_JOB_LABELS || 'false';
75+
const disableCheckWorkflowJobLabels = JSON.parse(disableCheckWorkflowJobLabelsEnv) as boolean;
76+
if (!disableCheckWorkflowJobLabels && !canRunJob(body)) {
7577
console.error(`Received event contains runner labels '${body.workflow_job.labels}' that are not accepted.`);
7678
return 403;
7779
}
@@ -115,24 +117,32 @@ async function handleCheckRun(body: CheckRunEvent, githubEvent: string): Promise
115117
}
116118

117119
function isRepoNotAllowed(body: WorkflowJob | CheckRunEvent): boolean {
118-
const repositoryWhiteListEnv = (process.env.REPOSITORY_WHITE_LIST as string) || '[]';
120+
const repositoryWhiteListEnv = process.env.REPOSITORY_WHITE_LIST || '[]';
119121
const repositoryWhiteList = JSON.parse(repositoryWhiteListEnv) as Array<string>;
120122

121123
return repositoryWhiteList.length > 0 && !repositoryWhiteList.includes(body.repository.full_name);
122124
}
123125

124-
function isRunnerNotAllowed(job: WorkflowJob): boolean {
125-
const runnerLabelsEnv = (process.env.RUNNER_LABELS as string) || '[]';
126+
function canRunJob(job: WorkflowJob): boolean {
127+
const runnerLabelsEnv = process.env.RUNNER_LABELS || '[]';
126128
const runnerLabels = new Set(JSON.parse(runnerLabelsEnv) as Array<string>);
127129

128130
// ensure the self-hosted label is in the list.
129131
runnerLabels.add('self-hosted');
130-
const runnerMatch = job.workflow_job.labels.every((l) => runnerLabels.has(l));
132+
const workflowJobLabels = job.workflow_job.labels;
133+
134+
// eslint-disable-next-line max-len
135+
// GitHub managed labels: https://docs.github.com/en/actions/hosting-your-own-runners/using-self-hosted-runners-in-a-workflow#using-default-labels-to-route-jobs
136+
const githubManagedLabels = ['self-hosted', 'linux', 'macOS', 'windows', 'x64', 'ARM', 'ARM64'];
137+
// Remove GitHub managed labels
138+
const customWorkflowJobLabels = workflowJobLabels.filter((l) => githubManagedLabels.indexOf(l) < 0);
139+
140+
const runnerMatch = customWorkflowJobLabels.every((l) => runnerLabels.has(l));
131141

132142
console.debug(
133143
`Received workflow job event with labels: '${JSON.stringify(job.workflow_job.labels)}'. The event does ${
134144
runnerMatch ? '' : 'NOT '
135145
}match the configured labels: '${Array.from(runnerLabels).join(',')}'`,
136146
);
137-
return !runnerMatch;
147+
return runnerMatch;
138148
}

Diff for: modules/webhook/variables.tf

+6
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,9 @@ variable "runner_extra_labels" {
8888
type = string
8989
default = ""
9090
}
91+
92+
variable "disable_check_wokflow_job_labels" {
93+
description = "Disable the the check of workflow labels."
94+
type = bool
95+
default = false
96+
}

Diff for: modules/webhook/webhook.tf

+5-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ resource "aws_lambda_function" "webhook" {
1212

1313
environment {
1414
variables = {
15-
ENVIRONMENT = var.environment
16-
SQS_URL_WEBHOOK = var.sqs_build_queue.id
17-
REPOSITORY_WHITE_LIST = jsonencode(var.repository_white_list)
18-
RUNNER_LABELS = jsonencode(split(",", var.runner_extra_labels))
15+
DISABLE_CHECK_WORKFLOW_JOB_LABELS = var.disable_check_wokflow_job_labels
16+
ENVIRONMENT = var.environment
17+
SQS_URL_WEBHOOK = var.sqs_build_queue.id
18+
REPOSITORY_WHITE_LIST = jsonencode(var.repository_white_list)
19+
RUNNER_LABELS = jsonencode(split(",", var.runner_extra_labels))
1920
}
2021
}
2122

Diff for: variables.tf

+6
Original file line numberDiff line numberDiff line change
@@ -398,3 +398,9 @@ variable "runner_egress_rules" {
398398
description = null
399399
}]
400400
}
401+
402+
variable "disable_check_wokflow_job_labels" {
403+
description = "Disable the the check of workflow labels for received workflow job events."
404+
type = bool
405+
default = false
406+
}

0 commit comments

Comments
 (0)