@intentius/chant-lexicon-k8s 0.0.14 → 0.0.16

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 (63) hide show
  1. package/dist/integrity.json +8 -4
  2. package/dist/manifest.json +1 -1
  3. package/dist/rules/latest-image-tag.ts +121 -0
  4. package/dist/rules/missing-resource-limits.ts +111 -0
  5. package/dist/rules/wk8204.ts +33 -1
  6. package/dist/rules/wk8304.ts +70 -0
  7. package/dist/rules/wk8305.ts +115 -0
  8. package/dist/rules/wk8306.ts +50 -0
  9. package/package.json +27 -24
  10. package/src/codegen/docs.ts +1 -1
  11. package/src/composites/adot-collector.ts +8 -2
  12. package/src/composites/agic-ingress.ts +148 -0
  13. package/src/composites/aks-external-dns-agent.ts +199 -0
  14. package/src/composites/alb-ingress.ts +2 -1
  15. package/src/composites/autoscaled-service.ts +25 -7
  16. package/src/composites/azure-disk-storage-class.ts +82 -0
  17. package/src/composites/azure-file-storage-class.ts +77 -0
  18. package/src/composites/azure-monitor-collector.ts +232 -0
  19. package/src/composites/batch-job.ts +36 -3
  20. package/src/composites/composites.test.ts +1060 -0
  21. package/src/composites/config-connector-context.ts +62 -0
  22. package/src/composites/configured-app.ts +6 -0
  23. package/src/composites/cron-workload.ts +6 -0
  24. package/src/composites/ebs-storage-class.ts +4 -4
  25. package/src/composites/external-dns-agent.ts +6 -0
  26. package/src/composites/filestore-storage-class.ts +79 -0
  27. package/src/composites/fluent-bit-agent.ts +5 -0
  28. package/src/composites/gce-ingress.ts +143 -0
  29. package/src/composites/gce-pd-storage-class.ts +85 -0
  30. package/src/composites/gke-external-dns-agent.ts +175 -0
  31. package/src/composites/gke-fluent-bit-agent.ts +219 -0
  32. package/src/composites/gke-gateway.ts +143 -0
  33. package/src/composites/gke-otel-collector.ts +229 -0
  34. package/src/composites/index.ts +31 -0
  35. package/src/composites/metrics-server.ts +1 -1
  36. package/src/composites/monitored-service.ts +6 -0
  37. package/src/composites/network-isolated-app.ts +6 -0
  38. package/src/composites/node-agent.ts +6 -0
  39. package/src/composites/security-context.ts +10 -0
  40. package/src/composites/sidecar-app.ts +6 -0
  41. package/src/composites/stateful-app.ts +4 -7
  42. package/src/composites/web-app.ts +4 -7
  43. package/src/composites/worker-pool.ts +4 -7
  44. package/src/composites/workload-identity-sa.ts +118 -0
  45. package/src/composites/workload-identity-service-account.ts +116 -0
  46. package/src/index.ts +20 -1
  47. package/src/lint/post-synth/post-synth.test.ts +362 -1
  48. package/src/lint/post-synth/wk8204.ts +33 -1
  49. package/src/lint/post-synth/wk8304.ts +70 -0
  50. package/src/lint/post-synth/wk8305.ts +115 -0
  51. package/src/lint/post-synth/wk8306.ts +50 -0
  52. package/src/lint/rules/latest-image-tag.ts +121 -0
  53. package/src/lint/rules/missing-resource-limits.ts +111 -0
  54. package/src/lint/rules/rules.test.ts +192 -0
  55. package/src/plugin.test.ts +2 -2
  56. package/src/plugin.ts +129 -209
  57. package/src/serializer.test.ts +120 -0
  58. package/src/serializer.ts +16 -4
  59. package/src/skills/chant-k8s-aks.md +146 -0
  60. package/src/skills/chant-k8s-gke.md +191 -0
  61. package/src/skills/kubernetes-patterns.md +183 -0
  62. package/src/skills/kubernetes-security.md +237 -0
  63. /package/{dist → src}/skills/chant-k8s-eks.md +0 -0
