@intentius/chant-lexicon-terraform 0.124.45 → 0.124.48

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 (93) hide show
  1. package/dist/__fixtures__/capabilities/chant.config.d.ts +26 -0
  2. package/dist/__fixtures__/capabilities/chant.config.d.ts.map +1 -0
  3. package/dist/__fixtures__/capabilities/chant.config.js +13 -0
  4. package/dist/__fixtures__/effective-topology/chant.config.d.ts +13 -0
  5. package/dist/__fixtures__/effective-topology/chant.config.d.ts.map +1 -0
  6. package/dist/__fixtures__/effective-topology/chant.config.js +9 -0
  7. package/dist/__fixtures__/kind-type/chant.config.d.ts +13 -0
  8. package/dist/__fixtures__/kind-type/chant.config.d.ts.map +1 -0
  9. package/dist/__fixtures__/kind-type/chant.config.js +9 -0
  10. package/dist/__fixtures__/search-roots/chant.config.d.ts +13 -0
  11. package/dist/__fixtures__/search-roots/chant.config.d.ts.map +1 -0
  12. package/dist/__fixtures__/search-roots/chant.config.js +9 -0
  13. package/dist/__fixtures__/sensitive-default/chant.config.d.ts +13 -0
  14. package/dist/__fixtures__/sensitive-default/chant.config.d.ts.map +1 -0
  15. package/dist/__fixtures__/sensitive-default/chant.config.js +9 -0
  16. package/dist/capabilities/adapter.d.ts +9 -0
  17. package/dist/capabilities/adapter.d.ts.map +1 -0
  18. package/dist/capabilities/adapter.js +25 -0
  19. package/dist/capabilities/mapping.json +166 -0
  20. package/dist/config.d.ts +52 -0
  21. package/dist/config.d.ts.map +1 -1
  22. package/dist/config.js +23 -0
  23. package/dist/describe-resources.d.ts +101 -8
  24. package/dist/describe-resources.d.ts.map +1 -1
  25. package/dist/describe-resources.js +395 -56
  26. package/dist/hcl/parse.d.ts +10 -0
  27. package/dist/hcl/parse.d.ts.map +1 -1
  28. package/dist/hcl/parse.js +20 -2
  29. package/dist/hcl/redact.d.ts +26 -0
  30. package/dist/hcl/redact.d.ts.map +1 -0
  31. package/dist/hcl/redact.js +228 -0
  32. package/dist/integrity.json +2 -2
  33. package/dist/manifest.json +1 -1
  34. package/dist/op/activities/terraform.d.ts +109 -4
  35. package/dist/op/activities/terraform.d.ts.map +1 -1
  36. package/dist/op/activities/terraform.js +148 -7
  37. package/dist/plan-observation.d.ts +153 -0
  38. package/dist/plan-observation.d.ts.map +1 -0
  39. package/dist/plan-observation.js +354 -0
  40. package/dist/plugin.d.ts.map +1 -1
  41. package/dist/plugin.js +2 -0
  42. package/package.json +2 -2
  43. package/src/__fixtures__/ACCEPTANCE.md +53 -1
  44. package/src/__fixtures__/capabilities/catalog/main.tf +105 -0
  45. package/src/__fixtures__/capabilities/chant.config.ts +15 -0
  46. package/src/__fixtures__/capabilities/findings/main.tf +225 -0
  47. package/src/__fixtures__/capabilities/ledger/main.tf +265 -0
  48. package/src/__fixtures__/capabilities/package.json +1 -0
  49. package/src/__fixtures__/effective-topology/chant.config.ts +11 -0
  50. package/src/__fixtures__/effective-topology/net/main.tf +176 -0
  51. package/src/__fixtures__/effective-topology/package.json +6 -0
  52. package/src/__fixtures__/kind-type/app/main.tf +35 -0
  53. package/src/__fixtures__/kind-type/chant.config.ts +11 -0
  54. package/src/__fixtures__/kind-type/package.json +6 -0
  55. package/src/__fixtures__/live-plan-depth/README.md +59 -0
  56. package/src/__fixtures__/live-plan-depth/live-plan.json +110 -0
  57. package/src/__fixtures__/live-plan-depth/show-plan-sensitive.json +1 -0
  58. package/src/__fixtures__/live-plan-depth/show-plan.json +1 -0
  59. package/src/__fixtures__/plan-read/main.tf +46 -0
  60. package/src/__fixtures__/plan-read/next.tfvars +1 -0
  61. package/src/__fixtures__/plan-read-drift/README.md +33 -0
  62. package/src/__fixtures__/plan-read-drift/main.tf +63 -0
  63. package/src/__fixtures__/plan-read-drift/next.tfvars +1 -0
  64. package/src/__fixtures__/search-roots/chant.config.ts +11 -0
  65. package/src/__fixtures__/search-roots/net/main.tf +73 -0
  66. package/src/__fixtures__/search-roots/package.json +6 -0
  67. package/src/__fixtures__/sensitive-default/chant.config.ts +11 -0
  68. package/src/__fixtures__/sensitive-default/net/main.tf +38 -0
  69. package/src/__fixtures__/sensitive-default/package.json +6 -0
  70. package/src/__fixtures__/show-plan.json +663 -0
  71. package/src/capabilities/adapter.ts +32 -0
  72. package/src/capabilities/mapping.json +166 -0
  73. package/src/capabilities-workspace.e2e.test.ts +251 -0
  74. package/src/capabilities.test.ts +264 -0
  75. package/src/config.ts +26 -0
  76. package/src/describe-resources.live-plan.test.ts +302 -0
  77. package/src/describe-resources.live-root-unchanged.test.ts +126 -0
  78. package/src/describe-resources.plan.test.ts +437 -0
  79. package/src/describe-resources.ts +445 -52
  80. package/src/effective-topology.test.ts +134 -0
  81. package/src/hcl/parse.ts +30 -2
  82. package/src/hcl/redact.ts +181 -0
  83. package/src/live-plan-depth.acceptance.e2e.test.ts +193 -0
  84. package/src/op/activities/terraform.test.ts +118 -1
  85. package/src/op/activities/terraform.ts +213 -9
  86. package/src/plan-observation.ts +428 -0
  87. package/src/plan-read.acceptance.test.ts +184 -0
  88. package/src/plugin.ts +2 -0
  89. package/src/redact-ir.e2e.test.ts +79 -0
  90. package/src/redact.test.ts +111 -0
  91. package/src/search-build-roots.test.ts +125 -0
  92. package/src/search-count.test.ts +144 -0
  93. package/src/search-kind-type.test.ts +136 -0
