@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.
- package/dist/integrity.json +12 -8
- package/dist/manifest.json +1 -1
- package/dist/meta.json +18141 -0
- package/dist/rules/schema-registry.ts +91 -0
- package/dist/rules/wgc101.ts +1 -1
- package/dist/rules/wgc401.ts +59 -0
- package/dist/rules/wgc402.ts +54 -0
- package/dist/rules/wgc403.ts +84 -0
- package/dist/skills/{chant-gke.md → chant-gcp-gke.md} +1 -1
- package/dist/skills/chant-gcp-patterns.md +3 -2
- package/dist/skills/chant-gcp-security.md +3 -2
- package/dist/skills/chant-gcp.md +363 -28
- package/package.json +20 -2
- package/src/codegen/docs.test.ts +16 -0
- package/src/codegen/generate.test.ts +18 -0
- package/src/codegen/generate.ts +11 -0
- package/src/codegen/package.test.ts +16 -0
- package/src/composites/cloud-function.ts +23 -15
- package/src/composites/cloud-run-service.ts +20 -13
- package/src/composites/cloud-sql-instance.ts +18 -14
- package/src/composites/composites.test.ts +94 -62
- package/src/composites/gcs-bucket.ts +13 -9
- package/src/composites/gke-cluster.ts +91 -16
- package/src/composites/index.ts +11 -11
- package/src/composites/managed-certificate.ts +19 -15
- package/src/composites/private-service.ts +23 -15
- package/src/composites/pubsub-pipeline.ts +30 -18
- package/src/composites/secure-project.ts +42 -27
- package/src/composites/vpc-network.ts +42 -35
- package/src/generated/lexicon-gcp.json +18141 -0
- package/src/import/import-fixtures.test.ts +98 -0
- package/src/index.ts +11 -11
- package/src/lint/post-synth/gcp-helpers.test.ts +166 -0
- package/src/lint/post-synth/post-synth.test.ts +132 -1
- package/src/lint/post-synth/schema-registry.ts +91 -0
- package/src/lint/post-synth/wgc101.test.ts +40 -0
- package/src/lint/post-synth/wgc101.ts +1 -1
- package/src/lint/post-synth/wgc102.test.ts +38 -0
- package/src/lint/post-synth/wgc103.test.ts +38 -0
- package/src/lint/post-synth/wgc104.test.ts +37 -0
- package/src/lint/post-synth/wgc105.test.ts +46 -0
- package/src/lint/post-synth/wgc106.test.ts +38 -0
- package/src/lint/post-synth/wgc107.test.ts +38 -0
- package/src/lint/post-synth/wgc108.test.ts +42 -0
- package/src/lint/post-synth/wgc109.test.ts +46 -0
- package/src/lint/post-synth/wgc110.test.ts +37 -0
- package/src/lint/post-synth/wgc111.test.ts +46 -0
- package/src/lint/post-synth/wgc112.test.ts +48 -0
- package/src/lint/post-synth/wgc113.test.ts +36 -0
- package/src/lint/post-synth/wgc201.test.ts +38 -0
- package/src/lint/post-synth/wgc202.test.ts +38 -0
- package/src/lint/post-synth/wgc203.test.ts +45 -0
- package/src/lint/post-synth/wgc204.test.ts +42 -0
- package/src/lint/post-synth/wgc301.test.ts +39 -0
- package/src/lint/post-synth/wgc302.test.ts +36 -0
- package/src/lint/post-synth/wgc303.test.ts +37 -0
- package/src/lint/post-synth/wgc401.test.ts +46 -0
- package/src/lint/post-synth/wgc401.ts +59 -0
- package/src/lint/post-synth/wgc402.test.ts +40 -0
- package/src/lint/post-synth/wgc402.ts +54 -0
- package/src/lint/post-synth/wgc403.test.ts +59 -0
- package/src/lint/post-synth/wgc403.ts +84 -0
- package/src/plugin.test.ts +4 -1
- package/src/plugin.ts +258 -177
- package/src/skills/{chant-gke.md → chant-gcp-gke.md} +1 -1
- package/src/skills/chant-gcp-patterns.md +3 -2
- package/src/skills/chant-gcp-security.md +3 -2
- 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
|
+
});
|