@suss/terraform-gcp 0.33.1 → 0.34.1

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 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 says where the two disagree.
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
- Says what Google Cloud's Terraform provider declares, for `@suss/contract-terraform` to read.
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, and nothing but entries. Each one says what a resource is, and what its own words mean in the terms suss compares boundaries in.
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: 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 below with no pack loaded.
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: `@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: 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 `@suss/terraform-aws` DESIGN walks 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.
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 one 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 pair with nothing yet, because no code pack records a publish or a subscribe. [What each entry decided](./DESIGN.md) says how each of those is read.
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
- ## The pair the provider refuses
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, and the apply fails minutes in: a distribution has no single value to compare, and Cloud Monitoring wants an aligner such as `ALIGN_PERCENTILE_95` to reduce each window to one number first.
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 say that `value_type = "DISTRIBUTION"` means the measurements are a histogram, that a `threshold_value` means the condition compares against a single number, and that the four percentile aligners are the ones that reduce a window to a number. `checkMetric` puts those together and reports the pair as a `boundaryShapeMismatch` at error severity, naming `aggregations.per_series_aligner` and the four values that would fix it.
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 states one of the percentile aligners is left alone, as is a condition on a metric declared as `INT64` or `DOUBLE`.
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** says nothing. Most alerts watch metrics the platform publishes, and a metric declared in a module this run did not read looks the same from here. The pairing pass reports a boundary with one side missing.
82
- - **A condition that states no `metric.type`** leaves the condition with no metric type on it, so it pairs with nothing rather than pairing with the wrong thing. An SLO burn-rate condition is written as a call rather than a comparison, and it is about an objective rather than a metric, so it lands here.
83
- - **A metric the platform publishes**, `run.googleapis.com/request_latencies` and everything like it, states its value type in Google's documentation rather than in any configuration. Judging a condition on one of those needs a catalog this does not ship.
84
- - **A `BOOL`, `STRING`, or `MONEY` metric** is left out of the value-type table, because none of suss's words describe one, and a metric this pack says nothing about is compared against nothing.
85
- - **`for_each` and `count`** state 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, states no engine of its own. Which store it is lives on the instance its `instance` attribute points at, and an entry has no way to read an attribute through a reference to another resource, so the database goes unread and the instance is what declares the store.
87
- - **`google_monitoring_uptime_check_config`** is a probe rather than a reading: 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 a synthetic check, which suss does not have.
88
- - **A Spanner database's `ddl`** statements state the tables, and reading SQL out of a Terraform attribute is a job for the SQL readers rather than for this pack.
89
- - **A Firestore database in Datastore mode** speaks a different API from the Firestore one, so the entry's gate turns it down rather than reading it as something it may not be.
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 spells that whole string, so the whole string is the identity the two 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 is spelled the same way.
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
- Depends on `@suss/contract-terraform` for the shape of an entry and on `@suss/behavioral-ir` for the words a translation table is allowed to use. The reader knows nothing about Google, and neither does the checker: Google's vocabulary starts and stops in the entries here.
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
- - [What each entry decided](./DESIGN.md), the provider versions it was written against, and the pages it came from
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
- // The name is what code passes to `bucket()`, so it is the
94
- // identity both sides spell.
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 is every column the
121
- // table has; one a file or a variable supplies says nothing.
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 speaks a different API, so it is
147
- // not the store this entry describes.
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
- // A table id is what code passes to `instance.table()`, so
165
- // the declared name and the accessed name meet.
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 says how the sides meet.
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 spells the
225
- // whole string, so the whole string is the shared identity.
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 runs on the same medium as one.
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 says nothing about
282
- // which file it is in.
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: the resource declares a series of
8
- * measurements, and an alert policy elsewhere reads it back by the type
9
- * string Cloud Monitoring gives it. That string is what the two share,
10
- * whether the policy writes it out or builds it from a reference to the
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 vocabulary starts and stops in this file. Each entry says
14
- * which attribute a resource writes which of Google's words in, and
15
- * what they mean in the terms suss compares boundaries in, so
16
- * `checkMetric` in `@suss/checker` judges a pair with no pack loaded.
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: the resource declares a series of
8
- * measurements, and an alert policy elsewhere reads it back by the type
9
- * string Cloud Monitoring gives it. That string is what the two share,
10
- * whether the policy writes it out or builds it from a reference to the
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 vocabulary starts and stops in this file. Each entry says
14
- * which attribute a resource writes which of Google's words in, and
15
- * what they mean in the terms suss compares boundaries in, so
16
- * `checkMetric` in `@suss/checker` judges a pair with no pack loaded.
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
- // The name is what code passes to `bucket()`, so it is the
69
- // identity both sides spell.
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 is every column the
96
- // table has; one a file or a variable supplies says nothing.
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 speaks a different API, so it is
122
- // not the store this entry describes.
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
- // A table id is what code passes to `instance.table()`, so
140
- // the declared name and the accessed name meet.
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 says how the sides meet.
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 spells the
200
- // whole string, so the whole string is the shared identity.
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 runs on the same medium as one.
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 says nothing about
257
- // which file it is in.
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.33.1",
3
+ "version": "0.34.1",
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://github.com/nimbuscloud-ai/suss/tree/main/packages/terraform/gcp#readme",
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.33.1",
51
- "@suss/contract-terraform": "0.33.1"
50
+ "@suss/behavioral-ir": "0.34.1",
51
+ "@suss/contract-terraform": "0.34.1"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@suss/checker": "*",