@intentius/chant-lexicon-terraform 0.100.0 → 0.102.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/dist/codegen/package.d.ts +1 -1
  2. package/dist/config.d.ts +2 -2
  3. package/dist/hcl/jsonencode.d.ts +106 -0
  4. package/dist/hcl/jsonencode.d.ts.map +1 -0
  5. package/dist/hcl/marker.d.ts.map +1 -1
  6. package/dist/integrity.json +11 -2
  7. package/dist/lint/audit-catalog.d.ts.map +1 -1
  8. package/dist/lint/audit-lineage.d.ts +1 -1
  9. package/dist/lint/audit-lineage.d.ts.map +1 -1
  10. package/dist/lint/post-synth/flat-attributes.d.ts +69 -0
  11. package/dist/lint/post-synth/flat-attributes.d.ts.map +1 -0
  12. package/dist/lint/post-synth/index.d.ts.map +1 -1
  13. package/dist/lint/post-synth/tf030.d.ts +51 -0
  14. package/dist/lint/post-synth/tf030.d.ts.map +1 -0
  15. package/dist/lint/post-synth/tf031.d.ts +55 -0
  16. package/dist/lint/post-synth/tf031.d.ts.map +1 -0
  17. package/dist/lint/post-synth/tf032.d.ts +71 -0
  18. package/dist/lint/post-synth/tf032.d.ts.map +1 -0
  19. package/dist/lint/post-synth/tf033.d.ts +50 -0
  20. package/dist/lint/post-synth/tf033.d.ts.map +1 -0
  21. package/dist/lint/post-synth/tf034.d.ts +25 -0
  22. package/dist/lint/post-synth/tf034.d.ts.map +1 -0
  23. package/dist/lint/post-synth/tf035.d.ts +33 -0
  24. package/dist/lint/post-synth/tf035.d.ts.map +1 -0
  25. package/dist/lint/post-synth/tf036.d.ts +33 -0
  26. package/dist/lint/post-synth/tf036.d.ts.map +1 -0
  27. package/dist/lint/post-synth/tf037.d.ts +31 -0
  28. package/dist/lint/post-synth/tf037.d.ts.map +1 -0
  29. package/dist/manifest.json +1 -1
  30. package/dist/okf/index.md +8 -0
  31. package/dist/okf/rules/TF030.md +11 -0
  32. package/dist/okf/rules/TF031.md +11 -0
  33. package/dist/okf/rules/TF032.md +11 -0
  34. package/dist/okf/rules/TF033.md +11 -0
  35. package/dist/okf/rules/TF034.md +11 -0
  36. package/dist/okf/rules/TF035.md +11 -0
  37. package/dist/okf/rules/TF036.md +11 -0
  38. package/dist/okf/rules/TF037.md +11 -0
  39. package/dist/op/activity-contracts.d.ts +18 -18
  40. package/dist/op/builders.d.ts.map +1 -1
  41. package/dist/rules/flat-attributes.ts +146 -0
  42. package/dist/rules/tf030.ts +290 -0
  43. package/dist/rules/tf031.ts +370 -0
  44. package/dist/rules/tf032.ts +226 -0
  45. package/dist/rules/tf033.ts +160 -0
  46. package/dist/rules/tf034.ts +63 -0
  47. package/dist/rules/tf035.ts +74 -0
  48. package/dist/rules/tf036.ts +119 -0
  49. package/dist/rules/tf037.ts +101 -0
  50. package/package.json +3 -3
  51. package/src/hcl/jsonencode.test.ts +226 -0
  52. package/src/hcl/jsonencode.ts +454 -0
  53. package/src/lint/audit-catalog.ts +148 -0
  54. package/src/lint/audit-lineage.ts +155 -1
  55. package/src/lint/post-synth/estate-2284.test.ts +68 -0
  56. package/src/lint/post-synth/fixtures/TF030/negative-rules.tf +45 -0
  57. package/src/lint/post-synth/fixtures/TF030/negative.tf +55 -0
  58. package/src/lint/post-synth/fixtures/TF030/not-determined-port.tf +28 -0
  59. package/src/lint/post-synth/fixtures/TF030/not-determined-standalone.tf +32 -0
  60. package/src/lint/post-synth/fixtures/TF030/not-determined-vpc-rule.tf +21 -0
  61. package/src/lint/post-synth/fixtures/TF030/not-determined.tf +39 -0
  62. package/src/lint/post-synth/fixtures/TF030/positive-ipv6.tf +44 -0
  63. package/src/lint/post-synth/fixtures/TF030/positive-mixed.tf +36 -0
  64. package/src/lint/post-synth/fixtures/TF030/positive-standalone.tf +25 -0
  65. package/src/lint/post-synth/fixtures/TF030/positive.tf +43 -0
  66. package/src/lint/post-synth/fixtures/TF031/negative.tf +89 -0
  67. package/src/lint/post-synth/fixtures/TF031/not-determined.tf +139 -0
  68. package/src/lint/post-synth/fixtures/TF031/positive-data-source.tf +57 -0
  69. package/src/lint/post-synth/fixtures/TF031/positive-heredoc.tf +149 -0
  70. package/src/lint/post-synth/fixtures/TF031/positive-jsonencode.tf +115 -0
  71. package/src/lint/post-synth/fixtures/TF032/negative-heredoc.tf +20 -0
  72. package/src/lint/post-synth/fixtures/TF032/negative-references.tf +214 -0
  73. package/src/lint/post-synth/fixtures/TF032/negative.tf +99 -0
  74. package/src/lint/post-synth/fixtures/TF032/positive-heredoc.tf +22 -0
  75. package/src/lint/post-synth/fixtures/TF032/positive-sidecar.tf +197 -0
  76. package/src/lint/post-synth/fixtures/TF032/positive.tf +54 -0
  77. package/src/lint/post-synth/fixtures/TF033/negative.tf +39 -0
  78. package/src/lint/post-synth/fixtures/TF033/not-determined-aurora.tf +25 -0
  79. package/src/lint/post-synth/fixtures/TF033/positive-absent.tf +93 -0
  80. package/src/lint/post-synth/fixtures/TF033/positive.tf +50 -0
  81. package/src/lint/post-synth/fixtures/TF034/negative.tf +24 -0
  82. package/src/lint/post-synth/fixtures/TF034/positive-absent.tf +36 -0
  83. package/src/lint/post-synth/fixtures/TF034/positive.tf +14 -0
  84. package/src/lint/post-synth/fixtures/TF035/negative-absent.tf +43 -0
  85. package/src/lint/post-synth/fixtures/TF035/negative.tf +54 -0
  86. package/src/lint/post-synth/fixtures/TF035/positive.tf +37 -0
  87. package/src/lint/post-synth/fixtures/TF036/negative.tf +61 -0
  88. package/src/lint/post-synth/fixtures/TF036/not-determined.tf +28 -0
  89. package/src/lint/post-synth/fixtures/TF036/positive.tf +38 -0
  90. package/src/lint/post-synth/fixtures/TF037/negative-exclusion.tf +63 -0
  91. package/src/lint/post-synth/fixtures/TF037/negative.tf +27 -0
  92. package/src/lint/post-synth/fixtures/TF037/not-determined.tf +27 -0
  93. package/src/lint/post-synth/fixtures/TF037/positive-absent.tf +15 -0
  94. package/src/lint/post-synth/fixtures/TF037/positive.tf +26 -0
  95. package/src/lint/post-synth/fixtures/estate-2284/clean/main.tf +132 -0
  96. package/src/lint/post-synth/fixtures/estate-2284/violating/main.tf +112 -0
  97. package/src/lint/post-synth/flat-attributes.ts +146 -0
  98. package/src/lint/post-synth/index.ts +16 -0
  99. package/src/lint/post-synth/tf030.test.ts +219 -0
  100. package/src/lint/post-synth/tf030.ts +290 -0
  101. package/src/lint/post-synth/tf031.test.ts +229 -0
  102. package/src/lint/post-synth/tf031.ts +370 -0
  103. package/src/lint/post-synth/tf032.test.ts +127 -0
  104. package/src/lint/post-synth/tf032.ts +226 -0
  105. package/src/lint/post-synth/tf033.test.ts +126 -0
  106. package/src/lint/post-synth/tf033.ts +160 -0
  107. package/src/lint/post-synth/tf034.test.ts +71 -0
  108. package/src/lint/post-synth/tf034.ts +63 -0
  109. package/src/lint/post-synth/tf035.test.ts +68 -0
  110. package/src/lint/post-synth/tf035.ts +74 -0
  111. package/src/lint/post-synth/tf036.test.ts +87 -0
  112. package/src/lint/post-synth/tf036.ts +119 -0
  113. package/src/lint/post-synth/tf037.test.ts +88 -0
  114. package/src/lint/post-synth/tf037.ts +101 -0
  115. package/src/op/activities/terraform.test.ts +2 -2