@@ -0,0 +1,225 @@
1
+ # The -findings layer of choudoufu terralith-gen -scale 4 -findings (INTENTIUS/choudoufu#2199),
2
+ # copied from its bastion.tf, data.tf and network.tf, for behold#912 steps 4 and 6 (#4375).
3
+ resource "aws_vpc" "main" {
4
+ cidr_block = "10.42.0.0/16"
5
+ }
6
+
7
+ resource "aws_subnet" "main" {
8
+ vpc_id = aws_vpc.main.id
9
+ cidr_block = "10.42.1.0/24"
10
+ availability_zone = "us-east-1a"
11
+
12
+ tags = {
13
+ Name = "tl-subnet"
14
+ }
15
+ }
16
+
17
+ resource "aws_security_group" "ecs" {
18
+ name = "tl-ecs-sg"
19
+ description = "terralith-gen: shared security group for the container-service layer"
20
+ vpc_id = aws_vpc.main.id
21
+
22
+ egress {
23
+ from_port = 0
24
+ to_port = 0
25
+ protocol = "-1"
26
+ cidr_blocks = ["0.0.0.0/0"]
27
+ }
28
+ }
29
+
30
+
31
+ resource "aws_internet_gateway" "main" {
32
+ vpc_id = aws_vpc.main.id
33
+
34
+ tags = {
35
+ Name = "tl-igw"
36
+ }
37
+ }
38
+
39
+ resource "aws_subnet" "public" {
40
+ vpc_id = aws_vpc.main.id
41
+ cidr_block = "10.42.2.0/24"
42
+ availability_zone = "us-east-1a"
43
+ map_public_ip_on_launch = true
44
+
45
+ tags = {
46
+ Name = "tl-public"
47
+ }
48
+ }
49
+
50
+ resource "aws_route_table" "public" {
51
+ vpc_id = aws_vpc.main.id
52
+
53
+ route {
54
+ cidr_block = "0.0.0.0/0"
55
+ gateway_id = aws_internet_gateway.main.id
56
+ }
57
+
58
+ tags = {
59
+ Name = "tl-public"
60
+ }
61
+ }
62
+
63
+ resource "aws_route_table_association" "public" {
64
+ subnet_id = aws_subnet.public.id
65
+ route_table_id = aws_route_table.public.id
66
+ }
67
+
68
+ resource "aws_security_group" "bastion" {
69
+ name = "tl-bastion-sg"
70
+ description = "terralith-gen: the bastion's security group"
71
+ vpc_id = aws_vpc.main.id
72
+ }
73
+
74
+ resource "aws_vpc_security_group_ingress_rule" "bastion_ssh" {
75
+ security_group_id = aws_security_group.bastion.id
76
+ description = "ssh from anywhere"
77
+ ip_protocol = "tcp"
78
+ from_port = 22
79
+ to_port = 22
80
+ cidr_ipv4 = "0.0.0.0/0"
81
+ }
82
+
83
+ resource "aws_launch_template" "bastion" {
84
+ name = "tl-bastion"
85
+ image_id = "ami-12345678"
86
+ instance_type = "t3.micro"
87
+ vpc_security_group_ids = [aws_security_group.bastion.id]
88
+
89
+ # By arn, not name: floci returns the profile by ARN only (issue #2199).
90
+ iam_instance_profile {
91
+ arn = aws_iam_instance_profile.app_data.arn
92
+ }
93
+ }
94
+
95
+ resource "aws_instance" "bastion" {
96
+ subnet_id = aws_subnet.public.id
97
+
98
+ launch_template {
99
+ id = aws_launch_template.bastion.id
100
+ version = "$Latest"
101
+ }
102
+
103
+ tags = {
104
+ Name = "tl-bastion"
105
+ }
106
+
107
+ # floci does not return the aws:ec2launchtemplate:id tag the provider
108
+ # reads this block back from, so without this every plan replaces the
109
+ # instance (issue #2199).
110
+ lifecycle {
111
+ ignore_changes = [launch_template]
112
+ }
113
+ }
114
+
115
+ resource "aws_subnet" "db_a" {
116
+ vpc_id = aws_vpc.main.id
117
+ cidr_block = "10.42.10.0/24"
118
+ availability_zone = "us-east-1a"
119
+
120
+ tags = {
121
+ Name = "tl-db-a"
122
+ }
123
+ }
124
+
125
+ resource "aws_subnet" "db_b" {
126
+ vpc_id = aws_vpc.main.id
127
+ cidr_block = "10.42.11.0/24"
128
+ availability_zone = "us-east-1b"
129
+
130
+ tags = {
131
+ Name = "tl-db-b"
132
+ }
133
+ }
134
+
135
+ resource "aws_db_subnet_group" "orders" {
136
+ name = "tl-orders"
137
+ subnet_ids = [aws_subnet.db_a.id, aws_subnet.db_b.id]
138
+ }
139
+
140
+ # storage_encrypted = true forces replacement; identifier and
141
+ # engine_version update in place on provider 6.59.0 (issue #2199).
142
+ resource "aws_db_instance" "orders" {
143
+ identifier = "tl-orders"
144
+ engine = "postgres"
145
+ engine_version = "16.3"
146
+ instance_class = "db.t3.micro"
147
+ allocated_storage = 20
148
+ db_name = "orders"
149
+ username = "orders_admin"
150
+ password = "emulator-only-not-a-secret"
151
+ db_subnet_group_name = aws_db_subnet_group.orders.name
152
+ storage_encrypted = false
153
+ skip_final_snapshot = true
154
+ }
155
+
156
+ resource "aws_dynamodb_table" "sessions" {
157
+ name = "tl-sessions"
158
+ billing_mode = "PAY_PER_REQUEST"
159
+ hash_key = "id"
160
+
161
+ attribute {
162
+ name = "id"
163
+ type = "S"
164
+ }
165
+ }
166
+
167
+ resource "aws_iam_role" "app_data" {
168
+ name = "tl-app-data-role"
169
+ assume_role_policy = jsonencode({
170
+ Version = "2012-10-17"
171
+ Statement = [{
172
+ Effect = "Allow"
173
+ Action = "sts:AssumeRole"
174
+ Principal = { Service = "ec2.amazonaws.com" }
175
+ }]
176
+ })
177
+ }
178
+
179
+ resource "aws_iam_policy" "app_data" {
180
+ name = "tl-app-data"
181
+ policy = jsonencode({
182
+ Version = "2012-10-17"
183
+ Statement = [{
184
+ Effect = "Allow"
185
+ Action = ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query", "dynamodb:DeleteItem"]
186
+ Resource = aws_dynamodb_table.sessions.arn
187
+ }]
188
+ })
189
+ }
190
+
191
+ resource "aws_iam_role_policy_attachment" "app_data" {
192
+ role = aws_iam_role.app_data.name
193
+ policy_arn = aws_iam_policy.app_data.arn
194
+ }
195
+
196
+ resource "aws_iam_instance_profile" "app_data" {
197
+ name = "tl-app-data"
198
+ role = aws_iam_role.app_data.name
199
+ }
200
+
201
+ # One of the eight team roles with dynamodb actions on Resource = "*" (iam.tf).
202
+ resource "aws_iam_role" "team_0002_role" {
203
+ name = "tl-team-0002-role"
204
+ assume_role_policy = jsonencode({
205
+ Version = "2012-10-17"
206
+ Statement = [{
207
+ Effect = "Allow"
208
+ Action = "sts:AssumeRole"
209
+ Principal = { Service = "lambda.amazonaws.com" }
210
+ }]
211
+ })
212
+ }
213
+
214
+ resource "aws_iam_role_policy" "team_0002_inline" {
215
+ name = "tl-team-0002-inline"
216
+ role = aws_iam_role.team_0002_role.name
217
+ policy = jsonencode({
218
+ Version = "2012-10-17"
219
+ Statement = [{
220
+ Effect = "Allow"
221
+ Action = ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:DeleteItem"]
222
+ Resource = "*"
223
+ }]
224
+ })
225
+ }
@@ -0,0 +1,265 @@
1
+ # "ledger": the Terraform form of the estate chant#4361 measured the rule language on (#4375).
2
+ terraform {
3
+ required_providers {
4
+ aws = { source = "hashicorp/aws", version = "~> 6.0" }
5
+ }
6
+ }
7
+ provider "aws" { region = "us-east-1" }
8
+
9
+ locals {
10
+ ami = "ami-0f3f13f145e66a0a3"
11
+ restricted = { "data-classification" = "restricted" }
12
+ }
13
+
14
+ # network
15
+ resource "aws_vpc" "vpc" { cidr_block = "10.0.0.0/16" }
16
+ resource "aws_subnet" "public" {
17
+ vpc_id = aws_vpc.vpc.id
18
+ cidr_block = "10.0.0.0/24"
19
+ }
20
+ resource "aws_subnet" "private" {
21
+ vpc_id = aws_vpc.vpc.id
22
+ cidr_block = "10.0.1.0/24"
23
+ }
24
+ resource "aws_internet_gateway" "igw" { vpc_id = aws_vpc.vpc.id }
25
+ resource "aws_route_table" "public" { vpc_id = aws_vpc.vpc.id }
26
+ resource "aws_route_table" "private" { vpc_id = aws_vpc.vpc.id }
27
+ resource "aws_route" "public_default" {
28
+ route_table_id = aws_route_table.public.id
29
+ destination_cidr_block = "0.0.0.0/0"
30
+ gateway_id = aws_internet_gateway.igw.id
31
+ }
32
+ resource "aws_route_table_association" "public" {
33
+ route_table_id = aws_route_table.public.id
34
+ subnet_id = aws_subnet.public.id
35
+ }
36
+ resource "aws_route_table_association" "private" {
37
+ route_table_id = aws_route_table.private.id
38
+ subnet_id = aws_subnet.private.id
39
+ }
40
+
41
+ resource "aws_security_group" "web" {
42
+ description = "web"
43
+ vpc_id = aws_vpc.vpc.id
44
+ ingress {
45
+ protocol = "tcp"
46
+ from_port = 443
47
+ to_port = 443
48
+ cidr_blocks = ["0.0.0.0/0"]
49
+ }
50
+ ingress {
51
+ protocol = "tcp"
52
+ from_port = 22
53
+ to_port = 22
54
+ cidr_blocks = ["0.0.0.0/0"]
55
+ }
56
+ }
57
+ resource "aws_security_group" "app" {
58
+ description = "app"
59
+ vpc_id = aws_vpc.vpc.id
60
+ }
61
+ resource "aws_vpc_security_group_ingress_rule" "app_from_web" {
62
+ security_group_id = aws_security_group.app.id
63
+ ip_protocol = "tcp"
64
+ from_port = 8080
65
+ to_port = 8080
66
+ referenced_security_group_id = aws_security_group.web.id
67
+ }
68
+ resource "aws_security_group" "db" {
69
+ description = "db"
70
+ vpc_id = aws_vpc.vpc.id
71
+ ingress {
72
+ protocol = "tcp"
73
+ from_port = 5432
74
+ to_port = 5432
75
+ security_groups = [aws_security_group.app.id]
76
+ }
77
+ }
78
+
79
+ # data
80
+ resource "aws_s3_bucket" "assets" {}
81
+ resource "aws_s3_bucket" "customer_data" { tags = local.restricted }
82
+ resource "aws_dynamodb_table" "orders" {
83
+ name = "orders"
84
+ hash_key = "id"
85
+ billing_mode = "PAY_PER_REQUEST"
86
+ attribute {
87
+ name = "id"
88
+ type = "S"
89
+ }
90
+ }
91
+ resource "aws_secretsmanager_secret" "db" { name = "ledger-db" }
92
+ resource "aws_secretsmanager_secret_version" "db" {
93
+ secret_id = aws_secretsmanager_secret.db.id
94
+ secret_string = "generated-elsewhere"
95
+ }
96
+ resource "aws_db_instance" "customers" {
97
+ engine = "postgres"
98
+ instance_class = "db.t3.micro"
99
+ allocated_storage = 20
100
+ username = "ledger"
101
+ password = aws_secretsmanager_secret_version.db.secret_string
102
+ vpc_security_group_ids = [aws_security_group.db.id]
103
+ publicly_accessible = false
104
+ storage_encrypted = true
105
+ tags = { "data-classification" = "restricted" }
106
+ }
107
+
108
+ # identity
109
+ data "aws_iam_policy_document" "ec2_trust" {
110
+ statement {
111
+ actions = ["sts:AssumeRole"]
112
+ principals {
113
+ type = "Service"
114
+ identifiers = ["ec2.amazonaws.com"]
115
+ }
116
+ }
117
+ }
118
+ resource "aws_iam_role" "web" { assume_role_policy = data.aws_iam_policy_document.ec2_trust.json }
119
+ resource "aws_iam_role" "deploy" {
120
+ assume_role_policy = jsonencode({
121
+ Version = "2012-10-17"
122
+ Statement = [{ Effect = "Allow", Principal = { AWS = aws_iam_role.web.arn }, Action = "sts:AssumeRole" }]
123
+ })
124
+ }
125
+ resource "aws_iam_role_policy" "web" {
126
+ name = "web"
127
+ role = aws_iam_role.web.id
128
+ policy = jsonencode({
129
+ Version = "2012-10-17"
130
+ Statement = [
131
+ { Effect = "Allow", Action = "s3:GetObject", Resource = "${aws_s3_bucket.assets.arn}/*" },
132
+ { Effect = "Allow", Action = "sts:AssumeRole", Resource = aws_iam_role.deploy.arn },
133
+ ]
134
+ })
135
+ }
136
+ resource "aws_iam_policy" "deploy" {
137
+ name = "deploy"
138
+ policy = jsonencode({
139
+ Version = "2012-10-17"
140
+ Statement = [
141
+ { Effect = "Allow", Action = "s3:*", Resource = [aws_s3_bucket.customer_data.arn, "${aws_s3_bucket.customer_data.arn}/*"] },
142
+ { Effect = "Allow", Action = "secretsmanager:GetSecretValue", Resource = aws_secretsmanager_secret.db.arn },
143
+ ]
144
+ })
145
+ }
146
+ resource "aws_iam_role_policy_attachment" "deploy" {
147
+ role = aws_iam_role.deploy.name
148
+ policy_arn = aws_iam_policy.deploy.arn
149
+ }
150
+ resource "aws_iam_role" "worker" {
151
+ assume_role_policy = data.aws_iam_policy_document.ec2_trust.json
152
+ inline_policy {
153
+ name = "worker"
154
+ policy = jsonencode({
155
+ Version = "2012-10-17"
156
+ Statement = [
157
+ { Effect = "Allow", Action = "secretsmanager:GetSecretValue", Resource = aws_secretsmanager_secret.db.arn },
158
+ { Effect = "Allow", Action = ["dynamodb:GetItem", "dynamodb:PutItem"], Resource = aws_dynamodb_table.orders.arn },
159
+ ]
160
+ })
161
+ }
162
+ }
163
+ resource "aws_iam_role" "reporter" {
164
+ assume_role_policy = jsonencode({
165
+ Version = "2012-10-17"
166
+ Statement = [{ Effect = "Allow", Principal = { Service = "lambda.amazonaws.com" }, Action = "sts:AssumeRole" }]
167
+ })
168
+ }
169
+ resource "aws_iam_policy" "report_read" {
170
+ policy = jsonencode({
171
+ Version = "2012-10-17"
172
+ Statement = [
173
+ { Effect = "Allow", Action = "s3:GetObject", Resource = "${aws_s3_bucket.customer_data.arn}/*" },
174
+ { Effect = "Allow", Action = "logs:*", Resource = "*" },
175
+ ]
176
+ })
177
+ }
178
+ resource "aws_iam_role_policy_attachment" "report_read" {
179
+ role = aws_iam_role.reporter.name
180
+ policy_arn = aws_iam_policy.report_read.arn
181
+ }
182
+ resource "aws_iam_role" "batch" {
183
+ assume_role_policy = jsonencode({
184
+ Version = "2012-10-17"
185
+ Statement = [{ Effect = "Allow", Principal = { Service = "lambda.amazonaws.com" }, Action = "sts:AssumeRole" }]
186
+ })
187
+ }
188
+ resource "aws_iam_role_policy" "batch" {
189
+ role = aws_iam_role.batch.id
190
+ policy = jsonencode({
191
+ Version = "2012-10-17"
192
+ Statement = [{ Effect = "Allow", Action = "sts:AssumeRole", Resource = "arn:aws:iam::123456789012:role/audit" }]
193
+ })
194
+ }
195
+ resource "aws_iam_role" "audit" {
196
+ name = "audit"
197
+ assume_role_policy = jsonencode({
198
+ Version = "2012-10-17"
199
+ Statement = [{ Effect = "Allow", Principal = { AWS = aws_iam_role.batch.arn }, Action = "sts:AssumeRole" }]
200
+ })
201
+ }
202
+ resource "aws_iam_role_policy" "audit" {
203
+ role = aws_iam_role.audit.id
204
+ policy = jsonencode({
205
+ Version = "2012-10-17"
206
+ Statement = [{ Effect = "Allow", Action = "dynamodb:Scan", Resource = aws_dynamodb_table.orders.arn }]
207
+ })
208
+ }
209
+ resource "aws_s3_bucket_policy" "assets" {
210
+ bucket = aws_s3_bucket.assets.id
211
+ policy = jsonencode({
212
+ Version = "2012-10-17"
213
+ Statement = [{ Effect = "Allow", Principal = { AWS = aws_iam_role.worker.arn }, Action = "s3:GetObject", Resource = "${aws_s3_bucket.assets.arn}/*" }]
214
+ })
215
+ }
216
+
217
+ # compute
218
+ resource "aws_iam_instance_profile" "web" { role = aws_iam_role.web.name }
219
+ resource "aws_iam_instance_profile" "worker" { role = aws_iam_role.worker.name }
220
+ resource "aws_launch_template" "web" {
221
+ image_id = local.ami
222
+ instance_type = "t3.micro"
223
+ vpc_security_group_ids = [aws_security_group.web.id]
224
+ }
225
+ resource "aws_instance" "web" {
226
+ launch_template {
227
+ id = aws_launch_template.web.id
228
+ version = "1"
229
+ }
230
+ subnet_id = aws_subnet.public.id
231
+ iam_instance_profile = aws_iam_instance_profile.web.name
232
+ }
233
+ resource "aws_instance" "worker" {
234
+ ami = local.ami
235
+ instance_type = "t3.micro"
236
+ subnet_id = aws_subnet.private.id
237
+ vpc_security_group_ids = [aws_security_group.app.id]
238
+ iam_instance_profile = aws_iam_instance_profile.worker.name
239
+ }
240
+ # in a public subnet, but nothing on the internet is allowed in
241
+ resource "aws_instance" "admin_box" {
242
+ ami = local.ami
243
+ instance_type = "t3.micro"
244
+ subnet_id = aws_subnet.public.id
245
+ vpc_security_group_ids = [aws_security_group.app.id]
246
+ iam_instance_profile = aws_iam_instance_profile.worker.name
247
+ }
248
+ resource "aws_lambda_function" "reporter" {
249
+ function_name = "reporter"
250
+ runtime = "nodejs22.x"
251
+ handler = "index.handler"
252
+ role = aws_iam_role.reporter.arn
253
+ filename = "fn.zip"
254
+ }
255
+ resource "aws_lambda_function_url" "reporter" {
256
+ function_name = aws_lambda_function.reporter.function_name
257
+ authorization_type = "NONE"
258
+ }
259
+ resource "aws_lambda_function" "batch" {
260
+ function_name = "batch"
261
+ runtime = "nodejs22.x"
262
+ handler = "index.handler"
263
+ role = aws_iam_role.batch.arn
264
+ filename = "fn.zip"
265
+ }
@@ -0,0 +1 @@
1
+ { "name": "chant-fixture-terraform-capabilities", "version": "0.0.0", "private": true, "type": "module" }
@@ -0,0 +1,11 @@
1
+ import type { ChantConfig } from "@intentius/chant/config";
2
+ import "@intentius/chant-lexicon-terraform";
3
+
4
+ export default {
5
+ lexicons: ["terraform"],
6
+ terraform: {
7
+ roots: {
8
+ net: { dir: "./net" },
9
+ },
10
+ },
11
+ } satisfies ChantConfig;
@@ -0,0 +1,176 @@
1
+ # One VPC, three instances. Only `web` is internet-facing with SSH open to the
2
+ # world, and it gets its SSH rule through a launch template's security group.
3
+ # Every way of writing a route to an internet gateway and every way of writing
4
+ # an ingress rule appears exactly once, each on a path a test pins (chant #4362).
5
+
6
+ resource "aws_vpc" "main" {
7
+ cidr_block = "10.0.0.0/16"
8
+ }
9
+
10
+ resource "aws_internet_gateway" "main" {
11
+ vpc_id = aws_vpc.main.id
12
+ }
13
+
14
+ # --- Subnets and routing --------------------------------------------------
15
+
16
+ # public_a routes to the IGW through an INLINE `route` block.
17
+ resource "aws_subnet" "public_a" {
18
+ vpc_id = aws_vpc.main.id
19
+ cidr_block = "10.0.1.0/24"
20
+ }
21
+
22
+ resource "aws_route_table" "public_inline" {
23
+ vpc_id = aws_vpc.main.id
24
+
25
+ route {
26
+ cidr_block = "0.0.0.0/0"
27
+ gateway_id = aws_internet_gateway.main.id
28
+ }
29
+ }
30
+
31
+ resource "aws_route_table_association" "public_a" {
32
+ subnet_id = aws_subnet.public_a.id
33
+ route_table_id = aws_route_table.public_inline.id
34
+ }
35
+
36
+ # public_b routes to the IGW through a separate `aws_route` resource.
37
+ resource "aws_subnet" "public_b" {
38
+ vpc_id = aws_vpc.main.id
39
+ cidr_block = "10.0.2.0/24"
40
+ }
41
+
42
+ resource "aws_route_table" "public_separate" {
43
+ vpc_id = aws_vpc.main.id
44
+ }
45
+
46
+ resource "aws_route" "public_separate_default" {
47
+ route_table_id = aws_route_table.public_separate.id
48
+ destination_cidr_block = "0.0.0.0/0"
49
+ gateway_id = aws_internet_gateway.main.id
50
+ }
51
+
52
+ resource "aws_route_table_association" "public_b" {
53
+ subnet_id = aws_subnet.public_b.id
54
+ route_table_id = aws_route_table.public_separate.id
55
+ }
56
+
57
+ # private's default route goes to a NAT gateway, which is not internet-facing.
58
+ resource "aws_subnet" "private" {
59
+ vpc_id = aws_vpc.main.id
60
+ cidr_block = "10.0.3.0/24"
61
+ }
62
+
63
+ resource "aws_eip" "nat" {
64
+ domain = "vpc"
65
+ }
66
+
67
+ resource "aws_nat_gateway" "main" {
68
+ allocation_id = aws_eip.nat.id
69
+ subnet_id = aws_subnet.public_a.id
70
+ }
71
+
72
+ resource "aws_route_table" "private" {
73
+ vpc_id = aws_vpc.main.id
74
+
75
+ route {
76
+ cidr_block = "0.0.0.0/0"
77
+ nat_gateway_id = aws_nat_gateway.main.id
78
+ }
79
+ }
80
+
81
+ resource "aws_route_table_association" "private" {
82
+ subnet_id = aws_subnet.private.id
83
+ route_table_id = aws_route_table.private.id
84
+ }
85
+
86
+ # --- Security groups ------------------------------------------------------
87
+
88
+ # web: SSH open to the world through an INLINE `ingress` block.
89
+ resource "aws_security_group" "web" {
90
+ vpc_id = aws_vpc.main.id
91
+
92
+ ingress {
93
+ protocol = "tcp"
94
+ from_port = 22
95
+ to_port = 22
96
+ cidr_blocks = ["0.0.0.0/0"]
97
+ }
98
+
99
+ egress {
100
+ protocol = "-1"
101
+ from_port = 0
102
+ to_port = 0
103
+ cidr_blocks = ["0.0.0.0/0"]
104
+ }
105
+ }
106
+
107
+ # batch: HTTPS through an `aws_vpc_security_group_ingress_rule` resource.
108
+ resource "aws_security_group" "batch" {
109
+ vpc_id = aws_vpc.main.id
110
+ }
111
+
112
+ resource "aws_vpc_security_group_ingress_rule" "batch_https" {
113
+ security_group_id = aws_security_group.batch.id
114
+ ip_protocol = "tcp"
115
+ from_port = 443
116
+ to_port = 443
117
+ cidr_ipv4 = "0.0.0.0/0"
118
+ }
119
+
120
+ # db: SSH open to the world through an `aws_security_group_rule` resource. The
121
+ # egress rule beside it is not ingress and must not be counted.
122
+ resource "aws_security_group" "db" {
123
+ vpc_id = aws_vpc.main.id
124
+ }
125
+
126
+ resource "aws_security_group_rule" "db_ssh" {
127
+ type = "ingress"
128
+ security_group_id = aws_security_group.db.id
129
+ protocol = "tcp"
130
+ from_port = 22
131
+ to_port = 22
132
+ cidr_blocks = ["0.0.0.0/0"]
133
+ }
134
+
135
+ resource "aws_security_group_rule" "db_egress" {
136
+ type = "egress"
137
+ security_group_id = aws_security_group.db.id
138
+ protocol = "-1"
139
+ from_port = 0
140
+ to_port = 0
141
+ cidr_blocks = ["0.0.0.0/0"]
142
+ }
143
+
144
+ # --- Instances ------------------------------------------------------------
145
+
146
+ resource "aws_launch_template" "web" {
147
+ image_id = "ami-12345678"
148
+ instance_type = "t3.micro"
149
+ vpc_security_group_ids = [aws_security_group.web.id]
150
+ }
151
+
152
+ # Public, SSH open to the world via the launch template's group. The one match.
153
+ resource "aws_instance" "web" {
154
+ subnet_id = aws_subnet.public_a.id
155
+
156
+ launch_template {
157
+ id = aws_launch_template.web.id
158
+ version = "$Latest"
159
+ }
160
+ }
161
+
162
+ # Public (through the aws_route spelling), HTTPS only, group via `security_groups`.
163
+ resource "aws_instance" "batch" {
164
+ ami = "ami-12345678"
165
+ instance_type = "t3.micro"
166
+ subnet_id = aws_subnet.public_b.id
167
+ security_groups = [aws_security_group.batch.id]
168
+ }
169
+
170
+ # Private, SSH open to the world via `vpc_security_group_ids`. Not reachable.
171
+ resource "aws_instance" "db" {
172
+ ami = "ami-12345678"
173
+ instance_type = "t3.micro"
174
+ subnet_id = aws_subnet.private.id
175
+ vpc_security_group_ids = [aws_security_group.db.id]
176
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "chant-fixture-terraform-effective-topology",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module"
6
+ }