@intentius/chant-lexicon-k8s 0.0.14 → 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.
Files changed (48) hide show
  1. package/dist/integrity.json +6 -3
  2. package/dist/manifest.json +1 -1
  3. package/dist/rules/wk8204.ts +33 -1
  4. package/dist/rules/wk8304.ts +70 -0
  5. package/dist/rules/wk8305.ts +115 -0
  6. package/dist/rules/wk8306.ts +50 -0
  7. package/package.json +27 -24
  8. package/src/codegen/docs.ts +1 -1
  9. package/src/composites/adot-collector.ts +8 -2
  10. package/src/composites/agic-ingress.ts +149 -0
  11. package/src/composites/alb-ingress.ts +2 -1
  12. package/src/composites/autoscaled-service.ts +25 -7
  13. package/src/composites/azure-disk-storage-class.ts +82 -0
  14. package/src/composites/azure-file-storage-class.ts +77 -0
  15. package/src/composites/azure-monitor-collector.ts +232 -0
  16. package/src/composites/batch-job.ts +36 -3
  17. package/src/composites/composites.test.ts +701 -0
  18. package/src/composites/config-connector-context.ts +62 -0
  19. package/src/composites/configured-app.ts +6 -0
  20. package/src/composites/cron-workload.ts +6 -0
  21. package/src/composites/ebs-storage-class.ts +4 -4
  22. package/src/composites/external-dns-agent.ts +6 -0
  23. package/src/composites/filestore-storage-class.ts +79 -0
  24. package/src/composites/fluent-bit-agent.ts +5 -0
  25. package/src/composites/gce-pd-storage-class.ts +85 -0
  26. package/src/composites/gke-gateway.ts +143 -0
  27. package/src/composites/index.ts +19 -0
  28. package/src/composites/metrics-server.ts +1 -1
  29. package/src/composites/monitored-service.ts +6 -0
  30. package/src/composites/network-isolated-app.ts +6 -0
  31. package/src/composites/node-agent.ts +6 -0
  32. package/src/composites/security-context.ts +10 -0
  33. package/src/composites/sidecar-app.ts +6 -0
  34. package/src/composites/stateful-app.ts +4 -7
  35. package/src/composites/web-app.ts +4 -7
  36. package/src/composites/worker-pool.ts +4 -7
  37. package/src/composites/workload-identity-sa.ts +118 -0
  38. package/src/composites/workload-identity-service-account.ts +116 -0
  39. package/src/index.ts +6 -1
  40. package/src/lint/post-synth/post-synth.test.ts +362 -1
  41. package/src/lint/post-synth/wk8204.ts +33 -1
  42. package/src/lint/post-synth/wk8304.ts +70 -0
  43. package/src/lint/post-synth/wk8305.ts +115 -0
  44. package/src/lint/post-synth/wk8306.ts +50 -0
  45. package/src/plugin.test.ts +2 -2
  46. package/src/plugin.ts +4 -1
  47. package/src/serializer.test.ts +120 -0
  48. package/src/serializer.ts +16 -4
@@ -6,6 +6,8 @@
6
6
  * PDB selectors match pod labels, and resource requests are set.
7
7
  */
8
8
 
9
+ import type { ContainerSecurityContext } from "./security-context";
10
+
9
11
  export interface AutoscaledServiceProps {
10
12
  /** Application name — used in metadata and labels. */
11
13
  name: string;
@@ -47,13 +49,8 @@ export interface AutoscaledServiceProps {
47
49
  command?: string[];
48
50
  args?: string[];
49
51
  }>;
50
- /** Pod security context. */
51
- securityContext?: {
52
- runAsNonRoot?: boolean;
53
- readOnlyRootFilesystem?: boolean;
54
- runAsUser?: number;
55
- runAsGroup?: number;
56
- };
52
+ /** Container security context (supports PSS restricted fields). */
53
+ securityContext?: ContainerSecurityContext;
57
54
  /** Termination grace period in seconds. */
58
55
  terminationGracePeriodSeconds?: number;
59
56
  /** Priority class name for pod scheduling. */
@@ -64,6 +61,14 @@ export interface AutoscaledServiceProps {
64
61
  namespace?: string;
65
62
  /** Environment variables for the container. */
66
63
  env?: Array<{ name: string; value: string }>;
64
+ /** Service account name for the pod. */
65
+ serviceAccountName?: string;
66
+ /** Volumes to attach to the pod. */
67
+ volumes?: Array<Record<string, unknown>>;
68
+ /** Volume mounts for the primary container. */
69
+ volumeMounts?: Array<Record<string, unknown>>;
70
+ /** Convenience: auto-generate emptyDir volumes + mounts for writable temp dirs (e.g. ["/tmp", "/var/cache/nginx"]). */
71
+ tmpDirs?: string[];
67
72
  }
68
73
 
69
74
  export interface AutoscaledServiceResult {
@@ -114,6 +119,10 @@ export function AutoscaledService(props: AutoscaledServiceProps): AutoscaledServ
114
119
  labels: extraLabels = {},
115
120
  namespace,
116
121
  env,
122
+ serviceAccountName,
123
+ volumes: explicitVolumes = [],
124
+ volumeMounts: explicitMounts = [],
125
+ tmpDirs = [],
117
126
  } = props;
118
127
 
119
128
  const commonLabels: Record<string, string> = {
@@ -137,6 +146,12 @@ export function AutoscaledService(props: AutoscaledServiceProps): AutoscaledServ
137
146
  }];
