@intentius/chant-lexicon-gcp 0.124.31 → 0.124.32

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 (103) hide show
  1. package/dist/actions/index.js +45 -0
  2. package/dist/api/read-client.js +105 -0
  3. package/dist/codegen/docs-cli.js +6 -0
  4. package/dist/codegen/docs.js +115 -0
  5. package/dist/codegen/generate-cli.js +17 -0
  6. package/dist/codegen/generate.js +214 -0
  7. package/dist/codegen/naming.js +164 -0
  8. package/dist/codegen/package.js +43 -0
  9. package/dist/composites/catalog.js +1245 -0
  10. package/dist/composites/cloud-function.js +65 -0
  11. package/dist/composites/cloud-run-service.js +71 -0
  12. package/dist/composites/cloud-sql-instance.js +85 -0
  13. package/dist/composites/gcs-bucket.js +64 -0
  14. package/dist/composites/gke-cluster.js +113 -0
  15. package/dist/composites/gke-crdb-region.js +137 -0
  16. package/dist/composites/gpu-node-pool.js +74 -0
  17. package/dist/composites/index.js +15 -0
  18. package/dist/composites/landing-zone.js +89 -0
  19. package/dist/composites/managed-certificate.js +46 -0
  20. package/dist/composites/memorystore-redis.js +52 -0
  21. package/dist/composites/multi-region-vpc.js +108 -0
  22. package/dist/composites/private-service.js +50 -0
  23. package/dist/composites/pubsub-pipeline.js +63 -0
  24. package/dist/composites/secure-project.js +85 -0
  25. package/dist/composites/vpc-network.js +113 -0
  26. package/dist/coverage.js +28 -0
  27. package/dist/deep-observe-hooks.js +152 -0
  28. package/dist/deep-observe.js +273 -0
  29. package/dist/default-labels.js +67 -0
  30. package/dist/describe-resources.js +264 -0
  31. package/dist/detect.js +16 -0
  32. package/dist/export-resources.js +59 -0
  33. package/dist/generated/index.js +1804 -0
  34. package/dist/generated/runtime.js +4 -0
  35. package/dist/governance.js +98 -0
  36. package/dist/import/generator.js +68 -0
  37. package/dist/import/live-export.js +73 -0
  38. package/dist/import/parser.js +61 -0
  39. package/dist/index.js +36 -0
  40. package/dist/integrity.json +3 -3
  41. package/dist/lint/audit-catalog.js +38 -0
  42. package/dist/lint/audit-lineage.js +63 -0
  43. package/dist/lint/post-synth/gcp-helpers.js +91 -0
  44. package/dist/lint/post-synth/index.js +54 -0
  45. package/dist/lint/post-synth/schema-registry.d.ts.map +1 -1
  46. package/dist/lint/post-synth/schema-registry.js +69 -0
  47. package/dist/lint/post-synth/wgc101.js +47 -0
  48. package/dist/lint/post-synth/wgc102.js +29 -0
  49. package/dist/lint/post-synth/wgc103.js +37 -0
  50. package/dist/lint/post-synth/wgc104.js +34 -0
  51. package/dist/lint/post-synth/wgc105.js +39 -0
  52. package/dist/lint/post-synth/wgc106.js +30 -0
  53. package/dist/lint/post-synth/wgc107.js +33 -0
  54. package/dist/lint/post-synth/wgc108.js +34 -0
  55. package/dist/lint/post-synth/wgc109.js +33 -0
  56. package/dist/lint/post-synth/wgc110.js +32 -0
  57. package/dist/lint/post-synth/wgc111.js +47 -0
  58. package/dist/lint/post-synth/wgc112.js +46 -0
  59. package/dist/lint/post-synth/wgc113.js +35 -0
  60. package/dist/lint/post-synth/wgc201.js +30 -0
  61. package/dist/lint/post-synth/wgc202.js +33 -0
  62. package/dist/lint/post-synth/wgc203.js +35 -0
  63. package/dist/lint/post-synth/wgc204.js +33 -0
  64. package/dist/lint/post-synth/wgc301.js +28 -0
  65. package/dist/lint/post-synth/wgc302.js +28 -0
  66. package/dist/lint/post-synth/wgc303.js +29 -0
  67. package/dist/lint/post-synth/wgc401.js +50 -0
  68. package/dist/lint/post-synth/wgc402.js +46 -0
  69. package/dist/lint/post-synth/wgc403.js +74 -0
  70. package/dist/lint/post-synth/wgc501.js +63 -0
  71. package/dist/lint/post-synth/wgc502.js +37 -0
  72. package/dist/lint/post-synth/wgc503.js +49 -0
  73. package/dist/lint/rules/hardcoded-project.js +51 -0
  74. package/dist/lint/rules/hardcoded-region.js +51 -0
  75. package/dist/lint/rules/index.js +3 -0
  76. package/dist/lint/rules/public-iam.js +37 -0
  77. package/dist/lsp/completions.d.ts.map +1 -1
  78. package/dist/lsp/completions.js +15 -0
  79. package/dist/lsp/hover.d.ts.map +1 -1
  80. package/dist/lsp/hover.js +46 -0
  81. package/dist/manifest.json +1 -1
  82. package/dist/op/activities/floci-gcp.js +49 -0
  83. package/dist/op/activities/gcp-apply.js +618 -0
  84. package/dist/op/activities/index.js +10 -0
  85. package/dist/op/builders.js +50 -0
  86. package/dist/ownership.js +38 -0
  87. package/dist/package-cli.js +20 -0
  88. package/dist/plugin.js +371 -0
  89. package/dist/pseudo.js +15 -0
  90. package/dist/rules/schema-registry.ts +2 -1
  91. package/dist/serializer.d.ts.map +1 -1
  92. package/dist/serializer.js +233 -0
  93. package/dist/spec/fetch.js +107 -0
  94. package/dist/spec/parse.js +323 -0
  95. package/dist/validate-cli.js +11 -0
  96. package/dist/validate.js +24 -0
  97. package/dist/variables.js +15 -0
  98. package/package.json +8 -8
  99. package/src/codegen/package.ts +2 -2
  100. package/src/lint/post-synth/schema-registry.ts +2 -1
  101. package/src/lsp/completions.ts +2 -1
  102. package/src/lsp/hover.ts +2 -1
  103. package/src/serializer.ts +2 -1
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Landing-zone bootstrap composites — the GCP slice.
3
+ *
4
+ * Fixed-shape resources for greenfield creation of the recommended
5
+ * governance foundation through a Config Connector management stack. The
6
+ * evaluability rules (EVL002/004) require composites to declare a fixed set
7
+ * of resources, so these carry the foundation only; arbitrary folder/project
8
+ * trees are authored as config with `landingZoneConfig()` (../governance.ts)
9
+ * and reconciled by an external governance reconciler, and further folders/projects are
10
+ * declared as ordinary resources.
11
+ *
12
+ * The pieces compose:
13
+ * const lz = GovernanceFoundation({ orgId: "123456789012" });
14
+ * const lr = LocationRestriction({ orgId: "123456789012", locations: ["in:eu-locations"] });
15
+ * const ac = OrganizationAuditConfig({ orgId: "123456789012" });
16
+ * There is no OrganizationRoot analog — GCP organizations come from Cloud
17
+ * Identity / Workspace, not the resource API, so greenfield and brownfield
18
+ * both start from an existing org id.
19
+ */
20
+ import { Composite } from "@intentius/chant";
21
+ import { IAMAuditConfig, OrgpolicyPolicy, ResourcemanagerFolder } from "../generated/index.js";
22
+ import { AUDIT_ALL_SERVICES, DISABLE_SA_KEY_CREATION, SKIP_DEFAULT_NETWORK, resourceLocationRestriction, } from "../governance.js";
23
+ /** "organizations/123" and "123" are both accepted everywhere an org id appears. */
24
+ function orgNumber(orgId) {
25
+ return orgId.replace(/^organizations\//, "");
26
+ }
27
+ function labels(component) {
28
+ return {
29
+ "app.kubernetes.io/managed-by": "chant",
30
+ "app.kubernetes.io/component": component,
31
+ };
32
+ }
33
+ function orgPolicy(metaName, policy, orgId, namespace) {
34
+ return new OrgpolicyPolicy({
35
+ metadata: {
36
+ name: metaName,
37
+ ...(namespace && { namespace }),
38
+ labels: labels("org-policy"),
39
+ },
40
+ resourceID: policy.constraint,
41
+ organizationRef: { external: orgNumber(orgId) },
42
+ spec: { rules: policy.rules },
43
+ });
44
+ }
45
+ /**
46
+ * Security / Infrastructure / Sandbox / Workloads folders with
47
+ * `disable-sa-key-creation` and `skip-default-network` enforced at the
48
+ * organization root — the same baseline `landingZoneConfig()` declares.
49
+ */
50
+ export const GovernanceFoundation = Composite((props) => {
51
+ const { orgId, namespace } = props;
52
+ const folder = (metaName, displayName) => new ResourcemanagerFolder({
53
+ metadata: {
54
+ name: metaName,
55
+ ...(namespace && { namespace }),
56
+ labels: labels("folder"),
57
+ },
58
+ displayName,
59
+ organizationRef: { external: orgNumber(orgId) },
60
+ });
61
+ return {
62
+ folderSecurity: folder("security", "Security"),
63
+ folderInfrastructure: folder("infrastructure", "Infrastructure"),
64
+ folderSandbox: folder("sandbox", "Sandbox"),
65
+ folderWorkloads: folder("workloads", "Workloads"),
66
+ policyDisableSaKeyCreation: orgPolicy("disable-sa-key-creation", DISABLE_SA_KEY_CREATION, orgId, namespace),
67
+ policySkipDefaultNetwork: orgPolicy("skip-default-network", SKIP_DEFAULT_NETWORK, orgId, namespace),
68
+ };
69
+ }, "GovernanceFoundation");
70
+ export const LocationRestriction = Composite((props) => {
71
+ const policyResourceLocations = orgPolicy("resource-location-restriction", resourceLocationRestriction(props.locations), props.orgId, props.namespace);
72
+ return { policyResourceLocations };
73
+ }, "LocationRestriction");
74
+ export const OrganizationAuditConfig = Composite((props) => {
75
+ const auditConfig = new IAMAuditConfig({
76
+ metadata: {
77
+ name: "organization-audit",
78
+ ...(props.namespace && { namespace: props.namespace }),
79
+ labels: labels("audit"),
80
+ },
81
+ resourceRef: {
82
+ kind: "Organization",
83
+ external: `organizations/${orgNumber(props.orgId)}`,
84
+ },
85
+ service: props.service ?? AUDIT_ALL_SERVICES.service,
86
+ auditLogConfigs: (props.logTypes ?? [...AUDIT_ALL_SERVICES.logTypes]).map((logType) => ({ logType })),
87
+ });
88
+ return { auditConfig };
89
+ }, "OrganizationAuditConfig");
@@ -0,0 +1,46 @@
1
+ /**
2
+ * ManagedCertificate composite — ManagedSslCertificate + optional TargetHttpsProxy + UrlMap.
3
+ */
4
+ import { Composite, mergeDefaults } from "@intentius/chant";
5
+ import { ManagedSSLCertificate, TargetHTTPSProxy, URLMap } from "../generated/index.js";
6
+ export const ManagedCertificate = Composite((props) => {
7
+ const { name, domains, createProxy = false, backendServiceName, labels: extraLabels = {}, namespace, defaults: defs, } = props;
8
+ const commonLabels = {
9
+ "app.kubernetes.io/name": name,
10
+ "app.kubernetes.io/managed-by": "chant",
11
+ ...extraLabels,
12
+ };
13
+ const certificate = new ManagedSSLCertificate(mergeDefaults({
14
+ metadata: {
15
+ name,
16
+ ...(namespace && { namespace }),
17
+ labels: { ...commonLabels, "app.kubernetes.io/component": "certificate" },
18
+ },
19
+ managed: {
20
+ domains,
21
+ },
22
+ }, defs?.certificate));
23
+ const result = { certificate };
24
+ if (createProxy && backendServiceName) {
25
+ result.urlMap = new URLMap(mergeDefaults({
26
+ metadata: {
27
+ name: `${name}-url-map`,
28
+ ...(namespace && { namespace }),
29
+ labels: { ...commonLabels, "app.kubernetes.io/component": "url-map" },
30
+ },
31
+ defaultService: {
32
+ backendServiceRef: { name: backendServiceName },
33
+ },
34
+ }, defs?.urlMap));
35
+ result.targetHttpsProxy = new TargetHTTPSProxy(mergeDefaults({
36
+ metadata: {
37
+ name: `${name}-proxy`,
38
+ ...(namespace && { namespace }),
39
+ labels: { ...commonLabels, "app.kubernetes.io/component": "proxy" },
40
+ },
41
+ urlMapRef: { name: `${name}-url-map` },
42
+ sslCertificates: [{ name }],
43
+ }, defs?.targetHttpsProxy));
44
+ }
45
+ return result;
46
+ }, "ManagedCertificate");
@@ -0,0 +1,52 @@
1
+ /**
2
+ * MemorystoreRedis composite — RedisInstance with purpose-driven defaults.
3
+ */
4
+ import { Composite, mergeDefaults } from "@intentius/chant";
5
+ import { RedisInstance } from "../generated/index.js";
6
+ /**
7
+ * Create a MemorystoreRedis composite.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { MemorystoreRedis } from "@intentius/chant-lexicon-gcp";
12
+ *
13
+ * const { instance } = MemorystoreRedis({
14
+ * name: "my-app-persistent",
15
+ * purpose: "persistent",
16
+ * tier: "STANDARD_HA",
17
+ * memorySizeGb: 5,
18
+ * region: "us-central1",
19
+ * networkRef: "my-vpc",
20
+ * });
21
+ * ```
22
+ */
23
+ export const MemorystoreRedis = Composite((props) => {
24
+ const { name, purpose, tier, memorySizeGb, region, networkRef, redisVersion = "REDIS_7_0", authEnabled = true, namespace, labels: extraLabels = {}, defaults: defs, } = props;
25
+ const maxmemoryPolicy = purpose === "persistent" ? "noeviction" : "allkeys-lru";
26
+ const commonLabels = {
27
+ "app.kubernetes.io/name": name,
28
+ "app.kubernetes.io/managed-by": "chant",
29
+ ...extraLabels,
30
+ };
31
+ const instance = new RedisInstance(mergeDefaults({
32
+ metadata: {
33
+ name,
34
+ ...(namespace && { namespace }),
35
+ labels: { ...commonLabels, "app.kubernetes.io/component": "cache" },
36
+ },
37
+ region,
38
+ tier,
39
+ memorySizeGb,
40
+ authEnabled,
41
+ redisVersion,
42
+ connectMode: "PRIVATE_SERVICE_ACCESS",
43
+ authorizedNetworkRef: { name: networkRef },
44
+ // TLS disabled: GitLab's redis-rb client requires either no TLS or a custom CA cert
45
+ // injected via REDIS_SSL_CA_FILE. AUTH (authEnabled: true) provides access control.
46
+ transitEncryptionMode: "DISABLED",
47
+ redisConfigs: {
48
+ "maxmemory-policy": maxmemoryPolicy,
49
+ },
50
+ }, defs?.instance));
51
+ return { instance };
52
+ }, "MemorystoreRedis");
@@ -0,0 +1,108 @@
1
+ /**
2
+ * MultiRegionVpc composite — VPC + 2 subnets per region + Router + RouterNAT per region + Firewall.
3
+ *
4
+ * Collapses the boilerplate of a multi-region GKE networking stack into a single call.
5
+ * Each region gets node and pod subnets, a Cloud Router, and a Cloud NAT gateway.
6
+ * A single allow-internal firewall rule covers all region CIDRs.
7
+ */
8
+ import { Composite } from "@intentius/chant";
9
+ import { VPCNetwork, Subnetwork, Router, RouterNAT, Firewall } from "../generated/index.js";
10
+ /**
11
+ * Create a MultiRegionVpc composite — one VPC with subnets, Cloud NAT, and an
12
+ * allow-internal firewall for every region in the array.
13
+ *
14
+ * The composite eliminates the per-region Router/NAT boilerplate that arises when
15
+ * `VpcNetwork` only handles a single NAT region and the rest must be wired manually.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { MultiRegionVpc } from "@intentius/chant-lexicon-gcp";
20
+ *
21
+ * export const network = MultiRegionVpc({
22
+ * name: "crdb-multi-region",
23
+ * regions: [
24
+ * { region: "us-east4", regionAlias: "east", nodeSubnetCidr: "10.1.0.0/20", podSubnetCidr: "10.1.16.0/20" },
25
+ * { region: "us-central1", regionAlias: "central", nodeSubnetCidr: "10.2.0.0/20", podSubnetCidr: "10.2.16.0/20" },
26
+ * { region: "us-west1", regionAlias: "west", nodeSubnetCidr: "10.3.0.0/20", podSubnetCidr: "10.3.16.0/20" },
27
+ * ],
28
+ * });
29
+ * ```
30
+ */
31
+ export const MultiRegionVpc = Composite((props) => {
32
+ const { name, regions, enableFlowLogs = false, labels: extraLabels = {}, namespace, } = props;
33
+ const commonLabels = {
34
+ "app.kubernetes.io/name": name,
35
+ "app.kubernetes.io/managed-by": "chant",
36
+ ...extraLabels,
37
+ };
38
+ const meta = (component, resourceName) => ({
39
+ metadata: {
40
+ name: resourceName ?? name,
41
+ ...(namespace && { namespace }),
42
+ labels: { ...commonLabels, "app.kubernetes.io/component": component },
43
+ },
44
+ });
45
+ const network = new VPCNetwork({
46
+ ...meta("network"),
47
+ autoCreateSubnetworks: false,
48
+ routingMode: "REGIONAL",
49
+ });
50
+ const subnetEntries = {};
51
+ const routerEntries = {};
52
+ const natEntries = {};
53
+ const allCidrs = [];
54
+ for (const r of regions) {
55
+ const alias = r.regionAlias ?? r.region;
56
+ allCidrs.push(r.nodeSubnetCidr, r.podSubnetCidr);
57
+ const flowConfig = enableFlowLogs
58
+ ? { logConfig: { enable: true, aggregationInterval: "INTERVAL_5_SEC", flowSampling: 0.5 } }
59
+ : {};
60
+ subnetEntries[`subnet_${alias}_nodes`] = new Subnetwork({
61
+ ...meta("subnet", `${name}-${alias}-nodes`),
62
+ networkRef: { name },
63
+ ipCidrRange: r.nodeSubnetCidr,
64
+ region: r.region,
65
+ privateIpGoogleAccess: true,
66
+ ...flowConfig,
67
+ });
68
+ subnetEntries[`subnet_${alias}_pods`] = new Subnetwork({
69
+ ...meta("subnet", `${name}-${alias}-pods`),
70
+ networkRef: { name },
71
+ ipCidrRange: r.podSubnetCidr,
72
+ region: r.region,
73
+ privateIpGoogleAccess: true,
74
+ ...flowConfig,
75
+ });
76
+ const routerName = `${name}-${alias}`;
77
+ routerEntries[`router_${alias}`] = new Router({
78
+ ...meta("router", routerName),
79
+ networkRef: { name },
80
+ region: r.region,
81
+ });
82
+ natEntries[`nat_${alias}`] = new RouterNAT({
83
+ ...meta("nat", routerName),
84
+ routerRef: { name: routerName },
85
+ region: r.region,
86
+ natIpAllocateOption: "AUTO_ONLY",
87
+ sourceSubnetworkIpRangesToNat: "ALL_SUBNETWORKS_ALL_PRIMARY_IP_RANGES",
88
+ });
89
+ }
90
+ // Allow all TCP/UDP/ICMP between every subnet CIDR in the VPC.
91
+ const firewallInternal = new Firewall({
92
+ ...meta("firewall", `${name}-allow-internal`),
93
+ networkRef: { name },
94
+ allow: [
95
+ { protocol: "tcp", ports: ["0-65535"] },
96
+ { protocol: "udp", ports: ["0-65535"] },
97
+ { protocol: "icmp" },
98
+ ],
99
+ sourceRanges: allCidrs,
100
+ });
101
+ return {
102
+ network,
103
+ ...subnetEntries,
104
+ ...routerEntries,
105
+ ...natEntries,
106
+ firewallInternal,
107
+ };
108
+ }, "MultiRegionVpc");
@@ -0,0 +1,50 @@
1
+ /**
2
+ * PrivateService composite — GlobalAddress + ServiceNetworkingConnection + optional DNS.
3
+ */
4
+ import { Composite, mergeDefaults } from "@intentius/chant";
5
+ import { ComputeAddress, ServicenetworkingConnection, DNSManagedZone, } from "../generated/index.js";
6
+ export const PrivateService = Composite((props) => {
7
+ const { name, networkName, prefixLength = 16, addressType = "INTERNAL", purpose = "VPC_PEERING", enableDns = false, dnsZoneName, dnsSuffix = "internal.", labels: extraLabels = {}, namespace, defaults: defs, } = props;
8
+ const commonLabels = {
9
+ "app.kubernetes.io/name": name,
10
+ "app.kubernetes.io/managed-by": "chant",
11
+ ...extraLabels,
12
+ };
13
+ const globalAddress = new ComputeAddress(mergeDefaults({
14
+ metadata: {
15
+ name: `${name}-address`,
16
+ ...(namespace && { namespace }),
17
+ labels: { ...commonLabels, "app.kubernetes.io/component": "address" },
18
+ },
19
+ addressType,
20
+ purpose,
21
+ prefixLength,
22
+ networkRef: { name: networkName },
23
+ }, defs?.globalAddress));
24
+ const serviceConnection = new ServicenetworkingConnection(mergeDefaults({
25
+ metadata: {
26
+ name: `${name}-connection`,
27
+ ...(namespace && { namespace }),
28
+ labels: { ...commonLabels, "app.kubernetes.io/component": "connection" },
29
+ },
30
+ networkRef: { name: networkName },
31
+ service: "servicenetworking.googleapis.com",
32
+ reservedPeeringRanges: [{ name: `${name}-address` }],
33
+ }, defs?.serviceConnection));
34
+ const result = { globalAddress, serviceConnection };
35
+ if (enableDns) {
36
+ result.dnsZone = new DNSManagedZone(mergeDefaults({
37
+ metadata: {
38
+ name: dnsZoneName ?? `${name}-dns`,
39
+ ...(namespace && { namespace }),
40
+ labels: { ...commonLabels, "app.kubernetes.io/component": "dns" },
41
+ },
42
+ dnsName: dnsSuffix,
43
+ visibility: "private",
44
+ privateVisibilityConfig: {
45
+ networks: [{ networkRef: { name: networkName } }],
46
+ },
47
+ }, defs?.dnsZone));
48
+ }
49
+ return result;
50
+ }, "PrivateService");
@@ -0,0 +1,63 @@
1
+ /**
2
+ * PubSubPipeline composite — Topic + Subscription + optional DLQ topic + subscriber IAM binding.
3
+ */
4
+ import { Composite, mergeDefaults } from "@intentius/chant";
5
+ import { PubSubTopic, PubSubSubscription, IAMPolicyMember } from "../generated/index.js";
6
+ export const PubSubPipeline = Composite((props) => {
7
+ const { name, ackDeadlineSeconds = 10, messageRetentionDuration = "604800s", enableDeadLetterQueue = false, maxDeliveryAttempts = 5, subscriberServiceAccount, labels: extraLabels = {}, namespace, defaults: defs, } = props;
8
+ const commonLabels = {
9
+ "app.kubernetes.io/name": name,
10
+ "app.kubernetes.io/managed-by": "chant",
11
+ ...extraLabels,
12
+ };
13
+ const topic = new PubSubTopic(mergeDefaults({
14
+ metadata: {
15
+ name: `${name}-topic`,
16
+ ...(namespace && { namespace }),
17
+ labels: { ...commonLabels, "app.kubernetes.io/component": "topic" },
18
+ },
19
+ }, defs?.topic));
20
+ const subscriptionProps = {
21
+ metadata: {
22
+ name: `${name}-subscription`,
23
+ ...(namespace && { namespace }),
24
+ labels: { ...commonLabels, "app.kubernetes.io/component": "subscription" },
25
+ },
26
+ topicRef: { name: `${name}-topic` },
27
+ ackDeadlineSeconds,
28
+ messageRetentionDuration,
29
+ };
30
+ const result = { topic };
31
+ if (enableDeadLetterQueue) {
32
+ result.deadLetterTopic = new PubSubTopic(mergeDefaults({
33
+ metadata: {
34
+ name: `${name}-dlq`,
35
+ ...(namespace && { namespace }),
36
+ labels: { ...commonLabels, "app.kubernetes.io/component": "dead-letter" },
37
+ },
38
+ }, defs?.deadLetterTopic));
39
+ subscriptionProps.deadLetterPolicy = {
40
+ deadLetterTopicRef: { name: `${name}-dlq` },
41
+ maxDeliveryAttempts,
42
+ };
43
+ }
44
+ const subscription = new PubSubSubscription(mergeDefaults(subscriptionProps, defs?.subscription));
45
+ result.subscription = subscription;
46
+ if (subscriberServiceAccount) {
47
+ result.subscriberIam = new IAMPolicyMember(mergeDefaults({
48
+ metadata: {
49
+ name: `${name}-subscriber`,
50
+ ...(namespace && { namespace }),
51
+ labels: { ...commonLabels, "app.kubernetes.io/component": "iam" },
52
+ },
53
+ member: `serviceAccount:${subscriberServiceAccount}`,
54
+ role: "roles/pubsub.subscriber",
55
+ resourceRef: {
56
+ apiVersion: "pubsub.cnrm.cloud.google.com/v1beta1",
57
+ kind: "PubSubSubscription",
58
+ name: `${name}-subscription`,
59
+ },
60
+ }, defs?.subscriberIam));
61
+ }
62
+ return result;
63
+ }, "PubSubPipeline");
@@ -0,0 +1,85 @@
1
+ /**
2
+ * SecureProject composite — Project + IAMAuditConfig + Service enablement + owner IAM + LoggingSink.
3
+ */
4
+ import { Composite, mergeDefaults } from "@intentius/chant";
5
+ import { ResourcemanagerProject, IAMAuditConfig, ServiceusageService, IAMPolicyMember, LogSink, } from "../generated/index.js";
6
+ export const SecureProject = Composite((props) => {
7
+ const { name, orgId, folderId, billingAccountRef, owner, enabledApis = [
8
+ "compute.googleapis.com",
9
+ "container.googleapis.com",
10
+ "iam.googleapis.com",
11
+ "logging.googleapis.com",
12
+ "monitoring.googleapis.com",
13
+ ], loggingSinkDestination, loggingSinkFilter = 'logName:"cloudaudit.googleapis.com"', labels: extraLabels = {}, namespace, defaults: defs, } = props;
14
+ const commonLabels = {
15
+ "app.kubernetes.io/name": name,
16
+ "app.kubernetes.io/managed-by": "chant",
17
+ ...extraLabels,
18
+ };
19
+ const project = new ResourcemanagerProject(mergeDefaults({
20
+ metadata: {
21
+ name,
22
+ ...(namespace && { namespace }),
23
+ labels: { ...commonLabels, "app.kubernetes.io/component": "project" },
24
+ },
25
+ ...(orgId && { organizationRef: { external: orgId } }),
26
+ ...(folderId && { folderRef: { external: folderId } }),
27
+ ...(billingAccountRef && { billingAccountRef: { external: billingAccountRef } }),
28
+ }, defs?.project));
29
+ const auditConfig = new IAMAuditConfig(mergeDefaults({
30
+ metadata: {
31
+ name: `${name}-audit`,
32
+ ...(namespace && { namespace }),
33
+ labels: { ...commonLabels, "app.kubernetes.io/component": "audit" },
34
+ },
35
+ service: "allServices",
36
+ auditLogConfigs: [
37
+ { logType: "ADMIN_READ" },
38
+ { logType: "DATA_READ" },
39
+ { logType: "DATA_WRITE" },
40
+ ],
41
+ }, defs?.auditConfig));
42
+ // Spread services into named members (service_compute, service_container, etc.)
43
+ // so the Composite validator accepts them as individual Declarables.
44
+ const serviceEntries = {};
45
+ for (const api of enabledApis) {
46
+ const key = `service_${api.split(".")[0]}`;
47
+ serviceEntries[key] = new ServiceusageService({
48
+ metadata: {
49
+ name: `${name}-${api.split(".")[0]}`,
50
+ ...(namespace && { namespace }),
51
+ labels: { ...commonLabels, "app.kubernetes.io/component": "service" },
52
+ },
53
+ resourceID: api,
54
+ });
55
+ }
56
+ const result = { project, auditConfig, ...serviceEntries };
57
+ if (owner) {
58
+ result.ownerIam = new IAMPolicyMember(mergeDefaults({
59
+ metadata: {
60
+ name: `${name}-owner`,
61
+ ...(namespace && { namespace }),
62
+ labels: { ...commonLabels, "app.kubernetes.io/component": "iam" },
63
+ },
64
+ member: owner,
65
+ role: "roles/owner",
66
+ resourceRef: {
67
+ apiVersion: "resourcemanager.cnrm.cloud.google.com/v1beta1",
68
+ kind: "Project",
69
+ name,
70
+ },
71
+ }, defs?.ownerIam));
72
+ }
73
+ if (loggingSinkDestination) {
74
+ result.loggingSink = new LogSink(mergeDefaults({
75
+ metadata: {
76
+ name: `${name}-audit-sink`,
77
+ ...(namespace && { namespace }),
78
+ labels: { ...commonLabels, "app.kubernetes.io/component": "logging" },
79
+ },
80
+ destination: loggingSinkDestination,
81
+ filter: loggingSinkFilter,
82
+ }, defs?.loggingSink));
83
+ }
84
+ return result;
85
+ }, "SecureProject");
@@ -0,0 +1,113 @@
1
+ /**
2
+ * VpcNetwork composite — ComputeNetwork + ComputeSubnetwork + ComputeFirewall + ComputeRouterNAT.
3
+ */
4
+ import { Composite, mergeDefaults } from "@intentius/chant";
5
+ import { VPCNetwork, Subnetwork, Firewall, Router, RouterNAT } from "../generated/index.js";
6
+ /**
7
+ * Create a VpcNetwork composite.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { VpcNetwork } from "@intentius/chant-lexicon-gcp";
12
+ *
13
+ * const { network, subnets, firewalls } = VpcNetwork({
14
+ * name: "my-vpc",
15
+ * subnets: [
16
+ * { name: "app", ipCidrRange: "10.0.0.0/24", region: "us-central1" },
17
+ * { name: "data", ipCidrRange: "10.0.1.0/24", region: "us-central1" },
18
+ * ],
19
+ * enableNat: true,
20
+ * natRegion: "us-central1",
21
+ * });
22
+ * ```
23
+ */
24
+ export const VpcNetwork = Composite((props) => {
25
+ const { name, autoCreateSubnetworks = false, subnets: subnetDefs = [], enableNat = false, natRegion, allowInternalTraffic = true, allowIapSsh = false, labels: extraLabels = {}, namespace, defaults: defs, } = props;
26
+ const commonLabels = {
27
+ "app.kubernetes.io/name": name,
28
+ "app.kubernetes.io/managed-by": "chant",
29
+ ...extraLabels,
30
+ };
31
+ const network = new VPCNetwork(mergeDefaults({
32
+ metadata: {
33
+ name,
34
+ ...(namespace && { namespace }),
35
+ labels: { ...commonLabels, "app.kubernetes.io/component": "network" },
36
+ },
37
+ autoCreateSubnetworks,
38
+ routingMode: "REGIONAL",
39
+ }, defs?.network));
40
+ // Spread subnets into named members (subnet_<name>) for Composite validation.
41
+ const subnetEntries = {};
42
+ for (const sub of subnetDefs) {
43
+ subnetEntries[`subnet_${sub.name}`] = new Subnetwork({
44
+ metadata: {
45
+ name: `${name}-${sub.name}`,
46
+ ...(namespace && { namespace }),
47
+ labels: { ...commonLabels, "app.kubernetes.io/component": "subnet" },
48
+ },
49
+ networkRef: { name },
50
+ ipCidrRange: sub.ipCidrRange,
51
+ region: sub.region,
52
+ privateIpGoogleAccess: sub.privateIpGoogleAccess ?? true,
53
+ ...(sub.secondaryIpRanges && sub.secondaryIpRanges.length > 0 && {
54
+ secondaryIpRange: sub.secondaryIpRanges,
55
+ }),
56
+ });
57
+ }
58
+ // Spread firewalls into named members for Composite validation.
59
+ const firewallEntries = {};
60
+ if (allowInternalTraffic) {
61
+ firewallEntries.firewallAllowInternal = new Firewall({
62
+ metadata: {
63
+ name: `${name}-allow-internal`,
64
+ ...(namespace && { namespace }),
65
+ labels: { ...commonLabels, "app.kubernetes.io/component": "firewall" },
66
+ },
67
+ networkRef: { name },
68
+ allow: [
69
+ { protocol: "tcp", ports: ["0-65535"] },
70
+ { protocol: "udp", ports: ["0-65535"] },
71
+ { protocol: "icmp" },
72
+ ],
73
+ sourceRanges: subnetDefs.map((s) => s.ipCidrRange),
74
+ });
75
+ }
76
+ if (allowIapSsh) {
77
+ firewallEntries.firewallAllowIapSsh = new Firewall({
78
+ metadata: {
79
+ name: `${name}-allow-iap-ssh`,
80
+ ...(namespace && { namespace }),
81
+ labels: { ...commonLabels, "app.kubernetes.io/component": "firewall" },
82
+ },
83
+ networkRef: { name },
84
+ allow: [{ protocol: "tcp", ports: ["22"] }],
85
+ sourceRanges: ["35.235.240.0/20"], // IAP IP range
86
+ });
87
+ }
88
+ const result = { network, ...subnetEntries, ...firewallEntries };
89
+ if (enableNat && natRegion) {
90
+ const routerName = `${name}-router`;
91
+ result.router = new Router(mergeDefaults({
92
+ metadata: {
93
+ name: routerName,
94
+ ...(namespace && { namespace }),
95
+ labels: { ...commonLabels, "app.kubernetes.io/component": "router" },
96
+ },
97
+ networkRef: { name },
98
+ region: natRegion,
99
+ }, defs?.router));
100
+ result.routerNat = new RouterNAT(mergeDefaults({
101
+ metadata: {
102
+ name: `${name}-nat`,
103
+ ...(namespace && { namespace }),
104
+ labels: { ...commonLabels, "app.kubernetes.io/component": "nat" },
105
+ },
106
+ routerRef: { name: routerName },
107
+ region: natRegion,
108
+ natIpAllocateOption: "AUTO_ONLY",
109
+ sourceSubnetworkIpRangesToNat: "ALL_SUBNETWORKS_ALL_IP_RANGES",
110
+ }, defs?.routerNat));
111
+ }
112
+ return result;
113
+ }, "VpcNetwork");
@@ -0,0 +1,28 @@
1
+ /**
2
+ * GCP lexicon coverage analysis.
3
+ */
4
+ import { computeCoverage, formatSummary, formatVerbose, checkThresholds, } from "@intentius/chant/codegen/coverage";
5
+ import { readFileSync } from "fs";
6
+ import { join, dirname } from "path";
7
+ import { fileURLToPath } from "url";
8
+ export { computeCoverage, overallPct, formatSummary, formatVerbose, checkThresholds, } from "@intentius/chant/codegen/coverage";
9
+ export async function analyzeGcpCoverage(opts) {
10
+ const pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
11
+ const lexiconPath = join(pkgDir, "src", "generated", "lexicon-gcp.json");
12
+ const content = readFileSync(lexiconPath, "utf-8");
13
+ const report = computeCoverage(content);
14
+ if (opts?.verbose) {
15
+ console.log(formatVerbose(report));
16
+ }
17
+ else {
18
+ console.log(formatSummary(report));
19
+ }
20
+ if (typeof opts?.minOverall === "number") {
21
+ const result = checkThresholds(report, { minOverallPct: opts.minOverall });
22
+ if (!result.ok) {
23
+ for (const v of result.violations)
24
+ console.error(` FAIL: ${v}`);
25
+ throw new Error("Coverage below threshold");
26
+ }
27
+ }
28
+ }