@intentius/chant-lexicon-gcp 0.0.18 → 0.0.24

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 (68) hide show
  1. package/dist/integrity.json +12 -8
  2. package/dist/manifest.json +1 -1
  3. package/dist/meta.json +18141 -0
  4. package/dist/rules/schema-registry.ts +91 -0
  5. package/dist/rules/wgc101.ts +1 -1
  6. package/dist/rules/wgc401.ts +59 -0
  7. package/dist/rules/wgc402.ts +54 -0
  8. package/dist/rules/wgc403.ts +84 -0
  9. package/dist/skills/{chant-gke.md → chant-gcp-gke.md} +1 -1
  10. package/dist/skills/chant-gcp-patterns.md +3 -2
  11. package/dist/skills/chant-gcp-security.md +3 -2
  12. package/dist/skills/chant-gcp.md +363 -28
  13. package/package.json +20 -2
  14. package/src/codegen/docs.test.ts +16 -0
  15. package/src/codegen/generate.test.ts +18 -0
  16. package/src/codegen/generate.ts +11 -0
  17. package/src/codegen/package.test.ts +16 -0
  18. package/src/composites/cloud-function.ts +23 -15
  19. package/src/composites/cloud-run-service.ts +20 -13
  20. package/src/composites/cloud-sql-instance.ts +18 -14
  21. package/src/composites/composites.test.ts +94 -62
  22. package/src/composites/gcs-bucket.ts +13 -9
  23. package/src/composites/gke-cluster.ts +91 -16
  24. package/src/composites/index.ts +11 -11
  25. package/src/composites/managed-certificate.ts +19 -15
  26. package/src/composites/private-service.ts +23 -15
  27. package/src/composites/pubsub-pipeline.ts +30 -18
  28. package/src/composites/secure-project.ts +42 -27
  29. package/src/composites/vpc-network.ts +42 -35
  30. package/src/generated/lexicon-gcp.json +18141 -0
  31. package/src/import/import-fixtures.test.ts +98 -0
  32. package/src/index.ts +11 -11
  33. package/src/lint/post-synth/gcp-helpers.test.ts +166 -0
  34. package/src/lint/post-synth/post-synth.test.ts +132 -1
  35. package/src/lint/post-synth/schema-registry.ts +91 -0
  36. package/src/lint/post-synth/wgc101.test.ts +40 -0
  37. package/src/lint/post-synth/wgc101.ts +1 -1
  38. package/src/lint/post-synth/wgc102.test.ts +38 -0
  39. package/src/lint/post-synth/wgc103.test.ts +38 -0
  40. package/src/lint/post-synth/wgc104.test.ts +37 -0
  41. package/src/lint/post-synth/wgc105.test.ts +46 -0
  42. package/src/lint/post-synth/wgc106.test.ts +38 -0
  43. package/src/lint/post-synth/wgc107.test.ts +38 -0
  44. package/src/lint/post-synth/wgc108.test.ts +42 -0
  45. package/src/lint/post-synth/wgc109.test.ts +46 -0
  46. package/src/lint/post-synth/wgc110.test.ts +37 -0
  47. package/src/lint/post-synth/wgc111.test.ts +46 -0
  48. package/src/lint/post-synth/wgc112.test.ts +48 -0
  49. package/src/lint/post-synth/wgc113.test.ts +36 -0
  50. package/src/lint/post-synth/wgc201.test.ts +38 -0
  51. package/src/lint/post-synth/wgc202.test.ts +38 -0
  52. package/src/lint/post-synth/wgc203.test.ts +45 -0
  53. package/src/lint/post-synth/wgc204.test.ts +42 -0
  54. package/src/lint/post-synth/wgc301.test.ts +39 -0
  55. package/src/lint/post-synth/wgc302.test.ts +36 -0
  56. package/src/lint/post-synth/wgc303.test.ts +37 -0
  57. package/src/lint/post-synth/wgc401.test.ts +46 -0
  58. package/src/lint/post-synth/wgc401.ts +59 -0
  59. package/src/lint/post-synth/wgc402.test.ts +40 -0
  60. package/src/lint/post-synth/wgc402.ts +54 -0
  61. package/src/lint/post-synth/wgc403.test.ts +59 -0
  62. package/src/lint/post-synth/wgc403.ts +84 -0
  63. package/src/plugin.test.ts +4 -1
  64. package/src/plugin.ts +258 -177
  65. package/src/skills/{chant-gke.md → chant-gcp-gke.md} +1 -1
  66. package/src/skills/chant-gcp-patterns.md +3 -2
  67. package/src/skills/chant-gcp-security.md +3 -2
  68. package/src/skills/chant-gcp.md +363 -28