138
147
  })();
139
148
 
149
+ // Generate emptyDir volumes/mounts from tmpDirs, then merge with explicit
150
+ const tmpVolumes = tmpDirs.map((_, i) => ({ name: `tmp-${i}`, emptyDir: {} }));
151
+ const tmpMounts = tmpDirs.map((dir, i) => ({ name: `tmp-${i}`, mountPath: dir }));
152
+ const allVolumes = [...explicitVolumes, ...tmpVolumes];
153
+ const allMounts = [...explicitMounts, ...tmpMounts];
154
+
140
155
  const resources: Record<string, unknown> = {
141
156
  requests: { cpu: cpuRequest, memory: memoryRequest },
142
157
  ...(cpuLimit || memoryLimit
@@ -179,6 +194,7 @@ export function AutoscaledService(props: AutoscaledServiceProps): AutoscaledServ
179
194
  },
180
195
  ...(env && { env }),
181
196
  ...(securityContext && { securityContext }),
197
+ ...(allMounts.length > 0 && { volumeMounts: allMounts }),
182
198
  },
183
199
  ],
184
200
  ...(initContainers && {
@@ -192,6 +208,8 @@ export function AutoscaledService(props: AutoscaledServiceProps): AutoscaledServ
192
208
  ...(topologyConstraints && { topologySpreadConstraints: topologyConstraints }),
193
209
  ...(terminationGracePeriodSeconds !== undefined && { terminationGracePeriodSeconds }),
194
210
  ...(priorityClassName && { priorityClassName }),
211
+ ...(serviceAccountName && { serviceAccountName }),
212
+ ...(allVolumes.length > 0 && { volumes: allVolumes }),
195
213
  },
196
214
  },
197
215
  },
