@suss/terraform-aws 0.31.2 → 0.33.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.
- package/README.md +26 -7
- package/dist/index.cjs +130 -9
- package/dist/index.js +130 -9
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -23,19 +23,23 @@ terraformFileToSummaries("infra/terraform/dynamodb", { packs: [awsTerraform()] }
|
|
|
23
23
|
| --- | --- |
|
|
24
24
|
| `aws_dynamodb_table` | a store, keyed by `hash_key` and `range_key`, with each `global_secondary_index` and `local_secondary_index` as its own way in |
|
|
25
25
|
| `aws_s3_bucket` | a store whose objects have no fields to compare against |
|
|
26
|
-
| `aws_elasticache_cluster` | a Redis store, when `engine` is `redis` or `valkey
|
|
26
|
+
| `aws_elasticache_cluster` | a Redis store, when `engine` is `redis` or `valkey` or unset; any other engine leaves the store with no engine on it |
|
|
27
27
|
| `aws_elasticache_replication_group` | a Redis store |
|
|
28
|
+
| `aws_rds_cluster` | a PostgreSQL or MySQL store, whichever its `engine` picks |
|
|
29
|
+
| `aws_db_instance` | the same, and `mariadb` counts as MySQL |
|
|
28
30
|
| `aws_sqs_queue` | a channel |
|
|
29
31
|
| `aws_sns_topic` | a channel |
|
|
30
32
|
| `aws_cloudwatch_event_bus` | a channel |
|
|
33
|
+
| `aws_kinesis_stream` | a channel |
|
|
34
|
+
| `aws_kinesis_firehose_delivery_stream` | a channel |
|
|
35
|
+
| `aws_cloudwatch_log_metric_filter` | a metric, identified by its namespace and its name together |
|
|
36
|
+
| `aws_cloudwatch_metric_alarm` | one consumer of that metric, identified the same way |
|
|
37
|
+
| `aws_lambda_function` | a deployable, with the variables it sets and the handler it calls |
|
|
38
|
+
| `aws_ecs_task_definition` | a deployable per container, with that container's variables, secrets and image |
|
|
31
39
|
|
|
32
40
|
Everything else a configuration declares, a security group, a subnet, an IAM policy, is how the deployment is wired rather than something a caller addresses, so nothing reads it.
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Code addresses Redis by key namespace: `@suss/framework-redis` reads `session:{id}` and records the container `session`. A cluster declares no namespaces; its `cluster_id` is a deployment name, and code never spells it. The two sides share no name either can state, so the entry says so: the summary declares the store exists, with no container name, and the storage check claims no access for it. A pair between a cluster called `session` and the `session` namespace would be a coincidence between a deployment name and a key prefix, so the entry refuses it rather than reporting it.
|
|
37
|
-
|
|
38
|
-
What you get from the entry is visibility: `suss contract --from terraform` shows the cluster, and `suss check` reports it as a declared store nothing paired with. Namespace-level pairing stays between the code's own readers and writers of the same keys.
|
|
42
|
+
A database instance and a Redis cluster are the two that pair with nothing: code addresses tables and key namespaces inside them, and no attribute of either lists one, so each declares the store and claims no access. Kinesis pairs with nothing yet either, since no code pack records a send to a stream. [What each entry decided](./DESIGN.md) says why for each of them, and what an alarm and a metric filter share.
|
|
39
43
|
|
|
40
44
|
## Why every entry states a version range
|
|
41
45
|
|
|
@@ -53,6 +57,21 @@ terraform {
|
|
|
53
57
|
|
|
54
58
|
The reader takes that pin and hands it to the pack. A configuration that pins nothing is read by every entry, since nothing said otherwise.
|
|
55
59
|
|
|
60
|
+
Every entry here was written against `>=4 <7`, from these pages of the provider's own documentation:
|
|
61
|
+
|
|
62
|
+
- [`aws_dynamodb_table`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/dynamodb_table), [`aws_s3_bucket`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket)
|
|
63
|
+
- [`aws_elasticache_cluster`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_cluster), [`aws_elasticache_replication_group`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_replication_group)
|
|
64
|
+
- [`aws_rds_cluster`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster), [`aws_db_instance`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance)
|
|
65
|
+
- [`aws_sqs_queue`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue), [`aws_sns_topic`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic), [`aws_cloudwatch_event_bus`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_bus)
|
|
66
|
+
- [`aws_kinesis_stream`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kinesis_stream), [`aws_kinesis_firehose_delivery_stream`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kinesis_firehose_delivery_stream)
|
|
67
|
+
- [`aws_cloudwatch_log_metric_filter`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_metric_filter), [`aws_cloudwatch_metric_alarm`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm)
|
|
68
|
+
|
|
56
69
|
## Where it fits in suss
|
|
57
70
|
|
|
58
|
-
Depends on `@suss/contract-terraform` for the shape of an entry, and on
|
|
71
|
+
Depends on `@suss/contract-terraform` for the shape of an entry, and on `@suss/ir-core` for the variables each deployment target injects on its own. A pack for another provider, `google` or `cloudflare`, is the same file with different entries.
|
|
72
|
+
|
|
73
|
+
## More
|
|
74
|
+
|
|
75
|
+
- [What each entry decided](./DESIGN.md)
|
|
76
|
+
- [Documentation](https://suss.sh/)
|
|
77
|
+
- [Source and issues](https://github.com/nimbuscloud-ai/suss)
|
package/dist/index.cjs
CHANGED
|
@@ -25,6 +25,41 @@ __export(index_exports, {
|
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(index_exports);
|
|
27
27
|
var CURRENT = ">=4 <7";
|
|
28
|
+
var METRIC_SYSTEM = "cloudwatch";
|
|
29
|
+
var STATISTICS = {
|
|
30
|
+
SampleCount: "number",
|
|
31
|
+
Average: "number",
|
|
32
|
+
Sum: "number",
|
|
33
|
+
Minimum: "number",
|
|
34
|
+
Maximum: "number"
|
|
35
|
+
};
|
|
36
|
+
var SQL_ENGINES = {
|
|
37
|
+
attribute: "engine",
|
|
38
|
+
means: {
|
|
39
|
+
postgres: "postgresql",
|
|
40
|
+
"aurora-postgresql": "postgresql",
|
|
41
|
+
mysql: "mysql",
|
|
42
|
+
"aurora-mysql": "mysql",
|
|
43
|
+
mariadb: "mysql"
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
var CACHE_ENGINES = {
|
|
47
|
+
attribute: "engine",
|
|
48
|
+
means: { redis: "redis", valkey: "redis" },
|
|
49
|
+
whenUnset: "redis"
|
|
50
|
+
};
|
|
51
|
+
function sqlStore(resource) {
|
|
52
|
+
return {
|
|
53
|
+
resource,
|
|
54
|
+
providerVersions: CURRENT,
|
|
55
|
+
boundary: {
|
|
56
|
+
kind: "storage",
|
|
57
|
+
storageSystem: SQL_ENGINES,
|
|
58
|
+
declares: "store",
|
|
59
|
+
fieldSet: "none"
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
28
63
|
function awsTerraform() {
|
|
29
64
|
return {
|
|
30
65
|
name: "terraform-aws",
|
|
@@ -74,17 +109,9 @@ function awsTerraform() {
|
|
|
74
109
|
{
|
|
75
110
|
resource: "aws_elasticache_cluster",
|
|
76
111
|
providerVersions: CURRENT,
|
|
77
|
-
// A cluster with no engine of its own joins a replication
|
|
78
|
-
// group, which always runs one of the two Redis-protocol
|
|
79
|
-
// engines, so an unset engine is read.
|
|
80
|
-
appliesWhen: {
|
|
81
|
-
attribute: "engine",
|
|
82
|
-
equals: ["redis", "valkey"],
|
|
83
|
-
whenUnset: "read"
|
|
84
|
-
},
|
|
85
112
|
boundary: {
|
|
86
113
|
kind: "storage",
|
|
87
|
-
storageSystem:
|
|
114
|
+
storageSystem: CACHE_ENGINES,
|
|
88
115
|
// Code addresses key namespaces, which no attribute of a
|
|
89
116
|
// cluster lists, so the cluster declares the store and
|
|
90
117
|
// claims no access. The README says how the sides meet.
|
|
@@ -102,6 +129,8 @@ function awsTerraform() {
|
|
|
102
129
|
fieldSet: "none"
|
|
103
130
|
}
|
|
104
131
|
},
|
|
132
|
+
sqlStore("aws_rds_cluster"),
|
|
133
|
+
sqlStore("aws_db_instance"),
|
|
105
134
|
{
|
|
106
135
|
resource: "aws_sqs_queue",
|
|
107
136
|
providerVersions: CURRENT,
|
|
@@ -128,6 +157,98 @@ function awsTerraform() {
|
|
|
128
157
|
messageBus: "eventbridge",
|
|
129
158
|
nameAttribute: "name"
|
|
130
159
|
}
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
resource: "aws_kinesis_stream",
|
|
163
|
+
providerVersions: CURRENT,
|
|
164
|
+
boundary: {
|
|
165
|
+
kind: "message-bus",
|
|
166
|
+
messageBus: "aws_kinesis",
|
|
167
|
+
nameAttribute: "name"
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
resource: "aws_kinesis_firehose_delivery_stream",
|
|
172
|
+
providerVersions: CURRENT,
|
|
173
|
+
boundary: {
|
|
174
|
+
kind: "message-bus",
|
|
175
|
+
messageBus: "aws_firehose",
|
|
176
|
+
nameAttribute: "name"
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
resource: "aws_cloudwatch_log_metric_filter",
|
|
181
|
+
providerVersions: CURRENT,
|
|
182
|
+
boundary: {
|
|
183
|
+
kind: "metric",
|
|
184
|
+
metricSystem: METRIC_SYSTEM,
|
|
185
|
+
// CloudWatch identifies a metric by its namespace and its
|
|
186
|
+
// name together, and an alarm spells both, so both are the
|
|
187
|
+
// identity the two sides share.
|
|
188
|
+
metricTypeTemplate: "{metric_transformation.namespace}/{metric_transformation.name}"
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
resource: "aws_cloudwatch_metric_alarm",
|
|
193
|
+
providerVersions: CURRENT,
|
|
194
|
+
boundary: {
|
|
195
|
+
kind: "metric-reading",
|
|
196
|
+
metricSystem: METRIC_SYSTEM,
|
|
197
|
+
// An alarm on a single metric is one reading, written in the
|
|
198
|
+
// resource itself rather than in a block.
|
|
199
|
+
readingBlocks: [],
|
|
200
|
+
identifies: {
|
|
201
|
+
from: "attributes",
|
|
202
|
+
template: "{namespace}/{metric_name}"
|
|
203
|
+
},
|
|
204
|
+
comparesTo: { attribute: "threshold", whenSet: "number" },
|
|
205
|
+
reducesTo: { attribute: "statistic", means: STATISTICS }
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
resource: "aws_lambda_function",
|
|
210
|
+
providerVersions: CURRENT,
|
|
211
|
+
boundary: {
|
|
212
|
+
kind: "deployable",
|
|
213
|
+
deploymentTarget: "lambda",
|
|
214
|
+
runtimeAttribute: "runtime",
|
|
215
|
+
env: [{ style: "map", attribute: "environment.variables" }],
|
|
216
|
+
// Lambda writes the module and the exported name into one
|
|
217
|
+
// string, split at the last dot.
|
|
218
|
+
code: {
|
|
219
|
+
handler: { attribute: "handler", spelling: "module.export" }
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
resource: "aws_ecs_task_definition",
|
|
225
|
+
providerVersions: CURRENT,
|
|
226
|
+
boundary: {
|
|
227
|
+
kind: "deployable",
|
|
228
|
+
deploymentTarget: "ecs-task",
|
|
229
|
+
// One task definition runs several containers, each starting
|
|
230
|
+
// with an environment of its own, and the JSON they are
|
|
231
|
+
// written in is read the same way a block would be.
|
|
232
|
+
containers: {
|
|
233
|
+
blocks: ["container_definitions"],
|
|
234
|
+
nameAttribute: "name"
|
|
235
|
+
},
|
|
236
|
+
env: [
|
|
237
|
+
{
|
|
238
|
+
style: "entries",
|
|
239
|
+
block: "environment",
|
|
240
|
+
nameAttribute: "name",
|
|
241
|
+
valueAttribute: "value"
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
style: "entries",
|
|
245
|
+
block: "secrets",
|
|
246
|
+
nameAttribute: "name",
|
|
247
|
+
secretAttribute: "valueFrom"
|
|
248
|
+
}
|
|
249
|
+
],
|
|
250
|
+
code: { imageAttribute: "image" }
|
|
251
|
+
}
|
|
131
252
|
}
|
|
132
253
|
]
|
|
133
254
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
var CURRENT = ">=4 <7";
|
|
3
|
+
var METRIC_SYSTEM = "cloudwatch";
|
|
4
|
+
var STATISTICS = {
|
|
5
|
+
SampleCount: "number",
|
|
6
|
+
Average: "number",
|
|
7
|
+
Sum: "number",
|
|
8
|
+
Minimum: "number",
|
|
9
|
+
Maximum: "number"
|
|
10
|
+
};
|
|
11
|
+
var SQL_ENGINES = {
|
|
12
|
+
attribute: "engine",
|
|
13
|
+
means: {
|
|
14
|
+
postgres: "postgresql",
|
|
15
|
+
"aurora-postgresql": "postgresql",
|
|
16
|
+
mysql: "mysql",
|
|
17
|
+
"aurora-mysql": "mysql",
|
|
18
|
+
mariadb: "mysql"
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var CACHE_ENGINES = {
|
|
22
|
+
attribute: "engine",
|
|
23
|
+
means: { redis: "redis", valkey: "redis" },
|
|
24
|
+
whenUnset: "redis"
|
|
25
|
+
};
|
|
26
|
+
function sqlStore(resource) {
|
|
27
|
+
return {
|
|
28
|
+
resource,
|
|
29
|
+
providerVersions: CURRENT,
|
|
30
|
+
boundary: {
|
|
31
|
+
kind: "storage",
|
|
32
|
+
storageSystem: SQL_ENGINES,
|
|
33
|
+
declares: "store",
|
|
34
|
+
fieldSet: "none"
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
3
38
|
function awsTerraform() {
|
|
4
39
|
return {
|
|
5
40
|
name: "terraform-aws",
|
|
@@ -49,17 +84,9 @@ function awsTerraform() {
|
|
|
49
84
|
{
|
|
50
85
|
resource: "aws_elasticache_cluster",
|
|
51
86
|
providerVersions: CURRENT,
|
|
52
|
-
// A cluster with no engine of its own joins a replication
|
|
53
|
-
// group, which always runs one of the two Redis-protocol
|
|
54
|
-
// engines, so an unset engine is read.
|
|
55
|
-
appliesWhen: {
|
|
56
|
-
attribute: "engine",
|
|
57
|
-
equals: ["redis", "valkey"],
|
|
58
|
-
whenUnset: "read"
|
|
59
|
-
},
|
|
60
87
|
boundary: {
|
|
61
88
|
kind: "storage",
|
|
62
|
-
storageSystem:
|
|
89
|
+
storageSystem: CACHE_ENGINES,
|
|
63
90
|
// Code addresses key namespaces, which no attribute of a
|
|
64
91
|
// cluster lists, so the cluster declares the store and
|
|
65
92
|
// claims no access. The README says how the sides meet.
|
|
@@ -77,6 +104,8 @@ function awsTerraform() {
|
|
|
77
104
|
fieldSet: "none"
|
|
78
105
|
}
|
|
79
106
|
},
|
|
107
|
+
sqlStore("aws_rds_cluster"),
|
|
108
|
+
sqlStore("aws_db_instance"),
|
|
80
109
|
{
|
|
81
110
|
resource: "aws_sqs_queue",
|
|
82
111
|
providerVersions: CURRENT,
|
|
@@ -103,6 +132,98 @@ function awsTerraform() {
|
|
|
103
132
|
messageBus: "eventbridge",
|
|
104
133
|
nameAttribute: "name"
|
|
105
134
|
}
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
resource: "aws_kinesis_stream",
|
|
138
|
+
providerVersions: CURRENT,
|
|
139
|
+
boundary: {
|
|
140
|
+
kind: "message-bus",
|
|
141
|
+
messageBus: "aws_kinesis",
|
|
142
|
+
nameAttribute: "name"
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
resource: "aws_kinesis_firehose_delivery_stream",
|
|
147
|
+
providerVersions: CURRENT,
|
|
148
|
+
boundary: {
|
|
149
|
+
kind: "message-bus",
|
|
150
|
+
messageBus: "aws_firehose",
|
|
151
|
+
nameAttribute: "name"
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
resource: "aws_cloudwatch_log_metric_filter",
|
|
156
|
+
providerVersions: CURRENT,
|
|
157
|
+
boundary: {
|
|
158
|
+
kind: "metric",
|
|
159
|
+
metricSystem: METRIC_SYSTEM,
|
|
160
|
+
// CloudWatch identifies a metric by its namespace and its
|
|
161
|
+
// name together, and an alarm spells both, so both are the
|
|
162
|
+
// identity the two sides share.
|
|
163
|
+
metricTypeTemplate: "{metric_transformation.namespace}/{metric_transformation.name}"
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
resource: "aws_cloudwatch_metric_alarm",
|
|
168
|
+
providerVersions: CURRENT,
|
|
169
|
+
boundary: {
|
|
170
|
+
kind: "metric-reading",
|
|
171
|
+
metricSystem: METRIC_SYSTEM,
|
|
172
|
+
// An alarm on a single metric is one reading, written in the
|
|
173
|
+
// resource itself rather than in a block.
|
|
174
|
+
readingBlocks: [],
|
|
175
|
+
identifies: {
|
|
176
|
+
from: "attributes",
|
|
177
|
+
template: "{namespace}/{metric_name}"
|
|
178
|
+
},
|
|
179
|
+
comparesTo: { attribute: "threshold", whenSet: "number" },
|
|
180
|
+
reducesTo: { attribute: "statistic", means: STATISTICS }
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
resource: "aws_lambda_function",
|
|
185
|
+
providerVersions: CURRENT,
|
|
186
|
+
boundary: {
|
|
187
|
+
kind: "deployable",
|
|
188
|
+
deploymentTarget: "lambda",
|
|
189
|
+
runtimeAttribute: "runtime",
|
|
190
|
+
env: [{ style: "map", attribute: "environment.variables" }],
|
|
191
|
+
// Lambda writes the module and the exported name into one
|
|
192
|
+
// string, split at the last dot.
|
|
193
|
+
code: {
|
|
194
|
+
handler: { attribute: "handler", spelling: "module.export" }
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
resource: "aws_ecs_task_definition",
|
|
200
|
+
providerVersions: CURRENT,
|
|
201
|
+
boundary: {
|
|
202
|
+
kind: "deployable",
|
|
203
|
+
deploymentTarget: "ecs-task",
|
|
204
|
+
// One task definition runs several containers, each starting
|
|
205
|
+
// with an environment of its own, and the JSON they are
|
|
206
|
+
// written in is read the same way a block would be.
|
|
207
|
+
containers: {
|
|
208
|
+
blocks: ["container_definitions"],
|
|
209
|
+
nameAttribute: "name"
|
|
210
|
+
},
|
|
211
|
+
env: [
|
|
212
|
+
{
|
|
213
|
+
style: "entries",
|
|
214
|
+
block: "environment",
|
|
215
|
+
nameAttribute: "name",
|
|
216
|
+
valueAttribute: "value"
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
style: "entries",
|
|
220
|
+
block: "secrets",
|
|
221
|
+
nameAttribute: "name",
|
|
222
|
+
secretAttribute: "valueFrom"
|
|
223
|
+
}
|
|
224
|
+
],
|
|
225
|
+
code: { imageAttribute: "image" }
|
|
226
|
+
}
|
|
106
227
|
}
|
|
107
228
|
]
|
|
108
229
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suss/terraform-aws",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "What the AWS Terraform provider declares, so suss can check your code against the infrastructure you deploy.",
|
|
6
6
|
"keywords": [
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"typecheck": "tsc --noEmit"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@suss/contract-terraform": "0.
|
|
49
|
+
"@suss/contract-terraform": "0.33.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@suss/behavioral-ir": "*",
|