@@ -0,0 +1,46 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc105 } from "./wgc105";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC105: public Cloud SQL", () => {
11
+ test("flags SQLInstance with 0.0.0.0/0 in authorizedNetworks", () => {
12
+ const yaml = `apiVersion: sql.cnrm.cloud.google.com/v1beta1
13
+ kind: SQLInstance
14
+ metadata:
15
+ name: my-db
16
+ spec:
17
+ databaseVersion: POSTGRES_15
18
+ settings:
19
+ ipConfiguration:
20
+ authorizedNetworks:
21
+ - value: "0.0.0.0/0"
22
+ name: public
23
+ `;
24
+ const diags = wgc105.check(makeCtx(yaml));
25
+ expect(diags.length).toBeGreaterThanOrEqual(1);
26
+ expect(diags[0].checkId).toBe("WGC105");
27
+ expect(diags[0].severity).toBe("warning");
28
+ });
29
+
30
+ test("no diagnostic with private networks only", () => {
31
+ const yaml = `apiVersion: sql.cnrm.cloud.google.com/v1beta1
32
+ kind: SQLInstance
33
+ metadata:
34
+ name: my-db
35
+ spec:
36
+ databaseVersion: POSTGRES_15
37
+ settings:
38
+ ipConfiguration:
39
+ authorizedNetworks:
40
+ - value: "10.0.0.0/8"
41
+ name: internal
42
+ `;
43
+ const diags = wgc105.check(makeCtx(yaml));
44
+ expect(diags).toHaveLength(0);
45
+ });
46
+ });
@@ -0,0 +1,38 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc106 } from "./wgc106";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC106: missing deletion policy", () => {
11
+ test("flags resource without deletion policy annotation", () => {
12
+ const yaml = `apiVersion: storage.cnrm.cloud.google.com/v1beta1
13
+ kind: StorageBucket
14
+ metadata:
15
+ name: my-bucket
16
+ spec:
17
+ location: US
18
+ `;
19
+ const diags = wgc106.check(makeCtx(yaml));
20
+ expect(diags.length).toBeGreaterThanOrEqual(1);
21
+ expect(diags[0].checkId).toBe("WGC106");
22
+ expect(diags[0].severity).toBe("info");
23
+ });
24
+
25
+ test("no diagnostic when deletion policy present", () => {
26
+ const yaml = `apiVersion: storage.cnrm.cloud.google.com/v1beta1
27
+ kind: StorageBucket
28
+ metadata:
29
+ name: my-bucket
30
+ annotations:
31
+ cnrm.cloud.google.com/deletion-policy: abandon
32
+ spec:
33
+ location: US
34
+ `;
35
+ const diags = wgc106.check(makeCtx(yaml));
36
+ expect(diags).toHaveLength(0);
37
+ });
38
+ });
@@ -0,0 +1,38 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc107 } from "./wgc107";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC107: missing versioning", () => {
11
+ test("flags StorageBucket without versioning", () => {
12
+ const yaml = `apiVersion: storage.cnrm.cloud.google.com/v1beta1
13
+ kind: StorageBucket
14
+ metadata:
15
+ name: my-bucket
16
+ spec:
17
+ location: US
18
+ `;
19
+ const diags = wgc107.check(makeCtx(yaml));
20
+ expect(diags.length).toBeGreaterThanOrEqual(1);
21
+ expect(diags[0].checkId).toBe("WGC107");
22
+ expect(diags[0].severity).toBe("info");
23
+ });
24
+
25
+ test("no diagnostic when versioning enabled", () => {
26
+ const yaml = `apiVersion: storage.cnrm.cloud.google.com/v1beta1
27
+ kind: StorageBucket
28
+ metadata:
29
+ name: my-bucket
30
+ spec:
31
+ location: US
32
+ versioning:
33
+ enabled: true
34
+ `;
35
+ const diags = wgc107.check(makeCtx(yaml));
36
+ expect(diags).toHaveLength(0);
37
+ });
38
+ });
@@ -0,0 +1,42 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc108 } from "./wgc108";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC108: missing backup configuration", () => {
11
+ test("flags SQLInstance without backup", () => {
12
+ const yaml = `apiVersion: sql.cnrm.cloud.google.com/v1beta1
13
+ kind: SQLInstance
14
+ metadata:
15
+ name: my-db
16
+ spec:
17
+ databaseVersion: POSTGRES_15
18
+ settings:
19
+ tier: db-f1-micro
20
+ `;
21
+ const diags = wgc108.check(makeCtx(yaml));
22
+ expect(diags.length).toBeGreaterThanOrEqual(1);
23
+ expect(diags[0].checkId).toBe("WGC108");
24
+ expect(diags[0].severity).toBe("warning");
25
+ });
26
+
27
+ test("no diagnostic when backup enabled", () => {
28
+ const yaml = `apiVersion: sql.cnrm.cloud.google.com/v1beta1
29
+ kind: SQLInstance
30
+ metadata:
31
+ name: my-db
32
+ spec:
33
+ databaseVersion: POSTGRES_15
34
+ settings:
35
+ tier: db-f1-micro
36
+ backupConfiguration:
37
+ enabled: true
38
+ `;
39
+ const diags = wgc108.check(makeCtx(yaml));
40
+ expect(diags).toHaveLength(0);
41
+ });
42
+ });
@@ -0,0 +1,46 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc109 } from "./wgc109";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC109: open firewall", () => {
11
+ test("flags ComputeFirewall with 0.0.0.0/0", () => {
12
+ const yaml = `apiVersion: compute.cnrm.cloud.google.com/v1beta1
13
+ kind: ComputeFirewall
14
+ metadata:
15
+ name: allow-all
16
+ spec:
17
+ sourceRanges:
18
+ - "0.0.0.0/0"
19
+ allowed:
20
+ - protocol: tcp
21
+ ports:
22
+ - "80"
23
+ `;
24
+ const diags = wgc109.check(makeCtx(yaml));
25
+ expect(diags.length).toBeGreaterThanOrEqual(1);
26
+ expect(diags[0].checkId).toBe("WGC109");
27
+ expect(diags[0].severity).toBe("warning");
28
+ });
29
+
30
+ test("no diagnostic with specific source range", () => {
31
+ const yaml = `apiVersion: compute.cnrm.cloud.google.com/v1beta1
32
+ kind: ComputeFirewall
33
+ metadata:
34
+ name: allow-internal
35
+ spec:
36
+ sourceRanges:
37
+ - "10.0.0.0/8"
38
+ allowed:
39
+ - protocol: tcp
40
+ ports:
41
+ - "80"
42
+ `;
43
+ const diags = wgc109.check(makeCtx(yaml));
44
+ expect(diags).toHaveLength(0);
45
+ });
46
+ });
@@ -0,0 +1,37 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc110 } from "./wgc110";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC110: missing key rotation", () => {
11
+ test("flags KMSCryptoKey without rotation period", () => {
12
+ const yaml = `apiVersion: kms.cnrm.cloud.google.com/v1beta1
13
+ kind: KMSCryptoKey
14
+ metadata:
15
+ name: my-key
16
+ spec:
17
+ purpose: ENCRYPT_DECRYPT
18
+ `;
19
+ const diags = wgc110.check(makeCtx(yaml));
20
+ expect(diags.length).toBeGreaterThanOrEqual(1);
21
+ expect(diags[0].checkId).toBe("WGC110");
22
+ expect(diags[0].severity).toBe("warning");
23
+ });
24
+
25
+ test("no diagnostic when rotation period set", () => {
26
+ const yaml = `apiVersion: kms.cnrm.cloud.google.com/v1beta1
27
+ kind: KMSCryptoKey
28
+ metadata:
29
+ name: my-key
30
+ spec:
31
+ purpose: ENCRYPT_DECRYPT
32
+ rotationPeriod: 7776000s
33
+ `;
34
+ const diags = wgc110.check(makeCtx(yaml));
35
+ expect(diags).toHaveLength(0);
36
+ });
37
+ });
@@ -0,0 +1,46 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc111 } from "./wgc111";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC111: dangling resource reference", () => {
11
+ test("flags resourceRef pointing to nonexistent name", () => {
12
+ const yaml = `apiVersion: container.cnrm.cloud.google.com/v1beta1
13
+ kind: ContainerNodePool
14
+ metadata:
15
+ name: my-pool
16
+ spec:
17
+ clusterRef:
18
+ name: nonexistent-cluster
19
+ `;
20
+ const diags = wgc111.check(makeCtx(yaml));
21
+ expect(diags.length).toBeGreaterThanOrEqual(1);
22
+ expect(diags[0].checkId).toBe("WGC111");
23
+ expect(diags[0].severity).toBe("warning");
24
+ });
25
+
26
+ test("no diagnostic when referenced resource exists", () => {
27
+ const yaml = `apiVersion: container.cnrm.cloud.google.com/v1beta1
28
+ kind: ContainerCluster
29
+ metadata:
30
+ name: my-cluster
31
+ spec:
32
+ location: us-central1
33
+ ---
34
+ apiVersion: container.cnrm.cloud.google.com/v1beta1
35
+ kind: ContainerNodePool
36
+ metadata:
37
+ name: my-pool
38
+ spec:
39
+ clusterRef:
40
+ name: my-cluster
41
+ `;
42
+ const diags = wgc111.check(makeCtx(yaml));
43
+ const poolDiags = diags.filter(d => d.entity === "my-pool");
44
+ expect(poolDiags).toHaveLength(0);
45
+ });
46
+ });
@@ -0,0 +1,48 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc112 } from "./wgc112";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC112: missing or invalid apiVersion", () => {
11
+ test("flags resource with missing apiVersion", () => {
12
+ const yaml = `kind: StorageBucket
13
+ metadata:
14
+ name: my-bucket
15
+ spec:
16
+ location: US
17
+ `;
18
+ const diags = wgc112.check(makeCtx(yaml));
19
+ expect(diags.length).toBeGreaterThanOrEqual(1);
20
+ expect(diags[0].checkId).toBe("WGC112");
21
+ expect(diags[0].severity).toBe("error");
22
+ });
23
+
24
+ test("flags resource with malformed apiVersion", () => {
25
+ const yaml = `apiVersion: not-a-valid-version
26
+ kind: StorageBucket
27
+ metadata:
28
+ name: my-bucket
29
+ spec:
30
+ location: US
31
+ `;
32
+ const diags = wgc112.check(makeCtx(yaml));
33
+ expect(diags.length).toBeGreaterThanOrEqual(1);
34
+ expect(diags[0].checkId).toBe("WGC112");
35
+ });
36
+
37
+ test("no diagnostic with valid apiVersion", () => {
38
+ const yaml = `apiVersion: storage.cnrm.cloud.google.com/v1beta1
39
+ kind: StorageBucket
40
+ metadata:
41
+ name: my-bucket
42
+ spec:
43
+ location: US
44
+ `;
45
+ const diags = wgc112.check(makeCtx(yaml));
46
+ expect(diags).toHaveLength(0);
47
+ });
48
+ });
@@ -0,0 +1,36 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc113 } from "./wgc113";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC113: alpha API version", () => {
11
+ test("flags resource with v1alpha1 apiVersion", () => {
12
+ const yaml = `apiVersion: compute.cnrm.cloud.google.com/v1alpha1
13
+ kind: ComputeInstance
14
+ metadata:
15
+ name: my-vm
16
+ spec:
17
+ machineType: e2-medium
18
+ `;
19
+ const diags = wgc113.check(makeCtx(yaml));
20
+ expect(diags.length).toBeGreaterThanOrEqual(1);
21
+ expect(diags[0].checkId).toBe("WGC113");
22
+ expect(diags[0].severity).toBe("warning");
23
+ });
24
+
25
+ test("no diagnostic with v1beta1 apiVersion", () => {
26
+ const yaml = `apiVersion: compute.cnrm.cloud.google.com/v1beta1
27
+ kind: ComputeInstance
28
+ metadata:
29
+ name: my-vm
30
+ spec:
31
+ machineType: e2-medium
32
+ `;
33
+ const diags = wgc113.check(makeCtx(yaml));
34
+ expect(diags).toHaveLength(0);
35
+ });
36
+ });
@@ -0,0 +1,38 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc201 } from "./wgc201";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC201: missing managed-by label", () => {
11
+ test("flags resource without managed-by label", () => {
12
+ const yaml = `apiVersion: storage.cnrm.cloud.google.com/v1beta1
13
+ kind: StorageBucket
14
+ metadata:
15
+ name: my-bucket
16
+ spec:
17
+ location: US
18
+ `;
19
+ const diags = wgc201.check(makeCtx(yaml));
20
+ expect(diags.length).toBeGreaterThanOrEqual(1);
21
+ expect(diags[0].checkId).toBe("WGC201");
22
+ expect(diags[0].severity).toBe("info");
23
+ });
24
+
25
+ test("no diagnostic when managed-by label present", () => {
26
+ const yaml = `apiVersion: storage.cnrm.cloud.google.com/v1beta1
27
+ kind: StorageBucket
28
+ metadata:
29
+ name: my-bucket
30
+ labels:
31
+ app.kubernetes.io/managed-by: chant
32
+ spec:
33
+ location: US
34
+ `;
35
+ const diags = wgc201.check(makeCtx(yaml));
36
+ expect(diags).toHaveLength(0);
37
+ });
38
+ });
@@ -0,0 +1,38 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc202 } from "./wgc202";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC202: missing workload identity", () => {
11
+ test("flags ContainerCluster without workload identity", () => {
12
+ const yaml = `apiVersion: container.cnrm.cloud.google.com/v1beta1
13
+ kind: ContainerCluster
14
+ metadata:
15
+ name: my-cluster
16
+ spec:
17
+ location: us-central1
18
+ `;
19
+ const diags = wgc202.check(makeCtx(yaml));
20
+ expect(diags.length).toBeGreaterThanOrEqual(1);
21
+ expect(diags[0].checkId).toBe("WGC202");
22
+ expect(diags[0].severity).toBe("warning");
23
+ });
24
+
25
+ test("no diagnostic when workload identity configured", () => {
26
+ const yaml = `apiVersion: container.cnrm.cloud.google.com/v1beta1
27
+ kind: ContainerCluster
28
+ metadata:
29
+ name: my-cluster
30
+ spec:
31
+ location: us-central1
32
+ workloadIdentityConfig:
33
+ workloadPool: my-project.svc.id.goog
34
+ `;
35
+ const diags = wgc202.check(makeCtx(yaml));
36
+ expect(diags).toHaveLength(0);
37
+ });
38
+ });
@@ -0,0 +1,45 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc203 } from "./wgc203";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC203: cloud-platform OAuth scope", () => {
11
+ test("flags ContainerNodePool with cloud-platform scope", () => {
12
+ const yaml = `apiVersion: container.cnrm.cloud.google.com/v1beta1
13
+ kind: ContainerNodePool
14
+ metadata:
15
+ name: my-pool
16
+ spec:
17
+ clusterRef:
18
+ name: my-cluster
19
+ nodeConfig:
20
+ oauthScopes:
21
+ - "https://www.googleapis.com/auth/cloud-platform"
22
+ `;
23
+ const diags = wgc203.check(makeCtx(yaml));
24
+ expect(diags.length).toBeGreaterThanOrEqual(1);
25
+ expect(diags[0].checkId).toBe("WGC203");
26
+ expect(diags[0].severity).toBe("warning");
27
+ });
28
+
29
+ test("no diagnostic with specific scopes", () => {
30
+ const yaml = `apiVersion: container.cnrm.cloud.google.com/v1beta1
31
+ kind: ContainerNodePool
32
+ metadata:
33
+ name: my-pool
34
+ spec:
35
+ clusterRef:
36
+ name: my-cluster
37
+ nodeConfig:
38
+ oauthScopes:
39
+ - "https://www.googleapis.com/auth/logging.write"
40
+ - "https://www.googleapis.com/auth/monitoring"
41
+ `;
42
+ const diags = wgc203.check(makeCtx(yaml));
43
+ expect(diags).toHaveLength(0);
44
+ });
45
+ });
@@ -0,0 +1,42 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc204 } from "./wgc204";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC204: missing shielded VM config", () => {
11
+ test("flags ComputeInstance without shielded VM", () => {
12
+ const yaml = `apiVersion: compute.cnrm.cloud.google.com/v1beta1
13
+ kind: ComputeInstance
14
+ metadata:
15
+ name: my-vm
16
+ spec:
17
+ machineType: e2-medium
18
+ zone: us-central1-a
19
+ `;
20
+ const diags = wgc204.check(makeCtx(yaml));
21
+ expect(diags.length).toBeGreaterThanOrEqual(1);
22
+ expect(diags[0].checkId).toBe("WGC204");
23
+ expect(diags[0].severity).toBe("info");
24
+ });
25
+
26
+ test("no diagnostic when shielded VM configured", () => {
27
+ const yaml = `apiVersion: compute.cnrm.cloud.google.com/v1beta1
28
+ kind: ComputeInstance
29
+ metadata:
30
+ name: my-vm
31
+ spec:
32
+ machineType: e2-medium
33
+ zone: us-central1-a
34
+ shieldedInstanceConfig:
35
+ enableSecureBoot: true
36
+ enableVtpm: true
37
+ enableIntegrityMonitoring: true
38
+ `;
39
+ const diags = wgc204.check(makeCtx(yaml));
40
+ expect(diags).toHaveLength(0);
41
+ });
42
+ });
@@ -0,0 +1,39 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc301 } from "./wgc301";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC301: no audit logging", () => {
11
+ test("flags output without IAMAuditConfig", () => {
12
+ const yaml = `apiVersion: storage.cnrm.cloud.google.com/v1beta1
13
+ kind: StorageBucket
14
+ metadata:
15
+ name: my-bucket
16
+ spec:
17
+ location: US
18
+ `;
19
+ const diags = wgc301.check(makeCtx(yaml));
20
+ expect(diags.length).toBeGreaterThanOrEqual(1);
21
+ expect(diags[0].checkId).toBe("WGC301");
22
+ expect(diags[0].severity).toBe("info");
23
+ });
24
+
25
+ test("no diagnostic when IAMAuditConfig present", () => {
26
+ const yaml = `apiVersion: iam.cnrm.cloud.google.com/v1beta1
27
+ kind: IAMAuditConfig
28
+ metadata:
29
+ name: audit-config
30
+ spec:
31
+ service: allServices
32
+ auditLogConfigs:
33
+ - logType: ADMIN_READ
34
+ - logType: DATA_READ
35
+ `;
36
+ const diags = wgc301.check(makeCtx(yaml));
37
+ expect(diags).toHaveLength(0);
38
+ });
39
+ });
@@ -0,0 +1,36 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc302 } from "./wgc302";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC302: service API not enabled", () => {
11
+ test("flags output without Service resource", () => {
12
+ const yaml = `apiVersion: storage.cnrm.cloud.google.com/v1beta1
13
+ kind: StorageBucket
14
+ metadata:
15
+ name: my-bucket
16
+ spec:
17
+ location: US
18
+ `;
19
+ const diags = wgc302.check(makeCtx(yaml));
20
+ expect(diags.length).toBeGreaterThanOrEqual(1);
21
+ expect(diags[0].checkId).toBe("WGC302");
22
+ expect(diags[0].severity).toBe("info");
23
+ });
24
+
25
+ test("no diagnostic when Service resource present", () => {
26
+ const yaml = `apiVersion: serviceusage.cnrm.cloud.google.com/v1beta1
27
+ kind: Service
28
+ metadata:
29
+ name: compute-api
30
+ spec:
31
+ resourceID: compute.googleapis.com
32
+ `;
33
+ const diags = wgc302.check(makeCtx(yaml));
34
+ expect(diags).toHaveLength(0);
35
+ });
36
+ });
@@ -0,0 +1,37 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { wgc303 } from "./wgc303";
3
+
4
+ function makeCtx(yaml: string) {
5
+ return {
6
+ outputs: new Map([["gcp", yaml]]),
7
+ };
8
+ }
9
+
10
+ describe("WGC303: missing VPC Service Controls", () => {
11
+ test("flags output without service perimeter", () => {
12
+ const yaml = `apiVersion: storage.cnrm.cloud.google.com/v1beta1
13
+ kind: StorageBucket
14
+ metadata:
15
+ name: my-bucket
16
+ spec:
17
+ location: US
18
+ `;
19
+ const diags = wgc303.check(makeCtx(yaml));
20
+ expect(diags.length).toBeGreaterThanOrEqual(1);
21
+ expect(diags[0].checkId).toBe("WGC303");
22
+ expect(diags[0].severity).toBe("info");
23
+ });
24
+
25
+ test("no diagnostic when service perimeter present", () => {
26
+ const yaml = `apiVersion: accesscontextmanager.cnrm.cloud.google.com/v1beta1
27
+ kind: AccessContextManagerServicePerimeter
28
+ metadata:
29
+ name: my-perimeter
30
+ spec:
31
+ title: my-perimeter
32
+ perimeterType: PERIMETER_TYPE_REGULAR
33
+ `;
34
+ const diags = wgc303.check(makeCtx(yaml));
35
+ expect(diags).toHaveLength(0);
36
+ });
37
+ });