@@ -0,0 +1,214 @@
1
+ # Vendored for TF032 (chant #2287). Source: https://github.com/testdrivenio/django-ecs-terraform
2
+ # Path: terraform/07_ecs.tf
3
+ # Commit: 6571bcce48cee37fa10b1ee9a5caec147356b047
4
+ # Licence: MIT
5
+ # Copyright (c) 2023 TestDriven.io. MIT licence: https://github.com/testdrivenio/django-ecs-terraform/blob/6571bcce48cee37fa10b1ee9a5caec147356b047/LICENSE
6
+ # Copied verbatim below this header. No finding: RDS_PASSWORD is var.rds_password (a reference, not a literal), and the collectstatic task has no environment. The app task's container_definitions is data.template_file.app.rendered, which is not determined.
7
+
8
+ resource "aws_ecs_cluster" "production" {
9
+ name = "${var.ecs_cluster_name}-cluster"
10
+ }
11
+
12
+ data "template_file" "app" {
13
+ template = file("templates/django_app.json.tpl")
14
+
15
+ vars = {
16
+ docker_image_url_django = var.docker_image_url_django
17
+ docker_image_url_nginx = var.docker_image_url_nginx
18
+ region = var.region
19
+ rds_db_name = var.rds_db_name
20
+ rds_username = var.rds_username
21
+ rds_password = var.rds_password
22
+ rds_hostname = aws_db_instance.production.address
23
+ allowed_hosts = var.allowed_hosts
24
+ }
25
+ }
26
+
27
+ resource "aws_ecs_task_definition" "app" {
28
+ family = "django-app"
29
+ depends_on = [aws_db_instance.production]
30
+ network_mode = "awsvpc" # Required for Fargate
31
+ requires_compatibilities = ["FARGATE"]
32
+ cpu = "${var.fargate_cpu}"
33
+ memory = "${var.fargate_memory}"
34
+ execution_role_arn = aws_iam_role.ecs-task-execution-role.arn
35
+ task_role_arn = aws_iam_role.ecs-task-execution-role.arn
36
+ container_definitions = data.template_file.app.rendered
37
+ volume {
38
+ name = "efs-volume"
39
+ efs_volume_configuration {
40
+ file_system_id = aws_efs_file_system.efs.id
41
+ root_directory = "/"
42
+ transit_encryption = "ENABLED"
43
+ transit_encryption_port = 2049
44
+ authorization_config {
45
+ access_point_id = aws_efs_access_point.app_access_point.id
46
+ iam = "ENABLED"
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ resource "aws_ecs_service" "production" {
53
+ name = "${var.ecs_cluster_name}-service"
54
+ cluster = aws_ecs_cluster.production.id
55
+ task_definition = aws_ecs_task_definition.app.arn
56
+ launch_type = "FARGATE"
57
+ desired_count = var.app_count
58
+ network_configuration {
59
+ subnets = [aws_subnet.public-subnet-1.id, aws_subnet.public-subnet-2.id]
60
+ security_groups = [aws_security_group.ecs-fargate.id]
61
+ assign_public_ip = true
62
+ }
63
+
64
+ load_balancer {
65
+ target_group_arn = aws_alb_target_group.default-target-group.arn
66
+ container_name = "nginx"
67
+ container_port = 80
68
+ }
69
+ }
70
+
71
+ resource "aws_ecs_task_definition" "django_migration" {
72
+ family = "django-migration-task"
73
+ network_mode = "awsvpc"
74
+ requires_compatibilities = ["FARGATE"]
75
+ cpu = var.fargate_cpu
76
+ memory = var.fargate_memory
77
+ execution_role_arn = aws_iam_role.ecs-task-execution-role.arn
78
+
79
+ container_definitions = jsonencode([
80
+ {
81
+ name = "django-migration-container"
82
+ image = var.docker_image_url_django
83
+ environment: [
84
+ {
85
+ "name": "RDS_DB_NAME",
86
+ "value": var.rds_db_name
87
+ },
88
+ {
89
+ "name": "RDS_USERNAME",
90
+ "value": var.rds_username
91
+ },
92
+ {
93
+ "name": "RDS_PASSWORD",
94
+ "value": var.rds_password
95
+ },
96
+ {
97
+ "name": "RDS_HOSTNAME",
98
+ "value": aws_db_instance.production.address
99
+ },
100
+ {
101
+ "name": "RDS_PORT",
102
+ "value": "5432"
103
+ }
104
+ ],
105
+ # Run migrations as the command
106
+ command = ["python", "manage.py", "migrate"]
107
+
108
+ # Add log configuration for CloudWatch
109
+ logConfiguration = {
110
+ logDriver = "awslogs"
111
+ options = {
112
+ awslogs-group = "/ecs/django-app"
113
+ awslogs-region = var.region
114
+ awslogs-stream-prefix = "ecs"
115
+ }
116
+ }
117
+
118
+ # Other required configurations go here...
119
+ portMappings = [
120
+ {
121
+ containerPort = 8000
122
+ }
123
+ ]
124
+ }
125
+ ])
126
+ }
127
+
128
+ resource "aws_efs_file_system" "efs" {
129
+ lifecycle_policy {
130
+ transition_to_ia = "AFTER_30_DAYS"
131
+ }
132
+ }
133
+
134
+ resource "aws_efs_access_point" "app_access_point" {
135
+ file_system_id = aws_efs_file_system.efs.id
136
+ posix_user {
137
+ uid = 1000
138
+ gid = 1000
139
+ }
140
+ root_directory {
141
+ path = "/efs"
142
+ creation_info {
143
+ owner_uid = 1000
144
+ owner_gid = 1000
145
+ permissions = "755"
146
+ }
147
+ }
148
+ }
149
+
150
+ resource "aws_efs_mount_target" "efs_mount" {
151
+ count = length([aws_subnet.public-subnet-1.id, aws_subnet.public-subnet-2.id])
152
+ file_system_id = aws_efs_file_system.efs.id
153
+ subnet_id = [aws_subnet.public-subnet-1.id, aws_subnet.public-subnet-2.id][count.index]
154
+ security_groups = [aws_security_group.efs_sg.id]
155
+ }
156
+
157
+ resource "aws_ecs_task_definition" "django_collectstatic" {
158
+ family = "django-collectstatic-task"
159
+ network_mode = "awsvpc"
160
+ requires_compatibilities = ["FARGATE"]
161
+ cpu = var.fargate_cpu
162
+ memory = var.fargate_memory
163
+ execution_role_arn = aws_iam_role.ecs-task-execution-role.arn
164
+ task_role_arn = aws_iam_role.ecs-task-execution-role.arn
165
+ volume {
166
+ name = "efs-volume"
167
+ efs_volume_configuration {
168
+ file_system_id = aws_efs_file_system.efs.id
169
+ root_directory = "/"
170
+ transit_encryption = "ENABLED"
171
+ transit_encryption_port = 2049
172
+ authorization_config {
173
+ access_point_id = aws_efs_access_point.app_access_point.id
174
+ iam = "ENABLED"
175
+ }
176
+ }
177
+ }
178
+ container_definitions = jsonencode([
179
+ {
180
+ name = "django-collectstatic-container"
181
+ image = var.docker_image_url_django
182
+ linuxParameters = {
183
+ user = "1000:1000"
184
+ },
185
+ # Run collectstatic as the command
186
+ command = ["python", "manage.py", "collectstatic", "--no-input", "-v", "3"]
187
+
188
+ mountPoints = [
189
+ {
190
+ sourceVolume = "efs-volume",
191
+ containerPath = "/efs/staticfiles/",
192
+ readOnly = false
193
+ }
194
+ ]
195
+
196
+ # Add log configuration for CloudWatch
197
+ logConfiguration = {
198
+ logDriver = "awslogs"
199
+ options = {
200
+ awslogs-group = "/ecs/django-app"
201
+ awslogs-region = var.region
202
+ awslogs-stream-prefix = "ecs"
203
+ }
204
+ }
205
+
206
+ # Other required configurations go here...
207
+ portMappings = [
208
+ {
209
+ containerPort = 8000
210
+ }
211
+ ]
212
+ }
213
+ ])
214
+ }
@@ -0,0 +1,99 @@
1
+ # Vendored for TF032 (chant #2287). Source: https://github.com/vapor/penny-bot
2
+ # Path: infra/ecs.tf
3
+ # Commit: e1481d187e703649e2116d36c3cb022357946916
4
+ # Licence: Apache-2.0
5
+ # Copyright the penny-bot contributors. Licensed under the Apache License, Version 2.0: https://github.com/vapor/penny-bot/blob/e1481d187e703649e2116d36c3cb022357946916/LICENSE
6
+ # Copied verbatim below this header. Unmodified. Silent: BOT_TOKEN and SO_API_KEY arrive through secrets/valueFrom, and environment holds only a literal stage name and a reference.
7
+
8
+ resource "aws_ecs_cluster" "penny" {
9
+ name = module.constants.ecs_cluster_name
10
+ }
11
+
12
+ resource "aws_ecs_task_definition" "penny" {
13
+ family = "penny-bot"
14
+ skip_destroy = true
15
+ cpu = "256"
16
+ memory = "512"
17
+ network_mode = "awsvpc"
18
+ requires_compatibilities = ["FARGATE"]
19
+ execution_role_arn = data.aws_iam_role.ecs_task_execution.arn
20
+ task_role_arn = data.aws_iam_role.ecs_task.arn
21
+
22
+ runtime_platform {
23
+ cpu_architecture = "ARM64"
24
+ operating_system_family = "LINUX"
25
+ }
26
+
27
+ container_definitions = jsonencode([
28
+ {
29
+ name = "penny-bot"
30
+ image = "${aws_ecr_repository.penny_bot_discord_image.repository_url}:${local.penny_image_tag}"
31
+ cpu = 0
32
+ essential = true
33
+ portMappings = []
34
+ mountPoints = []
35
+ volumesFrom = []
36
+ systemControls = []
37
+ environment = [
38
+ {
39
+ name = "DEPLOYMENT_ENVIRONMENT"
40
+ value = "prod"
41
+ },
42
+ {
43
+ name = "GH_OAUTH_CLIENT_ID"
44
+ value = module.constants.gh_oauth_client_id
45
+ }
46
+ ]
47
+ secrets = [
48
+ {
49
+ name = "BOT_TOKEN"
50
+ valueFrom = aws_secretsmanager_secret.discord_bot_token.arn
51
+ },
52
+ {
53
+ name = "LOGGING_WEBHOOK_URL"
54
+ valueFrom = aws_secretsmanager_secret.logs_webhook_url.arn
55
+ },
56
+ {
57
+ name = "ACCOUNT_LINKING_OAUTH_FLOW_PRIV_KEY"
58
+ valueFrom = aws_secretsmanager_secret.account_linking_priv_key.arn
59
+ },
60
+ {
61
+ name = "SO_API_KEY"
62
+ valueFrom = aws_secretsmanager_secret.stack_overflow_api_key.arn
63
+ }
64
+ ]
65
+ logConfiguration = {
66
+ logDriver = "awslogs"
67
+ options = {
68
+ awslogs-group = aws_cloudwatch_log_group.ecs_api.name
69
+ awslogs-region = local.region
70
+ awslogs-stream-prefix = "ecs"
71
+ }
72
+ }
73
+ }
74
+ ])
75
+ }
76
+
77
+ resource "aws_ecs_service" "penny" {
78
+ name = module.constants.ecs_service_name
79
+ cluster = aws_ecs_cluster.penny.id
80
+ task_definition = "${aws_ecs_task_definition.penny.family}:${aws_ecs_task_definition.penny.revision}"
81
+ desired_count = 1
82
+ launch_type = "FARGATE"
83
+ platform_version = "1.4.0"
84
+ wait_for_steady_state = true
85
+
86
+ deployment_minimum_healthy_percent = 100
87
+ deployment_maximum_percent = 200
88
+
89
+ deployment_circuit_breaker {
90
+ enable = true
91
+ rollback = true
92
+ }
93
+
94
+ network_configuration {
95
+ subnets = data.aws_subnets.default.ids
96
+ security_groups = [aws_security_group.ecs_service.id]
97
+ assign_public_ip = true
98
+ }
99
+ }
@@ -0,0 +1,22 @@
1
+ # Vendored for TF032 (chant #2287). Source: https://github.com/aquasecurity/trivy-checks
2
+ # Path: checks/cloud/aws/ecs/no_plaintext_secrets.yaml (terraform.bad[0])
3
+ # Commit: 71c05d02845cc2c3a5dfa4fe914a68a052cc88bf
4
+ # Licence: MIT
5
+ # Copyright (c) 2024 Aqua Security. MIT licence: https://github.com/aquasecurity/trivy-checks/blob/71c05d02845cc2c3a5dfa4fe914a68a052cc88bf/LICENSE
6
+ # The upstream check's own failing example, lifted out of its YAML block scalar unchanged.
7
+ # A heredoc with no interpolation arrives from hcl2json as a plain string, so it is read
8
+ # as JSON. Fires once, on DATABASE_PASSWORD.
9
+
10
+ resource "aws_ecs_task_definition" "bad_example" {
11
+ container_definitions = <<EOF
12
+ [
13
+ {
14
+ "name": "my_service",
15
+ "environment": [
16
+ { "name": "ENVIRONMENT", "value": "development" },
17
+ { "name": "DATABASE_PASSWORD", "value": "oh no D:"}
18
+ ]
19
+ }
20
+ ]
21
+ EOF
22
+ }
@@ -0,0 +1,197 @@
1
+ # Vendored for TF032 (chant #2287). Source: https://github.com/govuk-forms/forms-admin
2
+ # Path: .review_apps/ecs_task_definition.tf
3
+ # Commit: b338d4386619e3379a2555d65b8cfdf5d786905c
4
+ # Licence: MIT
5
+ # Copyright (c) 2022 Crown Copyright (Government Digital Service). MIT licence: https://github.com/govuk-forms/forms-admin/blob/b338d4386619e3379a2555d65b8cfdf5d786905c/LICENSE
6
+ # Copied verbatim below this header. Fires once on the postgres sidecar's literal POSTGRES_PASSWORD; the two containers whose environment is local.forms_admin_env_vars are not determined. The traefik dockerLabels keys are templates, which the reader drops without losing the rest.
7
+
8
+ locals {
9
+ logs_stream_prefix = "${data.terraform_remote_state.review.outputs.review_apps_log_group_name}/pr-${var.pull_request_number}"
10
+
11
+ # try() so that deploys succeed before the review environment state has
12
+ # published the assets outputs
13
+ assets_bucket_name = try(data.terraform_remote_state.review.outputs.assets_bucket_name, "govuk-forms-review-assets")
14
+ forms_admin_task_role_arn = try(data.terraform_remote_state.review.outputs.forms_admin_task_role_arn, null)
15
+
16
+ review_app_hostname = "pr-${var.pull_request_number}.admin.review.forms.service.gov.uk"
17
+
18
+ forms_admin_startup_commands = [
19
+ "echo $PATH",
20
+ "bundle install",
21
+ "echo $PATH",
22
+ "bin/rails db:prepare",
23
+ "bin/rails s -b 0.0.0.0"
24
+ ]
25
+
26
+ forms_admin_shell_script = join(" && ", local.forms_admin_startup_commands)
27
+
28
+ forms_admin_env_vars = [
29
+ { name = "DATABASE_URL", value = "postgres://postgres:postgres@127.0.0.1:5432" },
30
+ { name = "EMAIL", value = "review-app-submissions@review.forms.service.gov.uk" },
31
+ { name = "GOVUK_APP_DOMAIN", value = "publishing.service.gov.uk" },
32
+ { name = "PORT", value = "3000" },
33
+ { name = "RAILS_DEVELOPMENT_HOSTS", value = "pr-${var.pull_request_number}.admin.review.forms.service.gov.uk" },
34
+ { name = "RAILS_ENV", value = "production" },
35
+ { name = "SECRET_KEY_BASE", value = "unsecured_secret_key_material" },
36
+ { name = "SETTINGS__ACT_AS_USER_ENABLED", value = "true" },
37
+ { name = "SETTINGS__AUTH_PROVIDER", value = "developer" },
38
+ { name = "SETTINGS__AWS__ASSETS_S3_BUCKET_NAME", value = local.assets_bucket_name },
39
+ { name = "SETTINGS__FORMS_ENV", value = "review" },
40
+ { name = "SETTINGS__FORMS_RUNNER__URL", value = "https://forms.service.gov.uk" },
41
+ ]
42
+ }
43
+
44
+ resource "aws_ecs_task_definition" "task" {
45
+ family = "forms-admin-pr-${var.pull_request_number}"
46
+
47
+ network_mode = "awsvpc"
48
+ cpu = 256
49
+ memory = 1024
50
+
51
+ requires_compatibilities = ["FARGATE"]
52
+
53
+ runtime_platform {
54
+ operating_system_family = "LINUX"
55
+ cpu_architecture = "ARM64"
56
+ }
57
+
58
+ execution_role_arn = data.terraform_remote_state.review.outputs.ecs_task_execution_role_arn
59
+
60
+ # Gives the app permission to upload brand assets to the assets bucket
61
+ task_role_arn = local.forms_admin_task_role_arn
62
+
63
+ container_definitions = jsonencode([
64
+
65
+ # forms-admin
66
+ {
67
+ name = "forms-admin"
68
+ image = var.forms_admin_container_image
69
+ command = []
70
+ essential = true
71
+ environment = local.forms_admin_env_vars
72
+ # Uploaded files are buffered to tempfiles, and the app user cannot
73
+ # write to a volume mounted at /tmp, so the root filesystem cannot be
74
+ # read-only
75
+ readonlyRootFilesystem = false
76
+
77
+ dockerLabels = {
78
+ "traefik.http.middlewares.forms-admin-pr-${var.pull_request_number}.basicauth.users" : data.terraform_remote_state.review.outputs.traefik_basic_auth_credentials
79
+
80
+ "traefik.http.routers.forms-admin-pr-${var.pull_request_number}.rule" : "Host(`${local.review_app_hostname}`)",
81
+ "traefik.http.routers.forms-admin-pr-${var.pull_request_number}.service" : "forms-admin-pr-${var.pull_request_number}",
82
+ "traefik.http.routers.forms-admin-pr-${var.pull_request_number}.middlewares" : "forms-admin-pr-${var.pull_request_number}@ecs"
83
+
84
+ "traefik.http.services.forms-admin-pr-${var.pull_request_number}.loadbalancer.server.port" : "3000",
85
+ "traefik.http.services.forms-admin-pr-${var.pull_request_number}.loadbalancer.healthcheck.path" : "/up",
86
+ "traefik.enable" : "true",
87
+ },
88
+
89
+ portMappings = [
90
+ {
91
+ containerPort = 3000
92
+ hostPort = 3000
93
+ protocol = "tcp"
94
+ appProtocol = "http"
95
+ }
96
+ ]
97
+
98
+ mountPoints = []
99
+ systemControls = []
100
+ volumesFrom = []
101
+
102
+ logConfiguration = {
103
+ logDriver = "awslogs"
104
+ options = {
105
+ awslogs-group = data.terraform_remote_state.review.outputs.review_apps_log_group_name
106
+ awslogs-region = "eu-west-2"
107
+ awslogs-stream-prefix = "${local.logs_stream_prefix}/forms-admin"
108
+ }
109
+ }
110
+
111
+ healthCheck = {
112
+ command = ["CMD-SHELL", "wget -O - 'http://localhost:3000/up' || exit 1"]
113
+ interval = 30
114
+ retries = 5
115
+ startPeriod = 180
116
+ timeout = 5
117
+ }
118
+
119
+ dependsOn = [
120
+ {
121
+ containerName = "postgres"
122
+ condition = "HEALTHY"
123
+ }
124
+ ]
125
+ },
126
+
127
+ # postgres
128
+ {
129
+ name = "postgres"
130
+ image = "public.ecr.aws/docker/library/postgres:16.6"
131
+ command = []
132
+ essential = true
133
+
134
+ portMappings = [
135
+ {
136
+ containerPort = 5432
137
+ hostPort = 5432
138
+ protocol = "tcp"
139
+ }
140
+ ]
141
+
142
+ mountPoints = []
143
+ systemControls = []
144
+ volumesFrom = []
145
+
146
+ environment = [
147
+ { name = "POSTGRES_PASSWORD", value = "postgres" }
148
+ ]
149
+
150
+ logConfiguration = {
151
+ logDriver = "awslogs"
152
+ options = {
153
+ awslogs-group = data.terraform_remote_state.review.outputs.review_apps_log_group_name
154
+ awslogs-region = "eu-west-2"
155
+ awslogs-stream-prefix = "${local.logs_stream_prefix}/postgres"
156
+ }
157
+ }
158
+
159
+ healthCheck = {
160
+ command = ["CMD-SHELL", "psql -h localhost -p 5432 -U postgres -c \"SELECT current_timestamp - pg_postmaster_start_time();\""]
161
+ interval = 30
162
+ retries = 3
163
+ timeout = 5
164
+ }
165
+ },
166
+
167
+ # forms-admin-seeding
168
+ {
169
+ name = "forms-admin-seeding"
170
+ image = var.forms_admin_container_image
171
+ command = ["rake", "db:create", "db:migrate", "db:seed"]
172
+ essential = false
173
+ environment = local.forms_admin_env_vars
174
+ readonlyRootFilesystem = true
175
+
176
+ mountPoints = []
177
+ systemControls = []
178
+ volumesFrom = []
179
+
180
+ logConfiguration = {
181
+ logDriver = "awslogs"
182
+ options = {
183
+ awslogs-group = data.terraform_remote_state.review.outputs.review_apps_log_group_name
184
+ awslogs-region = "eu-west-2"
185
+ awslogs-stream-prefix = "${local.logs_stream_prefix}/forms-admin-seeding"
186
+ }
187
+ }
188
+
189
+ dependsOn = [
190
+ {
191
+ containerName = "postgres"
192
+ condition = "HEALTHY"
193
+ }
194
+ ]
195
+ },
196
+ ])
197
+ }
@@ -0,0 +1,54 @@
1
+ # Vendored for TF032 (chant #2287). Source: https://github.com/edstem-tech/paylink-platform
2
+ # Path: terraform/ecs.tf
3
+ # Commit: 2bbcbcce09434286cf90d20f69df0bd3ffa4cd00
4
+ # Licence: MIT
5
+ # Copyright (c) 2025 EdStem. MIT licence: permission notice at https://github.com/edstem-tech/paylink-platform/blob/2bbcbcce09434286cf90d20f69df0bd3ffa4cd00/LICENSE
6
+ # Copied verbatim below this header. Fires twice: DB_PASSWORD and PAYMENT_API_KEY are literals in environment.
7
+
8
+ resource "aws_ecs_cluster" "main" {
9
+ name = "paylink-prod"
10
+ }
11
+
12
+ resource "aws_ecs_task_definition" "api" {
13
+ family = "paylink-api"
14
+ network_mode = "awsvpc"
15
+ requires_compatibilities = ["FARGATE"]
16
+ cpu = "1024"
17
+ memory = "2048"
18
+ task_role_arn = aws_iam_role.task.arn
19
+ execution_role_arn = aws_iam_role.execution.arn
20
+
21
+ container_definitions = jsonencode([{
22
+ name = "api"
23
+ image = "${var.ecr_repo}:latest"
24
+
25
+ portMappings = [{ containerPort = 8080 }]
26
+
27
+ environment = [
28
+ { name = "SPRING_PROFILES_ACTIVE", value = "prod" },
29
+ { name = "DB_PASSWORD", value = "Pl-Pr0d-Db-2025!" },
30
+ { name = "PAYMENT_API_KEY", value = "pk_live_4RtYuIoP2aSdF6gH8jK" }
31
+ ]
32
+
33
+ healthCheck = {
34
+ command = ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"]
35
+ interval = 10
36
+ timeout = 2
37
+ retries = 3
38
+ }
39
+ }])
40
+ }
41
+
42
+ resource "aws_ecs_service" "api" {
43
+ name = "paylink-api"
44
+ cluster = aws_ecs_cluster.main.id
45
+ task_definition = aws_ecs_task_definition.api.arn
46
+ desired_count = 2
47
+ launch_type = "FARGATE"
48
+
49
+ network_configuration {
50
+ subnets = aws_subnet.public[*].id
51
+ security_groups = [aws_security_group.service.id]
52
+ assign_public_ip = true
53
+ }
54
+ }
@@ -0,0 +1,39 @@
1
+ # Vendored for TF033 (chant #2288) from https://github.com/tmknom/example-pragmatic-terraform
2
+ # Path: 13/4.tf
3
+ # Commit: 7043f9216cf7fb55b3c5e9cd1926fe5da04a3ddb
4
+ # Licence: Apache-2.0, https://github.com/tmknom/example-pragmatic-terraform/blob/7043f9216cf7fb55b3c5e9cd1926fe5da04a3ddb/LICENSE
5
+ # The whole file, unmodified.
6
+ #
7
+ # TF033: silent. A MySQL DB instance with storage_encrypted = true and a customer managed kms_key_id.
8
+
9
+ resource "aws_db_instance" "example" {
10
+ identifier = "example"
11
+ engine = "mysql"
12
+ engine_version = "5.7.25"
13
+ instance_class = "db.t3.small"
14
+ allocated_storage = 20
15
+ max_allocated_storage = 100
16
+ storage_type = "gp2"
17
+ storage_encrypted = true
18
+ kms_key_id = aws_kms_key.example.arn
19
+ username = "admin"
20
+ password = "VeryStrongPassword!"
21
+ multi_az = true
22
+ publicly_accessible = false
23
+ backup_window = "09:10-09:40"
24
+ backup_retention_period = 30
25
+ maintenance_window = "mon:10:10-mon:10:40"
26
+ auto_minor_version_upgrade = false
27
+ deletion_protection = true
28
+ skip_final_snapshot = false
29
+ port = 3306
30
+ apply_immediately = false
31
+ vpc_security_group_ids = [module.mysql_sg.security_group_id]
32
+ parameter_group_name = aws_db_parameter_group.example.name
33
+ option_group_name = aws_db_option_group.example.name
34
+ db_subnet_group_name = aws_db_subnet_group.example.name
35
+
36
+ lifecycle {
37
+ ignore_changes = [password]
38
+ }
39
+ }
@@ -0,0 +1,25 @@
1
+ # Vendored for TF033 (chant #2288) from https://github.com/bridgecrewio/terragoat
2
+ # Path: terraform/aws/rds.tf
3
+ # Commit: 729f8da62c6a85ce4af5ad3d123de97776d954c4
4
+ # Licence: Apache-2.0, https://github.com/bridgecrewio/terragoat/blob/729f8da62c6a85ce4af5ad3d123de97776d954c4/LICENSE
5
+ # Excerpt: lines 1-15, unmodified.
6
+ #
7
+ # TF033: one info, Not determined. An aws_rds_cluster with no engine (Aurora; provider v5 defaulted it to "aurora")
8
+ # and no storage_encrypted. AWS encrypts Aurora clusters created on or after 2026-02-16 whatever the
9
+ # configuration says, and the configuration does not say when this one was created.
10
+
11
+ resource "aws_rds_cluster" "app1-rds-cluster" {
12
+ cluster_identifier = "app1-rds-cluster"
13
+ allocated_storage = 10
14
+ backup_retention_period = 0
15
+ tags = {
16
+ git_commit = "079fe74f6b96d887c245664fbd8cf676c92f20e5"
17
+ git_file = "terraform/aws/rds.tf"
18
+ git_last_modified_at = "2021-12-08 23:26:32"
19
+ git_last_modified_by = "tron47@gmail.com"
20
+ git_modifiers = "tron47"
21
+ git_org = "matansha"
22
+ git_repo = "terragoat"
23
+ yor_trace = "b6f2c2ec-0715-46a0-83d4-502e588826d1"
24
+ }
25
+ }