@@ -0,0 +1,232 @@
1
+ /**
2
+ * AzureMonitorCollector composite — DaemonSet + RBAC + ConfigMap for Azure Monitor / OTel collector.
3
+ *
4
+ * @aks Azure Monitor agent with OpenTelemetry collector config for
5
+ * Log Analytics workspace integration on AKS clusters.
6
+ */
7
+
8
+ export interface AzureMonitorCollectorProps {
9
+ /** Azure Log Analytics workspace ID. */
10
+ workspaceId: string;
11
+ /** AKS cluster name. */
12
+ clusterName: string;
13
+ /** Agent name (default: "azure-monitor-collector"). */
14
+ name?: string;
15
+ /** Collector image (default: "mcr.microsoft.com/azuremonitor/containerinsights/ciprod:3.1.35"). */
16
+ image?: string;
17
+ /** Namespace (default: "azure-monitor"). */
18
+ namespace?: string;
19
+ /** Additional labels. */
20
+ labels?: Record<string, string>;
21
+ /** CPU request (default: "100m"). */
22
+ cpuRequest?: string;
23
+ /** Memory request (default: "256Mi"). */
24
+ memoryRequest?: string;
25
+ /** CPU limit (default: "500m"). */
26
+ cpuLimit?: string;
27
+ /** Memory limit (default: "512Mi"). */
28
+ memoryLimit?: string;
29
+ /** Azure AD client ID for Workload Identity (adds azure.workload.identity annotations to ServiceAccount). */
30
+ clientId?: string;
31
+ }
32
+
33
+ export interface AzureMonitorCollectorResult {
34
+ daemonSet: Record<string, unknown>;
35
+ serviceAccount: Record<string, unknown>;
36
+ clusterRole: Record<string, unknown>;
37
+ clusterRoleBinding: Record<string, unknown>;
38
+ configMap: Record<string, unknown>;
39
+ }
40
+
41
+ /**
42
+ * Create an AzureMonitorCollector composite — returns prop objects for
43
+ * a DaemonSet, ServiceAccount, ClusterRole, ClusterRoleBinding, and ConfigMap.
44
+ *
45
+ * @aks
46
+ * @example
47
+ * ```ts
48
+ * import { AzureMonitorCollector } from "@intentius/chant-lexicon-k8s";
49
+ *
50
+ * const { daemonSet, serviceAccount, clusterRole, clusterRoleBinding, configMap } = AzureMonitorCollector({
51
+ * workspaceId: "00000000-0000-0000-0000-000000000000",
52
+ * clusterName: "my-aks-cluster",
53
+ * });
54
+ * ```
55
+ */
56
+ export function AzureMonitorCollector(props: AzureMonitorCollectorProps): AzureMonitorCollectorResult {
57
+ const {
58
+ workspaceId,
59
+ clusterName,
60
+ name = "azure-monitor-collector",
61
+ image = "mcr.microsoft.com/azuremonitor/containerinsights/ciprod:3.1.35",
62
+ namespace = "azure-monitor",
63
+ labels: extraLabels = {},
64
+ cpuRequest = "100m",
65
+ memoryRequest = "256Mi",
66
+ cpuLimit = "500m",
67
+ memoryLimit = "512Mi",
68
+ clientId,
69
+ } = props;
70
+
71
+ const saName = `${name}-sa`;
72
+ const clusterRoleName = `${name}-role`;
73
+ const bindingName = `${name}-binding`;
74
+ const configMapName = `${name}-config`;
75
+
76
+ const commonLabels: Record<string, string> = {
77
+ "app.kubernetes.io/name": name,
78
+ "app.kubernetes.io/managed-by": "chant",
79
+ ...extraLabels,
80
+ };
81
+
82
+ // Build OTel collector config YAML for Azure Monitor
83
+ const collectorConfig = `receivers:
84
+ otlp:
85
+ protocols:
86
+ grpc:
87
+ endpoint: 0.0.0.0:4317
88
+ http:
89
+ endpoint: 0.0.0.0:4318
90
+
91
+ processors:
92
+ batch:
93
+ timeout: 30s
94
+ send_batch_size: 8192
95
+
96
+ exporters:
97
+ azuremonitor:
98
+ connection_string: InstrumentationKey=\${APPINSIGHTS_INSTRUMENTATIONKEY}
99
+ endpoint: https://dc.services.visualstudio.com/v2/track
100
+ azuremonitor/logs:
101
+ workspace_id: ${workspaceId}
102
+ cluster_name: ${clusterName}
103
+
104
+ service:
105
+ pipelines:
106
+ metrics:
107
+ receivers: [otlp]
108
+ processors: [batch]
109
+ exporters: [azuremonitor]
110
+ traces:
111
+ receivers: [otlp]
112
+ processors: [batch]
113
+ exporters: [azuremonitor]
114
+ logs:
115
+ receivers: [otlp]
116
+ processors: [batch]
117
+ exporters: [azuremonitor/logs]
118
+ `;
119
+
120
+ const container: Record<string, unknown> = {
121
+ name,
122
+ image,
123
+ ports: [
124
+ { containerPort: 4317, name: "otlp-grpc" },
125
+ { containerPort: 4318, name: "otlp-http" },
126
+ ],
127
+ env: [
128
+ { name: "AKS_CLUSTER_NAME", value: clusterName },
129
+ { name: "WORKSPACE_ID", value: workspaceId },
130
+ ],
131
+ resources: {
132
+ requests: { cpu: cpuRequest, memory: memoryRequest },
133
+ limits: { cpu: cpuLimit, memory: memoryLimit },
134
+ },
135
+ volumeMounts: [
136
+ { name: "config", mountPath: "/etc/otel", readOnly: true },
137
+ ],
138
+ };
139
+
140
+ const daemonSetProps: Record<string, unknown> = {
141
+ metadata: {
142
+ name,
143
+ namespace,
144
+ labels: { ...commonLabels, "app.kubernetes.io/component": "agent" },
145
+ },
146
+ spec: {
147
+ selector: { matchLabels: { "app.kubernetes.io/name": name } },
148
+ template: {
149
+ metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
150
+ spec: {
151
+ serviceAccountName: saName,
152
+ containers: [container],
153
+ volumes: [
154
+ { name: "config", configMap: { name: configMapName } },
155
+ ],
156
+ tolerations: [{ operator: "Exists" }],
157
+ },
158
+ },
159
+ },
160
+ };
161
+
162
+ const saLabels: Record<string, string> = {
163
+ ...commonLabels,
164
+ "app.kubernetes.io/component": "agent",
165
+ };
166
+
167
+ if (clientId) {
168
+ saLabels["azure.workload.identity/use"] = "true";
169
+ }
170
+
171
+ const serviceAccountProps: Record<string, unknown> = {
172
+ metadata: {
173
+ name: saName,
174
+ namespace,
175
+ labels: saLabels,
176
+ ...(clientId ? { annotations: { "azure.workload.identity/client-id": clientId } } : {}),
177
+ },
178
+ };
179
+
180
+ const clusterRoleProps: Record<string, unknown> = {
181
+ metadata: {
182
+ name: clusterRoleName,
183
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
184
+ },
185
+ rules: [
186
+ { apiGroups: [""], resources: ["pods", "nodes", "endpoints"], verbs: ["get", "list", "watch"] },
187
+ { apiGroups: ["apps"], resources: ["replicasets"], verbs: ["get", "list", "watch"] },
188
+ { apiGroups: ["batch"], resources: ["jobs"], verbs: ["get", "list", "watch"] },
189
+ { apiGroups: [""], resources: ["nodes/proxy"], verbs: ["get"] },
190
+ { apiGroups: [""], resources: ["nodes/stats", "configmaps", "events"], verbs: ["create", "get"] },
191
+ { apiGroups: [""], resources: ["configmaps"], verbs: ["get", "update", "create"], resourceNames: ["otel-container-insight-clusterleader"] },
192
+ ],
193
+ };
194
+
195
+ const clusterRoleBindingProps: Record<string, unknown> = {
196
+ metadata: {
197
+ name: bindingName,
198
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
199
+ },
200
+ roleRef: {
201
+ apiGroup: "rbac.authorization.k8s.io",
202
+ kind: "ClusterRole",
203
+ name: clusterRoleName,
204
+ },
205
+ subjects: [
206
+ {
207
+ kind: "ServiceAccount",
208
+ name: saName,
209
+ namespace,
210
+ },
211
+ ],
212
+ };
213
+
214
+ const configMapProps: Record<string, unknown> = {
215
+ metadata: {
216
+ name: configMapName,
217
+ namespace,
218
+ labels: { ...commonLabels, "app.kubernetes.io/component": "config" },
219
+ },
220
+ data: {
221
+ "config.yaml": collectorConfig,
222
+ },
223
+ };
224
+
225
+ return {
226
+ daemonSet: daemonSetProps,
227
+ serviceAccount: serviceAccountProps,
228
+ clusterRole: clusterRoleProps,
229
+ clusterRoleBinding: clusterRoleBindingProps,
230
+ configMap: configMapProps,
231
+ };
232
+ }
@@ -5,6 +5,28 @@
5
5
  * seed tasks, backups). For scheduled workloads, use CronWorkload instead.
