@suss/terraform-gcp 0.33.0 → 0.34.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 +22 -22
- package/dist/index.cjs +15 -14
- package/dist/index.d.cts +8 -9
- package/dist/index.d.ts +8 -9
- package/dist/index.js +15 -14
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# @suss/terraform-gcp
|
|
2
2
|
|
|
3
|
-
Part of [suss](https://github.com/nimbuscloud-ai/suss), which reads both sides of every call in a repository and
|
|
3
|
+
Part of [suss](https://github.com/nimbuscloud-ai/suss), which reads both sides of every call in a repository and reports where the two disagree.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This pack declares what the Google Cloud Terraform provider's resources are, for `@suss/contract-terraform` to read.
|
|
6
6
|
|
|
7
7
|
## What this package is
|
|
8
8
|
|
|
9
|
-
A pack
|
|
9
|
+
A pack made only of entries. Each entry declares what a resource is, and translates the resource's own terms into the ones suss compares boundaries in.
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
12
|
import { terraformFileToSummaries } from "@suss/contract-terraform";
|
|
@@ -17,7 +17,7 @@ const summaries = terraformFileToSummaries("infra/terraform/monitoring", {
|
|
|
17
17
|
});
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
`suss contract --from terraform <path>` loads the entries for you. Nothing here runs at check time
|
|
20
|
+
`suss contract --from terraform <path>` loads the entries for you. Nothing here runs at check time. The summaries contain what a metric measures and what a reading needs, and `checkMetric` in `@suss/checker` compares them. So `suss check --dir` over a folder of summaries reports the pair described below without loading any pack.
|
|
21
21
|
|
|
22
22
|
## What it reads today
|
|
23
23
|
|
|
@@ -41,11 +41,11 @@ const summaries = terraformFileToSummaries("infra/terraform/monitoring", {
|
|
|
41
41
|
|
|
42
42
|
Everything else a configuration declares is skipped.
|
|
43
43
|
|
|
44
|
-
A bucket pairs by name
|
|
44
|
+
A bucket pairs by name. `@suss/framework-gcs` records the bucket an access reaches, and the `name` attribute is the same string, so `suss check` compares the two sides. A Memorystore instance does not pair. Code addresses Redis by key namespace, no attribute of the instance declares one, and a match on the instance's own name would be a coincidence. So the summary declares the store with no container name, and the storage check claims no access for it. The DESIGN notes in `@suss/terraform-aws` go through the same decision for ElastiCache. Spanner, Firestore and Cloud SQL are the same case: the tables or collections are inside the database, and nothing on the resource lists them.
|
|
45
45
|
|
|
46
|
-
A BigQuery table is the
|
|
46
|
+
A BigQuery table is the only resource here with a field contract, since a query against it reads named columns. A Cloud Run service, a job and a function each declare the environment their containers start with. A Pub/Sub topic and subscription do not pair with anything yet, because no code pack records a publish or a subscribe. [Why each entry reads what it reads](./DESIGN.md) explains how each of those is read.
|
|
47
47
|
|
|
48
|
-
##
|
|
48
|
+
## A pair the provider rejects at apply time
|
|
49
49
|
|
|
50
50
|
A log-based metric can declare that each measurement is a histogram of buckets:
|
|
51
51
|
|
|
@@ -70,32 +70,32 @@ condition_threshold {
|
|
|
70
70
|
}
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
Both blocks are well formed, `terraform validate` and `terraform plan` both pass
|
|
73
|
+
Both blocks are well formed, and `terraform validate` and `terraform plan` both pass. Then the apply fails several minutes in. A distribution has no single value to compare, and Cloud Monitoring needs an aligner such as `ALIGN_PERCENTILE_95` to reduce each window to one number first.
|
|
74
74
|
|
|
75
|
-
The entries
|
|
75
|
+
The entries declare three things: `value_type = "DISTRIBUTION"` means the measurements are a histogram, a `threshold_value` means the condition compares against a single number, and the four percentile aligners are the ones that reduce a window to a number. `checkMetric` combines those and reports the pair as a `boundaryShapeMismatch` at error severity. The finding points at `aggregations.per_series_aligner` and lists the four values that would fix it.
|
|
76
76
|
|
|
77
|
-
A condition that
|
|
77
|
+
A condition that sets one of the percentile aligners is left alone, and so is a condition on a metric declared as `INT64` or `DOUBLE`.
|
|
78
78
|
|
|
79
79
|
## What it will not tell you
|
|
80
80
|
|
|
81
|
-
- **A condition about a metric nothing in the run declares**
|
|
82
|
-
- **A condition that
|
|
83
|
-
- **A metric the platform publishes**, `run.googleapis.com/request_latencies
|
|
84
|
-
- **A `BOOL`, `STRING
|
|
85
|
-
- **`for_each` and `count`**
|
|
86
|
-
- **`google_sql_database`**, the named database inside a Cloud SQL instance,
|
|
87
|
-
- **`google_monitoring_uptime_check_config`** is a probe
|
|
88
|
-
- **A Spanner database's `ddl`** statements
|
|
89
|
-
- **A Firestore database in Datastore mode**
|
|
81
|
+
- **A condition about a metric that nothing in the run declares** produces nothing. Most alerts watch metrics the platform publishes, and from here a metric declared in a module this run did not read looks the same. The pairing pass reports a boundary with one side missing.
|
|
82
|
+
- **A condition that does not give a `metric.type`** has no metric type on it, so it does not pair with anything and cannot pair with the wrong thing. An SLO burn-rate condition is written as a call instead of a comparison, and is about an objective instead of a metric, so it ends up in this case.
|
|
83
|
+
- **A metric the platform publishes**, such as `run.googleapis.com/request_latencies`, has its value type in Google's documentation and not in any configuration. Judging a condition on one of those needs a catalog that this pack does not include.
|
|
84
|
+
- **A `BOOL`, `STRING` or `MONEY` metric** is left out of the value-type table, because suss has no term that describes one, and a metric this pack does not describe is not compared against anything.
|
|
85
|
+
- **`for_each` and `count`** use one block for many resources, and the reader takes the block as written.
|
|
86
|
+
- **`google_sql_database`**, the named database inside a Cloud SQL instance, has no engine of its own. The engine is on the instance its `instance` attribute points at, and an entry cannot read an attribute through a reference to another resource. So the database is not read, and the instance is what declares the store.
|
|
87
|
+
- **`google_monitoring_uptime_check_config`** is a probe, and does not read a metric. It makes its own requests on a schedule and publishes a result, so it never reads a metric type back and `checkMetric` has nothing to compare. It would fit a kind for synthetic checks, which suss does not have.
|
|
88
|
+
- **A Spanner database's `ddl`** statements declare the tables, and reading SQL out of a Terraform attribute is a job for the SQL readers, outside this pack.
|
|
89
|
+
- **A Firestore database in Datastore mode** uses a different API from Firestore's, so the entry's check turns it away instead of reading it as something it may not be.
|
|
90
90
|
|
|
91
91
|
## How the identity is built
|
|
92
92
|
|
|
93
|
-
Cloud Monitoring puts every metric a project defines for itself under `logging.googleapis.com/user/`, and the alert
|
|
93
|
+
Cloud Monitoring puts every metric a project defines for itself under `logging.googleapis.com/user/`, and the alert writes out that whole string. So the whole string is the identity both sides share. A name built at deploy time keeps its hole: `name = "${var.environment}-refusals"` becomes `logging.googleapis.com/user/{var.environment}-refusals`, and a filter that interpolates the same variable comes out the same way.
|
|
94
94
|
|
|
95
95
|
## Where it fits in suss
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
The pack depends on `@suss/contract-terraform` for the type of an entry, and on `@suss/behavioral-ir` for the terms a translation table may use. Neither the reader nor the checker knows anything about Google. Google's vocabulary appears only in the entries here.
|
|
98
98
|
|
|
99
99
|
## More
|
|
100
100
|
|
|
101
|
-
- [
|
|
101
|
+
- [Why each entry reads what it reads](./DESIGN.md), the provider versions it was written against, and the pages it came from
|
package/dist/index.cjs
CHANGED
|
@@ -90,8 +90,8 @@ function googleTerraform() {
|
|
|
90
90
|
boundary: {
|
|
91
91
|
kind: "storage",
|
|
92
92
|
storageSystem: "gcs",
|
|
93
|
-
//
|
|
94
|
-
//
|
|
93
|
+
// Code passes the same name to `bucket()`, so both sides use
|
|
94
|
+
// it as the identity.
|
|
95
95
|
nameAttribute: "name",
|
|
96
96
|
// An object has no fields to compare a read against.
|
|
97
97
|
fieldSet: "none"
|
|
@@ -117,8 +117,9 @@ function googleTerraform() {
|
|
|
117
117
|
storageSystem: BIGQUERY,
|
|
118
118
|
nameAttribute: "table_id",
|
|
119
119
|
scopeAttribute: "dataset_id",
|
|
120
|
-
// A schema written in the configuration
|
|
121
|
-
//
|
|
120
|
+
// A schema written in the configuration lists every column. A
|
|
121
|
+
// schema from a file or a variable is out of sight, so `none` is
|
|
122
|
+
// the fallback when fieldsFromJson finds nothing.
|
|
122
123
|
fieldSet: "none",
|
|
123
124
|
fieldsFromJson: {
|
|
124
125
|
attribute: "schema",
|
|
@@ -143,8 +144,8 @@ function googleTerraform() {
|
|
|
143
144
|
{
|
|
144
145
|
resource: "google_firestore_database",
|
|
145
146
|
providerVersions: CURRENT,
|
|
146
|
-
// A database in Datastore mode
|
|
147
|
-
//
|
|
147
|
+
// A database in Datastore mode uses a different API, so this
|
|
148
|
+
// entry does not describe it.
|
|
148
149
|
appliesWhen: { attribute: "type", equals: ["FIRESTORE_NATIVE"] },
|
|
149
150
|
boundary: {
|
|
150
151
|
kind: "storage",
|
|
@@ -161,8 +162,8 @@ function googleTerraform() {
|
|
|
161
162
|
boundary: {
|
|
162
163
|
kind: "storage",
|
|
163
164
|
storageSystem: "gcp.bigtable",
|
|
164
|
-
//
|
|
165
|
-
//
|
|
165
|
+
// Code passes the table id to `instance.table()`, so the
|
|
166
|
+
// declared name matches the accessed one.
|
|
166
167
|
nameAttribute: "name",
|
|
167
168
|
// Column families are not the fields of a row.
|
|
168
169
|
fieldSet: "none"
|
|
@@ -209,7 +210,7 @@ function googleTerraform() {
|
|
|
209
210
|
storageSystem: "redis",
|
|
210
211
|
// Code addresses key namespaces, which no attribute of the
|
|
211
212
|
// instance lists, so it declares the store and claims no
|
|
212
|
-
// access. The README
|
|
213
|
+
// access. The README explains why.
|
|
213
214
|
declares: "store",
|
|
214
215
|
fieldSet: "none"
|
|
215
216
|
}
|
|
@@ -221,8 +222,8 @@ function googleTerraform() {
|
|
|
221
222
|
kind: "metric",
|
|
222
223
|
metricSystem: METRIC_SYSTEM,
|
|
223
224
|
// Cloud Monitoring puts every metric a project defines for
|
|
224
|
-
// itself under this prefix, and an alert policy
|
|
225
|
-
// whole string, so the
|
|
225
|
+
// itself under this prefix, and an alert policy writes the
|
|
226
|
+
// whole string, so the identity is the whole string.
|
|
226
227
|
metricTypeTemplate: "logging.googleapis.com/user/{name}",
|
|
227
228
|
values: {
|
|
228
229
|
attribute: "metric_descriptor.value_type",
|
|
@@ -266,7 +267,7 @@ function googleTerraform() {
|
|
|
266
267
|
boundary: {
|
|
267
268
|
kind: "deployable",
|
|
268
269
|
// A second-generation function is deployed as a Cloud Run
|
|
269
|
-
// service, so it
|
|
270
|
+
// service, so it uses the same deployment target as one.
|
|
270
271
|
deploymentTarget: "container",
|
|
271
272
|
runtimeAttribute: "build_config.runtime",
|
|
272
273
|
env: [
|
|
@@ -278,8 +279,8 @@ function googleTerraform() {
|
|
|
278
279
|
secretAttribute: "secret"
|
|
279
280
|
}
|
|
280
281
|
],
|
|
281
|
-
// The entry point is an exported name and
|
|
282
|
-
//
|
|
282
|
+
// The entry point is an exported name and does not give the
|
|
283
|
+
// file it is in.
|
|
283
284
|
code: {
|
|
284
285
|
handler: {
|
|
285
286
|
attribute: "build_config.entry_point",
|
package/dist/index.d.cts
CHANGED
|
@@ -4,16 +4,15 @@ import { TerraformPack } from '@suss/contract-terraform';
|
|
|
4
4
|
* What Google Cloud's Terraform provider declares, as far as suss reads
|
|
5
5
|
* it.
|
|
6
6
|
*
|
|
7
|
-
* A log-based metric is a boundary
|
|
8
|
-
* measurements, and an alert policy
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* metric resource.
|
|
7
|
+
* A log-based metric is a boundary. The resource declares a series of
|
|
8
|
+
* measurements, and an alert policy reads it back by the type string
|
|
9
|
+
* Cloud Monitoring gives it, whether the policy writes that string out
|
|
10
|
+
* or builds it from a reference to the metric resource.
|
|
12
11
|
*
|
|
13
|
-
* Google's
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
12
|
+
* Google's own terms appear only in this file. Each entry gives the
|
|
13
|
+
* attribute that contains a Google value and what that value means in
|
|
14
|
+
* suss's terms, so `checkMetric` in `@suss/checker` can judge a pair
|
|
15
|
+
* without loading a pack.
|
|
17
16
|
*/
|
|
18
17
|
|
|
19
18
|
declare function googleTerraform(): TerraformPack;
|
package/dist/index.d.ts
CHANGED
|
@@ -4,16 +4,15 @@ import { TerraformPack } from '@suss/contract-terraform';
|
|
|
4
4
|
* What Google Cloud's Terraform provider declares, as far as suss reads
|
|
5
5
|
* it.
|
|
6
6
|
*
|
|
7
|
-
* A log-based metric is a boundary
|
|
8
|
-
* measurements, and an alert policy
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* metric resource.
|
|
7
|
+
* A log-based metric is a boundary. The resource declares a series of
|
|
8
|
+
* measurements, and an alert policy reads it back by the type string
|
|
9
|
+
* Cloud Monitoring gives it, whether the policy writes that string out
|
|
10
|
+
* or builds it from a reference to the metric resource.
|
|
12
11
|
*
|
|
13
|
-
* Google's
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
12
|
+
* Google's own terms appear only in this file. Each entry gives the
|
|
13
|
+
* attribute that contains a Google value and what that value means in
|
|
14
|
+
* suss's terms, so `checkMetric` in `@suss/checker` can judge a pair
|
|
15
|
+
* without loading a pack.
|
|
17
16
|
*/
|
|
18
17
|
|
|
19
18
|
declare function googleTerraform(): TerraformPack;
|
package/dist/index.js
CHANGED
|
@@ -65,8 +65,8 @@ function googleTerraform() {
|
|
|
65
65
|
boundary: {
|
|
66
66
|
kind: "storage",
|
|
67
67
|
storageSystem: "gcs",
|
|
68
|
-
//
|
|
69
|
-
//
|
|
68
|
+
// Code passes the same name to `bucket()`, so both sides use
|
|
69
|
+
// it as the identity.
|
|
70
70
|
nameAttribute: "name",
|
|
71
71
|
// An object has no fields to compare a read against.
|
|
72
72
|
fieldSet: "none"
|
|
@@ -92,8 +92,9 @@ function googleTerraform() {
|
|
|
92
92
|
storageSystem: BIGQUERY,
|
|
93
93
|
nameAttribute: "table_id",
|
|
94
94
|
scopeAttribute: "dataset_id",
|
|
95
|
-
// A schema written in the configuration
|
|
96
|
-
//
|
|
95
|
+
// A schema written in the configuration lists every column. A
|
|
96
|
+
// schema from a file or a variable is out of sight, so `none` is
|
|
97
|
+
// the fallback when fieldsFromJson finds nothing.
|
|
97
98
|
fieldSet: "none",
|
|
98
99
|
fieldsFromJson: {
|
|
99
100
|
attribute: "schema",
|
|
@@ -118,8 +119,8 @@ function googleTerraform() {
|
|
|
118
119
|
{
|
|
119
120
|
resource: "google_firestore_database",
|
|
120
121
|
providerVersions: CURRENT,
|
|
121
|
-
// A database in Datastore mode
|
|
122
|
-
//
|
|
122
|
+
// A database in Datastore mode uses a different API, so this
|
|
123
|
+
// entry does not describe it.
|
|
123
124
|
appliesWhen: { attribute: "type", equals: ["FIRESTORE_NATIVE"] },
|
|
124
125
|
boundary: {
|
|
125
126
|
kind: "storage",
|
|
@@ -136,8 +137,8 @@ function googleTerraform() {
|
|
|
136
137
|
boundary: {
|
|
137
138
|
kind: "storage",
|
|
138
139
|
storageSystem: "gcp.bigtable",
|
|
139
|
-
//
|
|
140
|
-
//
|
|
140
|
+
// Code passes the table id to `instance.table()`, so the
|
|
141
|
+
// declared name matches the accessed one.
|
|
141
142
|
nameAttribute: "name",
|
|
142
143
|
// Column families are not the fields of a row.
|
|
143
144
|
fieldSet: "none"
|
|
@@ -184,7 +185,7 @@ function googleTerraform() {
|
|
|
184
185
|
storageSystem: "redis",
|
|
185
186
|
// Code addresses key namespaces, which no attribute of the
|
|
186
187
|
// instance lists, so it declares the store and claims no
|
|
187
|
-
// access. The README
|
|
188
|
+
// access. The README explains why.
|
|
188
189
|
declares: "store",
|
|
189
190
|
fieldSet: "none"
|
|
190
191
|
}
|
|
@@ -196,8 +197,8 @@ function googleTerraform() {
|
|
|
196
197
|
kind: "metric",
|
|
197
198
|
metricSystem: METRIC_SYSTEM,
|
|
198
199
|
// Cloud Monitoring puts every metric a project defines for
|
|
199
|
-
// itself under this prefix, and an alert policy
|
|
200
|
-
// whole string, so the
|
|
200
|
+
// itself under this prefix, and an alert policy writes the
|
|
201
|
+
// whole string, so the identity is the whole string.
|
|
201
202
|
metricTypeTemplate: "logging.googleapis.com/user/{name}",
|
|
202
203
|
values: {
|
|
203
204
|
attribute: "metric_descriptor.value_type",
|
|
@@ -241,7 +242,7 @@ function googleTerraform() {
|
|
|
241
242
|
boundary: {
|
|
242
243
|
kind: "deployable",
|
|
243
244
|
// A second-generation function is deployed as a Cloud Run
|
|
244
|
-
// service, so it
|
|
245
|
+
// service, so it uses the same deployment target as one.
|
|
245
246
|
deploymentTarget: "container",
|
|
246
247
|
runtimeAttribute: "build_config.runtime",
|
|
247
248
|
env: [
|
|
@@ -253,8 +254,8 @@ function googleTerraform() {
|
|
|
253
254
|
secretAttribute: "secret"
|
|
254
255
|
}
|
|
255
256
|
],
|
|
256
|
-
// The entry point is an exported name and
|
|
257
|
-
//
|
|
257
|
+
// The entry point is an exported name and does not give the
|
|
258
|
+
// file it is in.
|
|
258
259
|
code: {
|
|
259
260
|
handler: {
|
|
260
261
|
attribute: "build_config.entry_point",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suss/terraform-gcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "What the Google Cloud Terraform provider declares, so suss can check your code against the infrastructure you deploy.",
|
|
6
6
|
"keywords": [
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
],
|
|
15
15
|
"license": "Apache-2.0",
|
|
16
16
|
"author": "Nimbus Cloud AI LLC",
|
|
17
|
-
"homepage": "https://
|
|
17
|
+
"homepage": "https://suss.sh",
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
20
20
|
"url": "git+https://github.com/nimbuscloud-ai/suss.git",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"typecheck": "tsc --noEmit"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@suss/behavioral-ir": "0.
|
|
51
|
-
"@suss/contract-terraform": "0.
|
|
50
|
+
"@suss/behavioral-ir": "0.34.0",
|
|
51
|
+
"@suss/contract-terraform": "0.34.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@suss/checker": "*",
|