@@ -0,0 +1,82 @@
1
+ /**
2
+ * AzureDiskStorageClass composite — StorageClass for Azure Disk CSI driver.
3
+ *
4
+ * @aks Creates a StorageClass with the `disk.csi.azure.com` provisioner.
5
+ */
6
+
7
+ export interface AzureDiskStorageClassProps {
8
+ /** StorageClass name. */
9
+ name: string;
10
+ /** Azure Disk SKU name (default: "Premium_LRS"). */
11
+ skuName?: string;
12
+ /** OS disk caching mode (default: "ReadOnly"). */
13
+ cachingMode?: string;
14
+ /** Network access policy (default: "AllowAll"). */
15
+ networkAccessPolicy?: string;
16
+ /** Reclaim policy (default: "Delete"). */
17
+ reclaimPolicy?: string;
18
+ /** Volume binding mode (default: "WaitForFirstConsumer"). */
19
+ volumeBindingMode?: string;
20
+ /** Allow volume expansion (default: true). */
21
+ allowVolumeExpansion?: boolean;
22
+ /** Additional labels. */
23
+ labels?: Record<string, string>;
24
+ }
25
+
26
+ export interface AzureDiskStorageClassResult {
27
+ storageClass: Record<string, unknown>;
28
+ }
29
+
30
+ /**
31
+ * Create an AzureDiskStorageClass composite — returns prop objects for
32
+ * a StorageClass with the Azure Disk CSI provisioner.
33
+ *
34
+ * @aks
35
+ * @example
36
+ * ```ts
37
+ * import { AzureDiskStorageClass } from "@intentius/chant-lexicon-k8s";
38
+ *
39
+ * const { storageClass } = AzureDiskStorageClass({
40
+ * name: "premium-disk",
41
+ * skuName: "Premium_LRS",
42
+ * });
43
+ * ```
44
+ */
45
+ export function AzureDiskStorageClass(props: AzureDiskStorageClassProps): AzureDiskStorageClassResult {
46
+ const {
47
+ name,
48
+ skuName = "Premium_LRS",
49
+ cachingMode = "ReadOnly",
50
+ networkAccessPolicy = "AllowAll",
51
+ reclaimPolicy = "Delete",
52
+ volumeBindingMode = "WaitForFirstConsumer",
53
+ allowVolumeExpansion = true,
54
+ labels: extraLabels = {},
55
+ } = props;
56
+
57
+ const commonLabels: Record<string, string> = {
58
+ "app.kubernetes.io/name": name,
59
+ "app.kubernetes.io/managed-by": "chant",
60
+ ...extraLabels,
61
+ };
62
+
63
+ const parameters: Record<string, string> = {
64
+ skuName,
65
+ cachingMode,
66
+ networkAccessPolicy,
67
+ };
68
+
69
+ const storageClassProps: Record<string, unknown> = {
70
+ metadata: {
71
+ name,
72
+ labels: { ...commonLabels, "app.kubernetes.io/component": "storage" },
73
+ },
74
+ provisioner: "disk.csi.azure.com",
75
+ parameters,
76
+ reclaimPolicy,
77
+ volumeBindingMode,
78
+ allowVolumeExpansion,
79
+ };
80
+
81
+ return { storageClass: storageClassProps };
82
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * AzureFileStorageClass composite — StorageClass for Azure Files CSI driver.
3
+ *
4
+ * @aks Creates a StorageClass with the `file.csi.azure.com` provisioner.
5
+ * Azure Files provides ReadWriteMany access mode (shared across pods/nodes).
6
+ */
7
+
8
+ export interface AzureFileStorageClassProps {
9
+ /** StorageClass name. */
10
+ name: string;
11
+ /** Azure Files SKU name (default: "Premium_LRS"). */
12
+ skuName?: string;
13
+ /** Protocol for Azure Files (default: "smb"). */
14
+ protocol?: string;
15
+ /** Specific Azure file share name (optional; dynamically provisioned if omitted). */
16
+ shareName?: string;
17
+ /** Reclaim policy (default: "Delete"). */
18
+ reclaimPolicy?: string;
19
+ /** Additional labels. */
20
+ labels?: Record<string, string>;
21
+ }
22
+
23
+ export interface AzureFileStorageClassResult {
24
+ storageClass: Record<string, unknown>;
25
+ }
26
+
27
+ /**
28
+ * Create an AzureFileStorageClass composite — returns prop objects for
29
+ * a StorageClass with the Azure Files CSI provisioner.
30
+ *
31
+ * @aks
32
+ * @example
33
+ * ```ts
34
+ * import { AzureFileStorageClass } from "@intentius/chant-lexicon-k8s";
35
+ *
36
+ * const { storageClass } = AzureFileStorageClass({
37
+ * name: "azure-files-shared",
38
+ * skuName: "Premium_LRS",
39
+ * protocol: "nfs",
40
+ * });
41
+ * ```
42
+ */
43
+ export function AzureFileStorageClass(props: AzureFileStorageClassProps): AzureFileStorageClassResult {
44
+ const {
45
+ name,
46
+ skuName = "Premium_LRS",
47
+ protocol = "smb",
48
+ shareName,
49
+ reclaimPolicy = "Delete",
50
+ labels: extraLabels = {},
51
+ } = props;
52
+
53
+ const commonLabels: Record<string, string> = {
54
+ "app.kubernetes.io/name": name,
55
+ "app.kubernetes.io/managed-by": "chant",
56
+ ...extraLabels,
57
+ };
58
+
59
+ const parameters: Record<string, string> = {
60
+ skuName,
61
+ protocol,
62
+ };
63
+
64
+ if (shareName) parameters.shareName = shareName;
65
+
66
+ const storageClassProps: Record<string, unknown> = {
67
+ metadata: {
68
+ name,
69
+ labels: { ...commonLabels, "app.kubernetes.io/component": "storage" },
70
+ },
71
+ provisioner: "file.csi.azure.com",
72
+ parameters,
73
+ reclaimPolicy,
74
+ };
75
+
76
+ return { storageClass: storageClassProps };
77
+ }
@@ -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:latest"). */
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:latest",
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> = {