@intentius/chant-lexicon-gcp 0.0.15
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 +36 -0
- package/dist/manifest.json +12 -0
- package/dist/meta.json +10919 -0
- package/dist/rules/gcp-helpers.ts +117 -0
- package/dist/rules/hardcoded-project.ts +58 -0
- package/dist/rules/hardcoded-region.ts +56 -0
- package/dist/rules/public-iam.ts +43 -0
- package/dist/rules/wgc101.ts +56 -0
- package/dist/rules/wgc102.ts +35 -0
- package/dist/rules/wgc103.ts +45 -0
- package/dist/rules/wgc104.ts +42 -0
- package/dist/rules/wgc105.ts +46 -0
- package/dist/rules/wgc106.ts +36 -0
- package/dist/rules/wgc107.ts +39 -0
- package/dist/rules/wgc108.ts +41 -0
- package/dist/rules/wgc109.ts +39 -0
- package/dist/rules/wgc110.ts +38 -0
- package/dist/rules/wgc111.ts +54 -0
- package/dist/rules/wgc112.ts +56 -0
- package/dist/rules/wgc113.ts +42 -0
- package/dist/rules/wgc201.ts +36 -0
- package/dist/rules/wgc202.ts +39 -0
- package/dist/rules/wgc203.ts +44 -0
- package/dist/rules/wgc204.ts +39 -0
- package/dist/rules/wgc301.ts +34 -0
- package/dist/rules/wgc302.ts +34 -0
- package/dist/rules/wgc303.ts +37 -0
- package/dist/skills/chant-gcp-patterns.md +367 -0
- package/dist/skills/chant-gcp-security.md +276 -0
- package/dist/skills/chant-gcp.md +108 -0
- package/dist/types/index.d.ts +26529 -0
- package/package.json +35 -0
- package/src/actions/index.ts +52 -0
- package/src/codegen/docs-cli.ts +7 -0
- package/src/codegen/docs.ts +820 -0
- package/src/codegen/generate-cli.ts +24 -0
- package/src/codegen/generate.ts +252 -0
- package/src/codegen/naming.test.ts +49 -0
- package/src/codegen/naming.ts +132 -0
- package/src/codegen/package.ts +66 -0
- package/src/composites/cloud-function.ts +117 -0
- package/src/composites/cloud-run-service.ts +124 -0
- package/src/composites/cloud-sql-instance.ts +126 -0
- package/src/composites/composites.test.ts +432 -0
- package/src/composites/gcs-bucket.ts +111 -0
- package/src/composites/gke-cluster.ts +125 -0
- package/src/composites/index.ts +20 -0
- package/src/composites/managed-certificate.ts +79 -0
- package/src/composites/private-service.ts +95 -0
- package/src/composites/pubsub-pipeline.ts +102 -0
- package/src/composites/secure-project.ts +128 -0
- package/src/composites/vpc-network.ts +165 -0
- package/src/coverage.test.ts +27 -0
- package/src/coverage.ts +51 -0
- package/src/default-labels.test.ts +111 -0
- package/src/default-labels.ts +93 -0
- package/src/generated/index.d.ts +26529 -0
- package/src/generated/index.ts +1723 -0
- package/src/generated/lexicon-gcp.json +10919 -0
- package/src/generated/runtime.ts +4 -0
- package/src/import/generator.test.ts +125 -0
- package/src/import/generator.ts +82 -0
- package/src/import/parser.test.ts +167 -0
- package/src/import/parser.ts +80 -0
- package/src/import/roundtrip.test.ts +66 -0
- package/src/index.ts +54 -0
- package/src/lint/post-synth/gcp-helpers.ts +117 -0
- package/src/lint/post-synth/index.ts +20 -0
- package/src/lint/post-synth/post-synth.test.ts +693 -0
- package/src/lint/post-synth/wgc101.ts +56 -0
- package/src/lint/post-synth/wgc102.ts +35 -0
- package/src/lint/post-synth/wgc103.ts +45 -0
- package/src/lint/post-synth/wgc104.ts +42 -0
- package/src/lint/post-synth/wgc105.ts +46 -0
- package/src/lint/post-synth/wgc106.ts +36 -0
- package/src/lint/post-synth/wgc107.ts +39 -0
- package/src/lint/post-synth/wgc108.ts +41 -0
- package/src/lint/post-synth/wgc109.ts +39 -0
- package/src/lint/post-synth/wgc110.ts +38 -0
- package/src/lint/post-synth/wgc111.ts +54 -0
- package/src/lint/post-synth/wgc112.ts +56 -0
- package/src/lint/post-synth/wgc113.ts +42 -0
- package/src/lint/post-synth/wgc201.ts +36 -0
- package/src/lint/post-synth/wgc202.ts +39 -0
- package/src/lint/post-synth/wgc203.ts +44 -0
- package/src/lint/post-synth/wgc204.ts +39 -0
- package/src/lint/post-synth/wgc301.ts +34 -0
- package/src/lint/post-synth/wgc302.ts +34 -0
- package/src/lint/post-synth/wgc303.ts +37 -0
- package/src/lint/rules/hardcoded-project.ts +58 -0
- package/src/lint/rules/hardcoded-region.ts +56 -0
- package/src/lint/rules/index.ts +3 -0
- package/src/lint/rules/public-iam.ts +43 -0
- package/src/lint/rules/rules.test.ts +63 -0
- package/src/lsp/completions.test.ts +67 -0
- package/src/lsp/completions.ts +17 -0
- package/src/lsp/hover.test.ts +66 -0
- package/src/lsp/hover.ts +54 -0
- package/src/package-cli.ts +24 -0
- package/src/plugin.test.ts +250 -0
- package/src/plugin.ts +405 -0
- package/src/pseudo.test.ts +40 -0
- package/src/pseudo.ts +19 -0
- package/src/serializer.test.ts +250 -0
- package/src/serializer.ts +232 -0
- package/src/skills/chant-gcp-patterns.md +367 -0
- package/src/skills/chant-gcp-security.md +276 -0
- package/src/skills/chant-gcp.md +108 -0
- package/src/spec/fetch.test.ts +16 -0
- package/src/spec/fetch.ts +121 -0
- package/src/spec/parse.test.ts +163 -0
- package/src/spec/parse.ts +432 -0
- package/src/testdata/compute-instance.yaml +93 -0
- package/src/testdata/iam-policy-member.yaml +66 -0
- package/src/testdata/manifests/compute-instance.yaml +18 -0
- package/src/testdata/manifests/full-app.yaml +34 -0
- package/src/testdata/manifests/storage-bucket.yaml +12 -0
- package/src/testdata/storage-bucket.yaml +100 -0
- package/src/validate-cli.ts +13 -0
- package/src/validate.test.ts +38 -0
- package/src/validate.ts +30 -0
- package/src/variables.ts +15 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GcsBucket composite — StorageBucket with encryption, uniform access, and lifecycle.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface GcsBucketProps {
|
|
6
|
+
/** Bucket name. */
|
|
7
|
+
name: string;
|
|
8
|
+
/** GCS location (default: "US"). */
|
|
9
|
+
location?: string;
|
|
10
|
+
/** Storage class (default: "STANDARD"). */
|
|
11
|
+
storageClass?: "STANDARD" | "NEARLINE" | "COLDLINE" | "ARCHIVE";
|
|
12
|
+
/** Enable uniform bucket-level access (default: true). */
|
|
13
|
+
uniformBucketLevelAccess?: boolean;
|
|
14
|
+
/** Enable versioning (default: false). */
|
|
15
|
+
versioning?: boolean;
|
|
16
|
+
/** KMS key name for encryption. */
|
|
17
|
+
kmsKeyName?: string;
|
|
18
|
+
/** Lifecycle rule: delete objects older than N days. */
|
|
19
|
+
lifecycleDeleteAfterDays?: number;
|
|
20
|
+
/** Lifecycle rule: transition to Nearline after N days. */
|
|
21
|
+
lifecycleNearlineAfterDays?: number;
|
|
22
|
+
/** Additional labels. */
|
|
23
|
+
labels?: Record<string, string>;
|
|
24
|
+
/** Namespace for all resources. */
|
|
25
|
+
namespace?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface GcsBucketResult {
|
|
29
|
+
bucket: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Create a GcsBucket composite.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { GcsBucket } from "@intentius/chant-lexicon-gcp";
|
|
38
|
+
*
|
|
39
|
+
* const { bucket } = GcsBucket({
|
|
40
|
+
* name: "my-data-bucket",
|
|
41
|
+
* location: "US",
|
|
42
|
+
* versioning: true,
|
|
43
|
+
* lifecycleDeleteAfterDays: 365,
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export function GcsBucket(props: GcsBucketProps): GcsBucketResult {
|
|
48
|
+
const {
|
|
49
|
+
name,
|
|
50
|
+
location = "US",
|
|
51
|
+
storageClass = "STANDARD",
|
|
52
|
+
uniformBucketLevelAccess = true,
|
|
53
|
+
versioning = false,
|
|
54
|
+
kmsKeyName,
|
|
55
|
+
lifecycleDeleteAfterDays,
|
|
56
|
+
lifecycleNearlineAfterDays,
|
|
57
|
+
labels: extraLabels = {},
|
|
58
|
+
namespace,
|
|
59
|
+
} = props;
|
|
60
|
+
|
|
61
|
+
const commonLabels: Record<string, string> = {
|
|
62
|
+
"app.kubernetes.io/name": name,
|
|
63
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
64
|
+
...extraLabels,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const spec: Record<string, unknown> = {
|
|
68
|
+
location,
|
|
69
|
+
storageClass,
|
|
70
|
+
uniformBucketLevelAccess,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if (versioning) {
|
|
74
|
+
spec.versioning = { enabled: true };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (kmsKeyName) {
|
|
78
|
+
spec.encryption = { defaultKmsKeyName: kmsKeyName };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const lifecycleRules: Array<Record<string, unknown>> = [];
|
|
82
|
+
|
|
83
|
+
if (lifecycleDeleteAfterDays) {
|
|
84
|
+
lifecycleRules.push({
|
|
85
|
+
action: { type: "Delete" },
|
|
86
|
+
condition: { age: lifecycleDeleteAfterDays },
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (lifecycleNearlineAfterDays) {
|
|
91
|
+
lifecycleRules.push({
|
|
92
|
+
action: { type: "SetStorageClass", storageClass: "NEARLINE" },
|
|
93
|
+
condition: { age: lifecycleNearlineAfterDays },
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (lifecycleRules.length > 0) {
|
|
98
|
+
spec.lifecycleRule = lifecycleRules;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const bucket: Record<string, unknown> = {
|
|
102
|
+
metadata: {
|
|
103
|
+
name,
|
|
104
|
+
...(namespace && { namespace }),
|
|
105
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "storage" },
|
|
106
|
+
},
|
|
107
|
+
...spec,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return { bucket };
|
|
111
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GkeCluster composite — ContainerCluster + ContainerNodePool.
|
|
3
|
+
*
|
|
4
|
+
* Creates a GKE cluster with a default node pool configured for
|
|
5
|
+
* workload identity and autoscaling.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface GkeClusterProps {
|
|
9
|
+
/** Cluster name. */
|
|
10
|
+
name: string;
|
|
11
|
+
/** GCP region for regional cluster (default: uses GCP.Region). */
|
|
12
|
+
location?: string;
|
|
13
|
+
/** Initial node count per zone (default: 1). */
|
|
14
|
+
initialNodeCount?: number;
|
|
15
|
+
/** Machine type for nodes (default: "e2-medium"). */
|
|
16
|
+
machineType?: string;
|
|
17
|
+
/** Minimum nodes for autoscaling (default: 1). */
|
|
18
|
+
minNodeCount?: number;
|
|
19
|
+
/** Maximum nodes for autoscaling (default: 5). */
|
|
20
|
+
maxNodeCount?: number;
|
|
21
|
+
/** Enable workload identity (default: true). */
|
|
22
|
+
workloadIdentity?: boolean;
|
|
23
|
+
/** Disk size in GB for nodes (default: 100). */
|
|
24
|
+
diskSizeGb?: number;
|
|
25
|
+
/** GKE release channel (default: "REGULAR"). */
|
|
26
|
+
releaseChannel?: "RAPID" | "REGULAR" | "STABLE";
|
|
27
|
+
/** Additional labels. */
|
|
28
|
+
labels?: Record<string, string>;
|
|
29
|
+
/** Namespace for all resources. */
|
|
30
|
+
namespace?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface GkeClusterResult {
|
|
34
|
+
cluster: Record<string, unknown>;
|
|
35
|
+
nodePool: Record<string, unknown>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create a GkeCluster composite — returns prop objects for
|
|
40
|
+
* a ContainerCluster and ContainerNodePool.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* import { GkeCluster } from "@intentius/chant-lexicon-gcp";
|
|
45
|
+
*
|
|
46
|
+
* const { cluster, nodePool } = GkeCluster({
|
|
47
|
+
* name: "my-cluster",
|
|
48
|
+
* location: "us-central1",
|
|
49
|
+
* maxNodeCount: 10,
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function GkeCluster(props: GkeClusterProps): GkeClusterResult {
|
|
54
|
+
const {
|
|
55
|
+
name,
|
|
56
|
+
location,
|
|
57
|
+
initialNodeCount = 1,
|
|
58
|
+
machineType = "e2-medium",
|
|
59
|
+
minNodeCount = 1,
|
|
60
|
+
maxNodeCount = 5,
|
|
61
|
+
workloadIdentity = true,
|
|
62
|
+
diskSizeGb = 100,
|
|
63
|
+
releaseChannel = "REGULAR",
|
|
64
|
+
labels: extraLabels = {},
|
|
65
|
+
namespace,
|
|
66
|
+
} = props;
|
|
67
|
+
|
|
68
|
+
const commonLabels: Record<string, string> = {
|
|
69
|
+
"app.kubernetes.io/name": name,
|
|
70
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
71
|
+
...extraLabels,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const clusterSpec: Record<string, unknown> = {
|
|
75
|
+
initialNodeCount: 1, // Minimal default pool, real nodes in separate pool
|
|
76
|
+
removeDefaultNodePool: true,
|
|
77
|
+
releaseChannel: { channel: releaseChannel },
|
|
78
|
+
...(location && { location }),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
if (workloadIdentity) {
|
|
82
|
+
clusterSpec.workloadIdentityConfig = {
|
|
83
|
+
workloadPool: `PROJECT_ID.svc.id.goog`,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const cluster: Record<string, unknown> = {
|
|
88
|
+
metadata: {
|
|
89
|
+
name,
|
|
90
|
+
...(namespace && { namespace }),
|
|
91
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "cluster" },
|
|
92
|
+
},
|
|
93
|
+
...clusterSpec,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const nodePoolName = `${name}-nodes`;
|
|
97
|
+
const nodePool: Record<string, unknown> = {
|
|
98
|
+
metadata: {
|
|
99
|
+
name: nodePoolName,
|
|
100
|
+
...(namespace && { namespace }),
|
|
101
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "node-pool" },
|
|
102
|
+
},
|
|
103
|
+
clusterRef: { name },
|
|
104
|
+
initialNodeCount,
|
|
105
|
+
autoscaling: {
|
|
106
|
+
minNodeCount,
|
|
107
|
+
maxNodeCount,
|
|
108
|
+
},
|
|
109
|
+
nodeConfig: {
|
|
110
|
+
machineType,
|
|
111
|
+
diskSizeGb,
|
|
112
|
+
oauthScopes: ["https://www.googleapis.com/auth/cloud-platform"],
|
|
113
|
+
...(workloadIdentity && {
|
|
114
|
+
workloadMetadataConfig: { mode: "GKE_METADATA" },
|
|
115
|
+
}),
|
|
116
|
+
},
|
|
117
|
+
management: {
|
|
118
|
+
autoRepair: true,
|
|
119
|
+
autoUpgrade: true,
|
|
120
|
+
},
|
|
121
|
+
...(location && { location }),
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
return { cluster, nodePool };
|
|
125
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export { GkeCluster } from "./gke-cluster";
|
|
2
|
+
export type { GkeClusterProps, GkeClusterResult } from "./gke-cluster";
|
|
3
|
+
export { CloudRunService } from "./cloud-run-service";
|
|
4
|
+
export type { CloudRunServiceProps, CloudRunServiceResult } from "./cloud-run-service";
|
|
5
|
+
export { CloudSqlInstance } from "./cloud-sql-instance";
|
|
6
|
+
export type { CloudSqlInstanceProps, CloudSqlInstanceResult } from "./cloud-sql-instance";
|
|
7
|
+
export { GcsBucket } from "./gcs-bucket";
|
|
8
|
+
export type { GcsBucketProps, GcsBucketResult } from "./gcs-bucket";
|
|
9
|
+
export { VpcNetwork } from "./vpc-network";
|
|
10
|
+
export type { VpcNetworkProps, VpcNetworkResult, VpcSubnet } from "./vpc-network";
|
|
11
|
+
export { PubSubPipeline } from "./pubsub-pipeline";
|
|
12
|
+
export type { PubSubPipelineProps, PubSubPipelineResult } from "./pubsub-pipeline";
|
|
13
|
+
export { CloudFunctionWithTrigger } from "./cloud-function";
|
|
14
|
+
export type { CloudFunctionWithTriggerProps, CloudFunctionWithTriggerResult } from "./cloud-function";
|
|
15
|
+
export { PrivateService } from "./private-service";
|
|
16
|
+
export type { PrivateServiceProps, PrivateServiceResult } from "./private-service";
|
|
17
|
+
export { ManagedCertificate } from "./managed-certificate";
|
|
18
|
+
export type { ManagedCertificateProps, ManagedCertificateResult } from "./managed-certificate";
|
|
19
|
+
export { SecureProject } from "./secure-project";
|
|
20
|
+
export type { SecureProjectProps, SecureProjectResult } from "./secure-project";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ManagedCertificate composite — ManagedSslCertificate + optional TargetHttpsProxy + UrlMap.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface ManagedCertificateProps {
|
|
6
|
+
/** Certificate name. */
|
|
7
|
+
name: string;
|
|
8
|
+
/** Domains for the managed SSL certificate. */
|
|
9
|
+
domains: string[];
|
|
10
|
+
/** Create a TargetHttpsProxy and UrlMap (default: false). */
|
|
11
|
+
createProxy?: boolean;
|
|
12
|
+
/** Backend service name (required if createProxy is true). */
|
|
13
|
+
backendServiceName?: string;
|
|
14
|
+
/** Additional labels. */
|
|
15
|
+
labels?: Record<string, string>;
|
|
16
|
+
/** Namespace for all resources. */
|
|
17
|
+
namespace?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ManagedCertificateResult {
|
|
21
|
+
certificate: Record<string, unknown>;
|
|
22
|
+
targetHttpsProxy?: Record<string, unknown>;
|
|
23
|
+
urlMap?: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function ManagedCertificate(props: ManagedCertificateProps): ManagedCertificateResult {
|
|
27
|
+
const {
|
|
28
|
+
name,
|
|
29
|
+
domains,
|
|
30
|
+
createProxy = false,
|
|
31
|
+
backendServiceName,
|
|
32
|
+
labels: extraLabels = {},
|
|
33
|
+
namespace,
|
|
34
|
+
} = props;
|
|
35
|
+
|
|
36
|
+
const commonLabels: Record<string, string> = {
|
|
37
|
+
"app.kubernetes.io/name": name,
|
|
38
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
39
|
+
...extraLabels,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const certificate: Record<string, unknown> = {
|
|
43
|
+
metadata: {
|
|
44
|
+
name,
|
|
45
|
+
...(namespace && { namespace }),
|
|
46
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "certificate" },
|
|
47
|
+
},
|
|
48
|
+
managed: {
|
|
49
|
+
domains,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const result: ManagedCertificateResult = { certificate };
|
|
54
|
+
|
|
55
|
+
if (createProxy && backendServiceName) {
|
|
56
|
+
result.urlMap = {
|
|
57
|
+
metadata: {
|
|
58
|
+
name: `${name}-url-map`,
|
|
59
|
+
...(namespace && { namespace }),
|
|
60
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "url-map" },
|
|
61
|
+
},
|
|
62
|
+
defaultService: {
|
|
63
|
+
backendServiceRef: { name: backendServiceName },
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
result.targetHttpsProxy = {
|
|
68
|
+
metadata: {
|
|
69
|
+
name: `${name}-proxy`,
|
|
70
|
+
...(namespace && { namespace }),
|
|
71
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "proxy" },
|
|
72
|
+
},
|
|
73
|
+
urlMapRef: { name: `${name}-url-map` },
|
|
74
|
+
sslCertificates: [{ name }],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PrivateService composite — GlobalAddress + ServiceNetworkingConnection + optional DNS.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface PrivateServiceProps {
|
|
6
|
+
/** Service name. */
|
|
7
|
+
name: string;
|
|
8
|
+
/** VPC network name to peer with. */
|
|
9
|
+
networkName: string;
|
|
10
|
+
/** IP address prefix length (default: 16). */
|
|
11
|
+
prefixLength?: number;
|
|
12
|
+
/** Address type (default: "INTERNAL"). */
|
|
13
|
+
addressType?: string;
|
|
14
|
+
/** Purpose (default: "VPC_PEERING"). */
|
|
15
|
+
purpose?: string;
|
|
16
|
+
/** Enable a DNS zone for the private service (default: false). */
|
|
17
|
+
enableDns?: boolean;
|
|
18
|
+
/** DNS zone name (default: "{name}-dns"). */
|
|
19
|
+
dnsZoneName?: string;
|
|
20
|
+
/** DNS name suffix (default: "internal."). */
|
|
21
|
+
dnsSuffix?: string;
|
|
22
|
+
/** Additional labels. */
|
|
23
|
+
labels?: Record<string, string>;
|
|
24
|
+
/** Namespace for all resources. */
|
|
25
|
+
namespace?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface PrivateServiceResult {
|
|
29
|
+
globalAddress: Record<string, unknown>;
|
|
30
|
+
serviceConnection: Record<string, unknown>;
|
|
31
|
+
dnsZone?: Record<string, unknown>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function PrivateService(props: PrivateServiceProps): PrivateServiceResult {
|
|
35
|
+
const {
|
|
36
|
+
name,
|
|
37
|
+
networkName,
|
|
38
|
+
prefixLength = 16,
|
|
39
|
+
addressType = "INTERNAL",
|
|
40
|
+
purpose = "VPC_PEERING",
|
|
41
|
+
enableDns = false,
|
|
42
|
+
dnsZoneName,
|
|
43
|
+
dnsSuffix = "internal.",
|
|
44
|
+
labels: extraLabels = {},
|
|
45
|
+
namespace,
|
|
46
|
+
} = props;
|
|
47
|
+
|
|
48
|
+
const commonLabels: Record<string, string> = {
|
|
49
|
+
"app.kubernetes.io/name": name,
|
|
50
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
51
|
+
...extraLabels,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const globalAddress: Record<string, unknown> = {
|
|
55
|
+
metadata: {
|
|
56
|
+
name: `${name}-address`,
|
|
57
|
+
...(namespace && { namespace }),
|
|
58
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "address" },
|
|
59
|
+
},
|
|
60
|
+
addressType,
|
|
61
|
+
purpose,
|
|
62
|
+
prefixLength,
|
|
63
|
+
networkRef: { name: networkName },
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const serviceConnection: Record<string, unknown> = {
|
|
67
|
+
metadata: {
|
|
68
|
+
name: `${name}-connection`,
|
|
69
|
+
...(namespace && { namespace }),
|
|
70
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "connection" },
|
|
71
|
+
},
|
|
72
|
+
networkRef: { name: networkName },
|
|
73
|
+
service: "servicenetworking.googleapis.com",
|
|
74
|
+
reservedPeeringRanges: [{ name: `${name}-address` }],
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const result: PrivateServiceResult = { globalAddress, serviceConnection };
|
|
78
|
+
|
|
79
|
+
if (enableDns) {
|
|
80
|
+
result.dnsZone = {
|
|
81
|
+
metadata: {
|
|
82
|
+
name: dnsZoneName ?? `${name}-dns`,
|
|
83
|
+
...(namespace && { namespace }),
|
|
84
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "dns" },
|
|
85
|
+
},
|
|
86
|
+
dnsName: dnsSuffix,
|
|
87
|
+
visibility: "private",
|
|
88
|
+
privateVisibilityConfig: {
|
|
89
|
+
networks: [{ networkRef: { name: networkName } }],
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PubSubPipeline composite — Topic + Subscription + optional DLQ topic + subscriber IAM binding.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface PubSubPipelineProps {
|
|
6
|
+
/** Pipeline name. */
|
|
7
|
+
name: string;
|
|
8
|
+
/** Subscription ack deadline in seconds (default: 10). */
|
|
9
|
+
ackDeadlineSeconds?: number;
|
|
10
|
+
/** Message retention duration (default: "604800s" = 7 days). */
|
|
11
|
+
messageRetentionDuration?: string;
|
|
12
|
+
/** Enable dead-letter queue (default: false). */
|
|
13
|
+
enableDeadLetterQueue?: boolean;
|
|
14
|
+
/** Max delivery attempts before sending to DLQ (default: 5). */
|
|
15
|
+
maxDeliveryAttempts?: number;
|
|
16
|
+
/** Service account email for subscriber IAM binding. */
|
|
17
|
+
subscriberServiceAccount?: string;
|
|
18
|
+
/** Additional labels. */
|
|
19
|
+
labels?: Record<string, string>;
|
|
20
|
+
/** Namespace for all resources. */
|
|
21
|
+
namespace?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface PubSubPipelineResult {
|
|
25
|
+
topic: Record<string, unknown>;
|
|
26
|
+
subscription: Record<string, unknown>;
|
|
27
|
+
deadLetterTopic?: Record<string, unknown>;
|
|
28
|
+
subscriberIam?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function PubSubPipeline(props: PubSubPipelineProps): PubSubPipelineResult {
|
|
32
|
+
const {
|
|
33
|
+
name,
|
|
34
|
+
ackDeadlineSeconds = 10,
|
|
35
|
+
messageRetentionDuration = "604800s",
|
|
36
|
+
enableDeadLetterQueue = false,
|
|
37
|
+
maxDeliveryAttempts = 5,
|
|
38
|
+
subscriberServiceAccount,
|
|
39
|
+
labels: extraLabels = {},
|
|
40
|
+
namespace,
|
|
41
|
+
} = props;
|
|
42
|
+
|
|
43
|
+
const commonLabels: Record<string, string> = {
|
|
44
|
+
"app.kubernetes.io/name": name,
|
|
45
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
46
|
+
...extraLabels,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const topic: Record<string, unknown> = {
|
|
50
|
+
metadata: {
|
|
51
|
+
name: `${name}-topic`,
|
|
52
|
+
...(namespace && { namespace }),
|
|
53
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "topic" },
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const subscription: Record<string, unknown> = {
|
|
58
|
+
metadata: {
|
|
59
|
+
name: `${name}-subscription`,
|
|
60
|
+
...(namespace && { namespace }),
|
|
61
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "subscription" },
|
|
62
|
+
},
|
|
63
|
+
topicRef: { name: `${name}-topic` },
|
|
64
|
+
ackDeadlineSeconds,
|
|
65
|
+
messageRetentionDuration,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const result: PubSubPipelineResult = { topic, subscription };
|
|
69
|
+
|
|
70
|
+
if (enableDeadLetterQueue) {
|
|
71
|
+
result.deadLetterTopic = {
|
|
72
|
+
metadata: {
|
|
73
|
+
name: `${name}-dlq`,
|
|
74
|
+
...(namespace && { namespace }),
|
|
75
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "dead-letter" },
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
subscription.deadLetterPolicy = {
|
|
79
|
+
deadLetterTopicRef: { name: `${name}-dlq` },
|
|
80
|
+
maxDeliveryAttempts,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (subscriberServiceAccount) {
|
|
85
|
+
result.subscriberIam = {
|
|
86
|
+
metadata: {
|
|
87
|
+
name: `${name}-subscriber`,
|
|
88
|
+
...(namespace && { namespace }),
|
|
89
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "iam" },
|
|
90
|
+
},
|
|
91
|
+
member: `serviceAccount:${subscriberServiceAccount}`,
|
|
92
|
+
role: "roles/pubsub.subscriber",
|
|
93
|
+
resourceRef: {
|
|
94
|
+
apiVersion: "pubsub.cnrm.cloud.google.com/v1beta1",
|
|
95
|
+
kind: "PubSubSubscription",
|
|
96
|
+
name: `${name}-subscription`,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SecureProject composite — Project + IAMAuditConfig + Service enablement + owner IAM + LoggingSink.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface SecureProjectProps {
|
|
6
|
+
/** Project name (also used as project ID). */
|
|
7
|
+
name: string;
|
|
8
|
+
/** Organization ID or folder ID for the parent. */
|
|
9
|
+
orgId?: string;
|
|
10
|
+
/** Folder ID for the parent (alternative to orgId). */
|
|
11
|
+
folderId?: string;
|
|
12
|
+
/** Billing account ID. */
|
|
13
|
+
billingAccountRef?: string;
|
|
14
|
+
/** Owner email (IAM member format, e.g., "user:admin@example.com"). */
|
|
15
|
+
owner?: string;
|
|
16
|
+
/** GCP APIs to enable (default: common APIs). */
|
|
17
|
+
enabledApis?: string[];
|
|
18
|
+
/** Logging sink destination (e.g., BigQuery dataset or Cloud Storage bucket). */
|
|
19
|
+
loggingSinkDestination?: string;
|
|
20
|
+
/** Logging sink filter (default: all audit logs). */
|
|
21
|
+
loggingSinkFilter?: string;
|
|
22
|
+
/** Additional labels. */
|
|
23
|
+
labels?: Record<string, string>;
|
|
24
|
+
/** Namespace for all resources. */
|
|
25
|
+
namespace?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface SecureProjectResult {
|
|
29
|
+
project: Record<string, unknown>;
|
|
30
|
+
auditConfig: Record<string, unknown>;
|
|
31
|
+
services: Record<string, unknown>[];
|
|
32
|
+
ownerIam?: Record<string, unknown>;
|
|
33
|
+
loggingSink?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function SecureProject(props: SecureProjectProps): SecureProjectResult {
|
|
37
|
+
const {
|
|
38
|
+
name,
|
|
39
|
+
orgId,
|
|
40
|
+
folderId,
|
|
41
|
+
billingAccountRef,
|
|
42
|
+
owner,
|
|
43
|
+
enabledApis = [
|
|
44
|
+
"compute.googleapis.com",
|
|
45
|
+
"container.googleapis.com",
|
|
46
|
+
"iam.googleapis.com",
|
|
47
|
+
"logging.googleapis.com",
|
|
48
|
+
"monitoring.googleapis.com",
|
|
49
|
+
],
|
|
50
|
+
loggingSinkDestination,
|
|
51
|
+
loggingSinkFilter = 'logName:"cloudaudit.googleapis.com"',
|
|
52
|
+
labels: extraLabels = {},
|
|
53
|
+
namespace,
|
|
54
|
+
} = props;
|
|
55
|
+
|
|
56
|
+
const commonLabels: Record<string, string> = {
|
|
57
|
+
"app.kubernetes.io/name": name,
|
|
58
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
59
|
+
...extraLabels,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const project: Record<string, unknown> = {
|
|
63
|
+
metadata: {
|
|
64
|
+
name,
|
|
65
|
+
...(namespace && { namespace }),
|
|
66
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "project" },
|
|
67
|
+
},
|
|
68
|
+
...(orgId && { organizationRef: { external: orgId } }),
|
|
69
|
+
...(folderId && { folderRef: { external: folderId } }),
|
|
70
|
+
...(billingAccountRef && { billingAccountRef: { external: billingAccountRef } }),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const auditConfig: Record<string, unknown> = {
|
|
74
|
+
metadata: {
|
|
75
|
+
name: `${name}-audit`,
|
|
76
|
+
...(namespace && { namespace }),
|
|
77
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "audit" },
|
|
78
|
+
},
|
|
79
|
+
service: "allServices",
|
|
80
|
+
auditLogConfigs: [
|
|
81
|
+
{ logType: "ADMIN_READ" },
|
|
82
|
+
{ logType: "DATA_READ" },
|
|
83
|
+
{ logType: "DATA_WRITE" },
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const services = enabledApis.map((api) => ({
|
|
88
|
+
metadata: {
|
|
89
|
+
name: `${name}-${api.split(".")[0]}`,
|
|
90
|
+
...(namespace && { namespace }),
|
|
91
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "service" },
|
|
92
|
+
},
|
|
93
|
+
resourceID: api,
|
|
94
|
+
}));
|
|
95
|
+
|
|
96
|
+
const result: SecureProjectResult = { project, auditConfig, services };
|
|
97
|
+
|
|
98
|
+
if (owner) {
|
|
99
|
+
result.ownerIam = {
|
|
100
|
+
metadata: {
|
|
101
|
+
name: `${name}-owner`,
|
|
102
|
+
...(namespace && { namespace }),
|
|
103
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "iam" },
|
|
104
|
+
},
|
|
105
|
+
member: owner,
|
|
106
|
+
role: "roles/owner",
|
|
107
|
+
resourceRef: {
|
|
108
|
+
apiVersion: "resourcemanager.cnrm.cloud.google.com/v1beta1",
|
|
109
|
+
kind: "Project",
|
|
110
|
+
name,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (loggingSinkDestination) {
|
|
116
|
+
result.loggingSink = {
|
|
117
|
+
metadata: {
|
|
118
|
+
name: `${name}-audit-sink`,
|
|
119
|
+
...(namespace && { namespace }),
|
|
120
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "logging" },
|
|
121
|
+
},
|
|
122
|
+
destination: loggingSinkDestination,
|
|
123
|
+
filter: loggingSinkFilter,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return result;
|
|
128
|
+
}
|