6
6
  */
7
7
 
8
+ import type { ContainerSecurityContext } from "./security-context";
9
+
10
+ /** Parse a K8s memory string (e.g. "256Mi", "1Gi") to bytes for comparison. */
11
+ function parseMemoryBytes(mem: string): number {
12
+ const match = mem.match(/^(\d+(?:\.\d+)?)\s*(Ki|Mi|Gi|Ti|k|M|G|T|[eE]\d+)?$/);
13
+ if (!match) return 0;
14
+ const value = parseFloat(match[1]);
15
+ const unit = match[2] ?? "";
16
+ const multipliers: Record<string, number> = {
17
+ "": 1, Ki: 1024, Mi: 1024 ** 2, Gi: 1024 ** 3, Ti: 1024 ** 4,
18
+ k: 1e3, M: 1e6, G: 1e9, T: 1e12,
19
+ };
20
+ if (unit.startsWith("e") || unit.startsWith("E")) return value * 10 ** parseInt(unit.slice(1));
21
+ return value * (multipliers[unit] ?? 1);
22
+ }
23
+
24
+ /** Parse a K8s CPU string (e.g. "500m", "1") to millicores for comparison. */
25
+ function parseCpuMillis(cpu: string): number {
26
+ if (cpu.endsWith("m")) return parseFloat(cpu.slice(0, -1));
27
+ return parseFloat(cpu) * 1000;
28
+ }
29
+
8
30
  export interface BatchJobProps {
9
31
  /** Job name — used in metadata and labels. */
10
32
  name: string;
@@ -44,6 +66,8 @@ export interface BatchJobProps {
44
66
  memoryLimit?: string;
45
67
  /** Environment variables for the container. */
46
68
  env?: Array<{ name: string; value: string }>;
69
+ /** Container security context (supports PSS restricted fields). */
70
+ securityContext?: ContainerSecurityContext;
47
71
  }
48
72
 
49
73
  export interface BatchJobResult {
@@ -85,12 +109,20 @@ export function BatchJob(props: BatchJobProps): BatchJobResult {
85
109
  labels: extraLabels = {},
86
110
  namespace,
87
111
  cpuRequest = "100m",
88
- memoryRequest = "128Mi",
89
- cpuLimit = "500m",
90
- memoryLimit = "256Mi",
112
+ memoryRequest: rawMemoryRequest = "128Mi",
113
+ cpuLimit: rawCpuLimit = "500m",
114
+ memoryLimit: rawMemoryLimit = "256Mi",
91
115
  env,
116
+ securityContext,
92
117
  } = props;
93
118
 
119
+ // Ensure limits >= requests (K8s rejects pods where request > limit).
120
+ const memoryRequest = rawMemoryRequest;
121
+ const memoryLimit = parseMemoryBytes(rawMemoryRequest) > parseMemoryBytes(rawMemoryLimit)
122
+ ? rawMemoryRequest : rawMemoryLimit;
123
+ const cpuLimit = parseCpuMillis(cpuRequest) > parseCpuMillis(rawCpuLimit)
124
+ ? cpuRequest : rawCpuLimit;
125
+
94
126
  const saName = `${name}-sa`;
95
127
  const roleName = `${name}-role`;
96
128
  const bindingName = `${name}-binding`;
@@ -117,6 +149,7 @@ export function BatchJob(props: BatchJobProps): BatchJobResult {
117
149
  requests: { cpu: cpuRequest, memory: memoryRequest },
118
150
  },
119
151
  ...(env && { env }),
152
+ ...(securityContext && { securityContext }),
120
153
  };
121
154
 
122
155
  const jobProps: Record<string, unknown> = {