timonel 3.1.1 → 3.1.2

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 (83) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +323 -695
  3. package/dist/cli.js +275 -15
  4. package/dist/index.d.ts +5 -1
  5. package/dist/index.js +12 -0
  6. package/dist/lib/helm.d.ts +471 -0
  7. package/dist/lib/helm.js +483 -0
  8. package/dist/lib/helmChartWriter.d.ts +157 -0
  9. package/dist/lib/helmChartWriter.js +171 -1
  10. package/dist/lib/policy/configurationLoader.d.ts +132 -0
  11. package/dist/lib/policy/configurationLoader.js +132 -0
  12. package/dist/lib/policy/errorContextGenerator.d.ts +89 -0
  13. package/dist/lib/policy/errorContextGenerator.js +99 -2
  14. package/dist/lib/policy/errors.d.ts +35 -0
  15. package/dist/lib/policy/errors.js +36 -0
  16. package/dist/lib/policy/index.d.ts +9 -0
  17. package/dist/lib/policy/index.js +16 -0
  18. package/dist/lib/policy/parallelExecutor.d.ts +90 -0
  19. package/dist/lib/policy/parallelExecutor.js +86 -3
  20. package/dist/lib/policy/pluginLoader.d.ts +92 -0
  21. package/dist/lib/policy/pluginLoader.js +92 -1
  22. package/dist/lib/policy/pluginRegistry.d.ts +54 -0
  23. package/dist/lib/policy/pluginRegistry.js +56 -0
  24. package/dist/lib/policy/policyEngine.d.ts +137 -0
  25. package/dist/lib/policy/policyEngine.js +191 -5
  26. package/dist/lib/policy/resultAggregator.d.ts +46 -0
  27. package/dist/lib/policy/resultAggregator.js +69 -1
  28. package/dist/lib/policy/resultFormatter.d.ts +88 -0
  29. package/dist/lib/policy/resultFormatter.js +101 -0
  30. package/dist/lib/policy/types.d.ts +136 -0
  31. package/dist/lib/policy/types.js +8 -0
  32. package/dist/lib/policy/validationCache.d.ts +146 -0
  33. package/dist/lib/policy/validationCache.js +142 -6
  34. package/dist/lib/resources/baseResourceProvider.d.ts +45 -0
  35. package/dist/lib/resources/baseResourceProvider.js +48 -1
  36. package/dist/lib/resources/cloud/aws/awsResources.d.ts +192 -0
  37. package/dist/lib/resources/cloud/aws/awsResources.js +163 -1
  38. package/dist/lib/resources/cloud/aws/karpenterResources.d.ts +131 -0
  39. package/dist/lib/resources/cloud/aws/karpenterResources.js +77 -0
  40. package/dist/lib/rutter.d.ts +381 -3
  41. package/dist/lib/rutter.js +439 -28
  42. package/dist/lib/security.d.ts +123 -0
  43. package/dist/lib/security.js +162 -4
  44. package/dist/lib/templates/flexible-subchart.d.ts +52 -0
  45. package/dist/lib/templates/flexible-subchart.js +70 -0
  46. package/dist/lib/templates/umbrella-chart.d.ts +27 -0
  47. package/dist/lib/templates/umbrella-chart.js +89 -0
  48. package/dist/lib/types.d.ts +26 -0
  49. package/dist/lib/umbrella.d.ts +23 -0
  50. package/dist/lib/umbrella.js +23 -0
  51. package/dist/lib/umbrellaRutter.d.ts +75 -0
  52. package/dist/lib/umbrellaRutter.js +82 -2
  53. package/dist/lib/utils/envVarsLoader.d.ts +49 -0
  54. package/dist/lib/utils/envVarsLoader.js +53 -0
  55. package/dist/lib/utils/helmConstructSerializer.d.ts +17 -0
  56. package/dist/lib/utils/helmConstructSerializer.js +22 -0
  57. package/dist/lib/utils/helmControlStructures.d.ts +194 -0
  58. package/dist/lib/utils/helmControlStructures.js +180 -0
  59. package/dist/lib/utils/helmHelpers/envHelpers.d.ts +13 -0
  60. package/dist/lib/utils/helmHelpers/envHelpers.js +13 -0
  61. package/dist/lib/utils/helmHelpers/gitopsHelpers.d.ts +13 -0
  62. package/dist/lib/utils/helmHelpers/gitopsHelpers.js +13 -0
  63. package/dist/lib/utils/helmHelpers/index.d.ts +74 -0
  64. package/dist/lib/utils/helmHelpers/index.js +85 -1
  65. package/dist/lib/utils/helmHelpers/observabilityHelpers.d.ts +13 -0
  66. package/dist/lib/utils/helmHelpers/observabilityHelpers.js +13 -0
  67. package/dist/lib/utils/helmHelpers/types.d.ts +23 -0
  68. package/dist/lib/utils/helmHelpers/types.js +4 -0
  69. package/dist/lib/utils/helmHelpers/validationHelpers.d.ts +13 -0
  70. package/dist/lib/utils/helmHelpers/validationHelpers.js +13 -0
  71. package/dist/lib/utils/helmHelpers.d.ts +62 -0
  72. package/dist/lib/utils/helmHelpers.js +77 -0
  73. package/dist/lib/utils/helmYamlSerializer.d.ts +77 -0
  74. package/dist/lib/utils/helmYamlSerializer.js +398 -21
  75. package/dist/lib/utils/logger.d.ts +153 -0
  76. package/dist/lib/utils/logger.js +170 -2
  77. package/dist/lib/utils/valuesRef.d.ts +181 -50
  78. package/dist/lib/utils/valuesRef.js +168 -170
  79. package/dist/lib/validation/inputValidator.d.ts +45 -0
  80. package/dist/lib/validation/inputValidator.js +67 -2
  81. package/dist/types/index.d.ts +34 -0
  82. package/dist/types/index.js +3 -0
  83. package/package.json +31 -38
@@ -1,70 +1,253 @@
1
1
  import type { ApiObject } from 'cdk8s';
2
2
  import * as kplus from 'cdk8s-plus-33';
3
3
  import { BaseResourceProvider } from '../../baseResourceProvider.js';
4
+ /**
5
+ * AWS-specific Kubernetes resources provider
6
+ * Handles AWS integrations like EBS, EFS, ALB, IRSA, and other AWS services
7
+ *
8
+ * @since 2.8.0+
9
+ */
4
10
  export declare class AWSResources extends BaseResourceProvider {
5
11
  private static readonly STORAGE_API_VERSION;
12
+ /**
13
+ * Creates an AWS EBS StorageClass
14
+ * @param spec - EBS StorageClass specification
15
+ * @returns Created StorageClass ApiObject
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * awsResources.addEBSStorageClass({
20
+ * name: 'fast-ebs',
21
+ * volumeType: 'gp3',
22
+ * encrypted: true,
23
+ * allowVolumeExpansion: true
24
+ * });
25
+ * ```
26
+ *
27
+ * @since 2.8.0+
28
+ */
6
29
  addEBSStorageClass(spec: AWSEBSStorageClassSpec): ApiObject;
30
+ /**
31
+ * Creates an AWS EFS StorageClass
32
+ * @param spec - EFS StorageClass specification
33
+ * @returns Created StorageClass ApiObject
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * awsResources.addEFSStorageClass({
38
+ * name: 'efs-storage',
39
+ * fileSystemId: 'fs-12345678',
40
+ * directoryPerms: '0755'
41
+ * });
42
+ * ```
43
+ *
44
+ * @since 2.8.0+
45
+ */
7
46
  addEFSStorageClass(spec: AWSEFSStorageClassSpec): ApiObject;
47
+ /**
48
+ * Creates an AWS IRSA (IAM Roles for Service Accounts) ServiceAccount
49
+ * @param spec - IRSA ServiceAccount specification
50
+ * @returns Created ServiceAccount ApiObject
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * awsResources.addIRSAServiceAccount({
55
+ * name: 'aws-service-account',
56
+ * roleArn: 'arn:aws:iam::123456789012:role/MyRole'
57
+ * });
58
+ * ```
59
+ *
60
+ * @since 2.8.0+
61
+ */
8
62
  addIRSAServiceAccount(spec: AWSIRSAServiceAccountSpec): kplus.ServiceAccount;
63
+ /**
64
+ * Creates an AWS ALB Ingress
65
+ * @param spec - ALB Ingress specification
66
+ * @returns Created Ingress ApiObject
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * awsResources.addALBIngress({
71
+ * name: 'web-ingress',
72
+ * rules: [{
73
+ * paths: [{
74
+ * path: '/',
75
+ * pathType: 'Prefix',
76
+ * backend: { service: { name: 'web-service', port: { number: 80 } } }
77
+ * }]
78
+ * }],
79
+ * scheme: 'internet-facing'
80
+ * });
81
+ * ```
82
+ *
83
+ * @since 2.8.0+
84
+ */
9
85
  addALBIngress(spec: AWSALBIngressSpec): kplus.Ingress;
86
+ /**
87
+ * Validates Ingress paths format according to Kubernetes specification
88
+ * @param rules - Ingress rules to validate
89
+ * @private
90
+ * @since 2.8.0+
91
+ */
10
92
  private validateIngressPaths;
93
+ /**
94
+ * Validates a single Ingress rule
95
+ * @param rule - Ingress rule to validate
96
+ * @private
97
+ * @since 2.8.0+
98
+ */
11
99
  private validateIngressRule;
100
+ /**
101
+ * Validates a single Ingress path
102
+ * @param pathRule - Path rule to validate
103
+ * @private
104
+ * @since 2.8.0+
105
+ */
12
106
  private validateIngressPath;
107
+ /**
108
+ * Validates path format
109
+ * @param path - Path to validate
110
+ * @private
111
+ * @since 2.5.0
112
+ */
13
113
  private validatePathFormat;
114
+ /**
115
+ * Validates path type
116
+ * @param pathType - Path type to validate
117
+ * @private
118
+ * @since 2.5.0
119
+ */
14
120
  private validatePathType;
121
+ /**
122
+ * Validates backend configuration
123
+ * @param backend - Backend to validate
124
+ * @private
125
+ * @since 2.5.0
126
+ */
15
127
  private validateBackend;
128
+ /**
129
+ * Validates StorageClass provisioner is present and valid
130
+ * @param provisioner - Provisioner string to validate
131
+ * @param storageType - Type of storage (for error messages)
132
+ * @private
133
+ * @since 2.5.0
134
+ */
16
135
  private validateStorageClassProvisioner;
136
+ /**
137
+ * Validates AWS IAM Role ARN format
138
+ * @param roleArn - Role ARN to validate
139
+ */
17
140
  private validateRoleArn;
141
+ /**
142
+ * Builds ALB-specific annotations
143
+ * @param spec - ALB Ingress specification
144
+ * @returns ALB annotations
145
+ */
18
146
  private buildALBAnnotations;
147
+ /**
148
+ * Creates a ServiceAccount with ECR access annotations
149
+ * @param spec - ECR ServiceAccount specification
150
+ * @returns Created ServiceAccount ApiObject
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * awsResources.addECRServiceAccount({
155
+ * name: 'ecr-service-account',
156
+ * roleArn: 'arn:aws:iam::123456789012:role/ECRAccessRole'
157
+ * });
158
+ * ```
159
+ *
160
+ * @since 2.8.0+
161
+ */
19
162
  addECRServiceAccount(spec: AWSECRServiceAccountSpec): kplus.ServiceAccount;
20
163
  }
164
+ /** Configuration for an AWS EBS CSI StorageClass. */
21
165
  export interface AWSEBSStorageClassSpec {
166
+ /** Kubernetes StorageClass name. */
22
167
  name: string;
168
+ /** EBS volume type. Defaults to `gp3`. */
23
169
  volumeType?: 'gp2' | 'gp3' | 'io1' | 'io2' | 'sc1' | 'st1';
170
+ /** Whether dynamically provisioned volumes should be encrypted. */
24
171
  encrypted?: boolean;
172
+ /** Requested IOPS for volume types that support explicit IOPS. */
25
173
  iops?: number;
174
+ /** Requested throughput in MiB/s for volume types that support it. */
26
175
  throughput?: number;
176
+ /** Filesystem type passed to the CSI provisioner. */
27
177
  fsType?: string;
178
+ /** Kubernetes reclaim policy. */
28
179
  reclaimPolicy?: 'Delete' | 'Retain';
180
+ /** Whether PVCs may expand the provisioned volume. */
29
181
  allowVolumeExpansion?: boolean;
182
+ /** StorageClass volume binding mode. */
30
183
  volumeBindingMode?: 'Immediate' | 'WaitForFirstConsumer';
184
+ /** Optional Kubernetes labels. */
31
185
  labels?: Record<string, string>;
186
+ /** Optional Kubernetes annotations. */
32
187
  annotations?: Record<string, string>;
33
188
  }
189
+ /** Configuration for an AWS EFS CSI StorageClass. */
34
190
  export interface AWSEFSStorageClassSpec {
191
+ /** Kubernetes StorageClass name. */
35
192
  name: string;
193
+ /** EFS filesystem identifier used by the CSI provisioner. */
36
194
  fileSystemId?: string;
195
+ /** Permissions applied to dynamically created access-point directories. */
37
196
  directoryPerms?: string;
197
+ /** Start of the POSIX group ID allocation range. */
38
198
  gidRangeStart?: number;
199
+ /** End of the POSIX group ID allocation range. */
39
200
  gidRangeEnd?: number;
201
+ /** Base path for dynamically provisioned directories. */
40
202
  basePath?: string;
203
+ /** Kubernetes reclaim policy. */
41
204
  reclaimPolicy?: 'Delete' | 'Retain';
205
+ /** StorageClass volume binding mode. */
42
206
  volumeBindingMode?: 'Immediate' | 'WaitForFirstConsumer';
207
+ /** Optional Kubernetes labels. */
43
208
  labels?: Record<string, string>;
209
+ /** Optional Kubernetes annotations. */
44
210
  annotations?: Record<string, string>;
45
211
  }
212
+ /** Configuration for an IRSA-enabled cdk8s-plus ServiceAccount. */
46
213
  export interface AWSIRSAServiceAccountSpec {
214
+ /** Kubernetes ServiceAccount name. */
47
215
  name: string;
216
+ /** IAM role ARN written to the IRSA annotation. */
48
217
  roleArn: string;
218
+ /** Whether Kubernetes should automount the service-account token. */
49
219
  automountServiceAccountToken?: boolean;
220
+ /** Existing image pull secrets referenced by name. */
50
221
  imagePullSecrets?: Array<{
51
222
  name: string;
52
223
  }>;
224
+ /** Optional Kubernetes labels. */
53
225
  labels?: Record<string, string>;
226
+ /** Additional annotations merged with the IRSA role annotation. */
54
227
  annotations?: Record<string, string>;
55
228
  }
229
+ /** Configuration for an ECR-oriented IRSA ServiceAccount. */
56
230
  export interface AWSECRServiceAccountSpec {
231
+ /** Kubernetes ServiceAccount name. */
57
232
  name: string;
233
+ /** IAM role ARN written to the IRSA annotation. */
58
234
  roleArn: string;
235
+ /** Whether Kubernetes should automount the service-account token. */
59
236
  automountServiceAccountToken?: boolean;
237
+ /** Existing image pull secrets referenced by name. */
60
238
  imagePullSecrets?: Array<{
61
239
  name: string;
62
240
  }>;
241
+ /** Optional Kubernetes labels. */
63
242
  labels?: Record<string, string>;
243
+ /** Additional Kubernetes annotations. */
64
244
  annotations?: Record<string, string>;
65
245
  }
246
+ /** Configuration for an AWS Load Balancer Controller-backed Ingress. */
66
247
  export interface AWSALBIngressSpec {
248
+ /** Kubernetes Ingress name. */
67
249
  name: string;
250
+ /** Host/path routing rules added to the Ingress. */
68
251
  rules: Array<{
69
252
  host?: string;
70
253
  paths: Array<{
@@ -81,16 +264,25 @@ export interface AWSALBIngressSpec {
81
264
  };
82
265
  }>;
83
266
  }>;
267
+ /** Optional TLS secret references and host lists. */
84
268
  tls?: Array<{
85
269
  hosts?: string[];
86
270
  secretName?: string;
87
271
  }>;
272
+ /** ALB exposure scheme. */
88
273
  scheme?: 'internet-facing' | 'internal';
274
+ /** ALB target registration mode. */
89
275
  targetType?: 'ip' | 'instance';
276
+ /** ACM certificate ARN added to the controller annotations. */
90
277
  certificateArn?: string;
278
+ /** Whether to request HTTP-to-HTTPS redirection on port 443. */
91
279
  sslRedirect?: boolean;
280
+ /** ALB health check path. */
92
281
  healthCheckPath?: string;
282
+ /** Kubernetes IngressClass name. Defaults to `alb`. */
93
283
  ingressClassName?: string;
284
+ /** Optional Kubernetes labels. */
94
285
  labels?: Record<string, string>;
286
+ /** Additional controller or Kubernetes annotations. */
95
287
  annotations?: Record<string, string>;
96
288
  }
@@ -1,6 +1,29 @@
1
1
  import * as kplus from 'cdk8s-plus-33';
2
2
  import { BaseResourceProvider } from '../../baseResourceProvider.js';
3
+ /**
4
+ * AWS-specific Kubernetes resources provider
5
+ * Handles AWS integrations like EBS, EFS, ALB, IRSA, and other AWS services
6
+ *
7
+ * @since 2.8.0+
8
+ */
3
9
  export class AWSResources extends BaseResourceProvider {
10
+ /**
11
+ * Creates an AWS EBS StorageClass
12
+ * @param spec - EBS StorageClass specification
13
+ * @returns Created StorageClass ApiObject
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * awsResources.addEBSStorageClass({
18
+ * name: 'fast-ebs',
19
+ * volumeType: 'gp3',
20
+ * encrypted: true,
21
+ * allowVolumeExpansion: true
22
+ * });
23
+ * ```
24
+ *
25
+ * @since 2.8.0+
26
+ */
4
27
  addEBSStorageClass(spec) {
5
28
  const parameters = {
6
29
  type: spec.volumeType ?? 'gp3',
@@ -17,9 +40,26 @@ export class AWSResources extends BaseResourceProvider {
17
40
  allowVolumeExpansion: spec.allowVolumeExpansion ?? true,
18
41
  volumeBindingMode: spec.volumeBindingMode ?? 'WaitForFirstConsumer',
19
42
  };
43
+ // Validate EBS-specific provisioner
20
44
  this.validateStorageClassProvisioner(provisioner, 'EBS');
21
45
  return this.createRootLevelApiObject(spec.name, AWSResources.STORAGE_API_VERSION, 'StorageClass', fields, spec.labels, spec.annotations);
22
46
  }
47
+ /**
48
+ * Creates an AWS EFS StorageClass
49
+ * @param spec - EFS StorageClass specification
50
+ * @returns Created StorageClass ApiObject
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * awsResources.addEFSStorageClass({
55
+ * name: 'efs-storage',
56
+ * fileSystemId: 'fs-12345678',
57
+ * directoryPerms: '0755'
58
+ * });
59
+ * ```
60
+ *
61
+ * @since 2.8.0+
62
+ */
23
63
  addEFSStorageClass(spec) {
24
64
  const parameters = {
25
65
  ...(spec.fileSystemId ? { fileSystemId: spec.fileSystemId } : {}),
@@ -35,9 +75,25 @@ export class AWSResources extends BaseResourceProvider {
35
75
  reclaimPolicy: spec.reclaimPolicy ?? 'Delete',
36
76
  volumeBindingMode: spec.volumeBindingMode ?? 'Immediate',
37
77
  };
78
+ // Validate EFS-specific provisioner
38
79
  this.validateStorageClassProvisioner(provisioner, 'EFS');
39
80
  return this.createRootLevelApiObject(spec.name, AWSResources.STORAGE_API_VERSION, 'StorageClass', fields, spec.labels, spec.annotations);
40
81
  }
82
+ /**
83
+ * Creates an AWS IRSA (IAM Roles for Service Accounts) ServiceAccount
84
+ * @param spec - IRSA ServiceAccount specification
85
+ * @returns Created ServiceAccount ApiObject
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * awsResources.addIRSAServiceAccount({
90
+ * name: 'aws-service-account',
91
+ * roleArn: 'arn:aws:iam::123456789012:role/MyRole'
92
+ * });
93
+ * ```
94
+ *
95
+ * @since 2.8.0+
96
+ */
41
97
  addIRSAServiceAccount(spec) {
42
98
  this.validateRoleArn(spec.roleArn);
43
99
  const annotations = {
@@ -52,6 +108,7 @@ export class AWSResources extends BaseResourceProvider {
52
108
  },
53
109
  automountToken: spec.automountServiceAccountToken ?? true,
54
110
  });
111
+ // Add image pull secrets if specified
55
112
  if (spec.imagePullSecrets) {
56
113
  spec.imagePullSecrets.forEach((secret) => {
57
114
  serviceAccount.addSecret(kplus.Secret.fromSecretName(this.chart, `${spec.name}-secret-${secret.name}`, secret.name));
@@ -59,7 +116,30 @@ export class AWSResources extends BaseResourceProvider {
59
116
  }
60
117
  return serviceAccount;
61
118
  }
119
+ /**
120
+ * Creates an AWS ALB Ingress
121
+ * @param spec - ALB Ingress specification
122
+ * @returns Created Ingress ApiObject
123
+ *
124
+ * @example
125
+ * ```typescript
126
+ * awsResources.addALBIngress({
127
+ * name: 'web-ingress',
128
+ * rules: [{
129
+ * paths: [{
130
+ * path: '/',
131
+ * pathType: 'Prefix',
132
+ * backend: { service: { name: 'web-service', port: { number: 80 } } }
133
+ * }]
134
+ * }],
135
+ * scheme: 'internet-facing'
136
+ * });
137
+ * ```
138
+ *
139
+ * @since 2.8.0+
140
+ */
62
141
  addALBIngress(spec) {
142
+ // Validate ingress paths format
63
143
  this.validateIngressPaths(spec.rules);
64
144
  const annotations = this.buildALBAnnotations(spec);
65
145
  const ingress = new kplus.Ingress(this.chart, spec.name, {
@@ -70,15 +150,21 @@ export class AWSResources extends BaseResourceProvider {
70
150
  },
71
151
  className: spec.ingressClassName ?? 'alb',
72
152
  });
153
+ // Add rules to the ingress
73
154
  spec.rules.forEach((rule) => {
74
155
  rule.paths.forEach((path) => {
75
- const service = new kplus.Service(this.chart, `${spec.name}-service-ref-${path.backend.service.name}`, {});
156
+ // Create a service reference for the backend - we need to create a Service instance that references the existing service
157
+ const service = new kplus.Service(this.chart, `${spec.name}-service-ref-${path.backend.service.name}`, {
158
+ // This creates a reference to an existing service by name
159
+ // The service should already exist in the cluster
160
+ });
76
161
  const backend = kplus.IngressBackend.fromService(service, {
77
162
  port: path.backend.service.port.number || parseInt(path.backend.service.port.name || '80'),
78
163
  });
79
164
  ingress.addRule(path.path, backend, path.pathType);
80
165
  });
81
166
  });
167
+ // Add TLS configuration if specified
82
168
  if (spec.tls) {
83
169
  spec.tls.forEach((tlsConfig) => {
84
170
  if (tlsConfig.secretName && tlsConfig.hosts) {
@@ -93,11 +179,23 @@ export class AWSResources extends BaseResourceProvider {
93
179
  }
94
180
  return ingress;
95
181
  }
182
+ /**
183
+ * Validates Ingress paths format according to Kubernetes specification
184
+ * @param rules - Ingress rules to validate
185
+ * @private
186
+ * @since 2.8.0+
187
+ */
96
188
  validateIngressPaths(rules) {
97
189
  for (const rule of rules) {
98
190
  this.validateIngressRule(rule);
99
191
  }
100
192
  }
193
+ /**
194
+ * Validates a single Ingress rule
195
+ * @param rule - Ingress rule to validate
196
+ * @private
197
+ * @since 2.8.0+
198
+ */
101
199
  validateIngressRule(rule) {
102
200
  if (!rule.paths || !Array.isArray(rule.paths)) {
103
201
  throw new Error('Ingress rule must have a paths array');
@@ -106,30 +204,58 @@ export class AWSResources extends BaseResourceProvider {
106
204
  this.validateIngressPath(pathRule);
107
205
  }
108
206
  }
207
+ /**
208
+ * Validates a single Ingress path
209
+ * @param pathRule - Path rule to validate
210
+ * @private
211
+ * @since 2.8.0+
212
+ */
109
213
  validateIngressPath(pathRule) {
110
214
  this.validatePathFormat(pathRule.path);
111
215
  this.validatePathType(pathRule.pathType);
112
216
  this.validateBackend(pathRule.backend);
113
217
  }
218
+ /**
219
+ * Validates path format
220
+ * @param path - Path to validate
221
+ * @private
222
+ * @since 2.5.0
223
+ */
114
224
  validatePathFormat(path) {
115
225
  if (!path || typeof path !== 'string') {
116
226
  throw new Error('Ingress path must be a non-empty string');
117
227
  }
228
+ // Normalize path and check for traversal attempts
118
229
  const normalizedPath = path.replace(/\/+/g, '/');
119
230
  if (!normalizedPath.startsWith('/')) {
120
231
  throw new Error(`Ingress path "${path}" must start with /`);
121
232
  }
233
+ // For Kubernetes Ingress paths, we allow URL patterns but warn about suspicious ones
122
234
  if (normalizedPath.includes('../') || normalizedPath.includes('./')) {
235
+ // Note: These could be valid URL patterns in some cases, but are suspicious
236
+ // Sanitize path for logging to prevent log injection
123
237
  const sanitizedPath = path.replace(/[\r\n]/g, '');
124
238
  console.warn(`Warning: Ingress path "${sanitizedPath}" contains path traversal-like sequences`);
125
239
  }
126
240
  }
241
+ /**
242
+ * Validates path type
243
+ * @param pathType - Path type to validate
244
+ * @private
245
+ * @since 2.5.0
246
+ */
127
247
  validatePathType(pathType) {
128
248
  const validPathTypes = ['Exact', 'Prefix', 'ImplementationSpecific'];
129
249
  if (!validPathTypes.includes(pathType)) {
130
250
  throw new Error(`Invalid pathType "${pathType}". Must be one of: ${validPathTypes.join(', ')}`);
131
251
  }
132
252
  }
253
+ /**
254
+ * Validates backend configuration
255
+ * @param backend - Backend to validate
256
+ * @private
257
+ * @since 2.5.0
258
+ */
133
259
  validateBackend(backend) {
134
260
  if (!backend?.service?.name) {
135
261
  throw new Error('Ingress path backend must specify service name');
@@ -143,6 +269,13 @@ export class AWSResources extends BaseResourceProvider {
143
269
  throw new Error(`Invalid port number ${port.number}. Must be between 1 and 65535`);
144
270
  }
145
271
  }
272
+ /**
273
+ * Validates StorageClass provisioner is present and valid
274
+ * @param provisioner - Provisioner string to validate
275
+ * @param storageType - Type of storage (for error messages)
276
+ * @private
277
+ * @since 2.5.0
278
+ */
146
279
  validateStorageClassProvisioner(provisioner, storageType) {
147
280
  if (!provisioner || typeof provisioner !== 'string' || provisioner.trim() === '') {
148
281
  throw new Error(`${storageType} StorageClass must have a valid provisioner`);
@@ -151,6 +284,7 @@ export class AWSResources extends BaseResourceProvider {
151
284
  EBS: 'ebs.csi.aws.com',
152
285
  EFS: 'efs.csi.aws.com',
153
286
  };
287
+ // Validate provisioner matches storage type
154
288
  const expectedProvisioner = validProvisioners[storageType];
155
289
  if (!expectedProvisioner) {
156
290
  throw new Error(`Invalid storage type: ${storageType}`);
@@ -159,7 +293,12 @@ export class AWSResources extends BaseResourceProvider {
159
293
  throw new Error(`Invalid AWS ${storageType} provisioner "${provisioner}". Must be: ${expectedProvisioner}`);
160
294
  }
161
295
  }
296
+ /**
297
+ * Validates AWS IAM Role ARN format
298
+ * @param roleArn - Role ARN to validate
299
+ */
162
300
  validateRoleArn(roleArn) {
301
+ // Skip validation for Helm template values
163
302
  if (roleArn.includes('{{') && roleArn.includes('}}')) {
164
303
  return;
165
304
  }
@@ -168,8 +307,15 @@ export class AWSResources extends BaseResourceProvider {
168
307
  throw new Error(`Invalid AWS IAM Role ARN format: ${roleArn}`);
169
308
  }
170
309
  }
310
+ /**
311
+ * Builds ALB-specific annotations
312
+ * @param spec - ALB Ingress specification
313
+ * @returns ALB annotations
314
+ */
171
315
  buildALBAnnotations(spec) {
172
316
  const annotations = {
317
+ // Remove deprecated kubernetes.io/ingress.class annotation
318
+ // Use spec.ingressClassName instead
173
319
  ...(spec.annotations ?? {}),
174
320
  };
175
321
  if (spec.scheme) {
@@ -189,6 +335,21 @@ export class AWSResources extends BaseResourceProvider {
189
335
  }
190
336
  return annotations;
191
337
  }
338
+ /**
339
+ * Creates a ServiceAccount with ECR access annotations
340
+ * @param spec - ECR ServiceAccount specification
341
+ * @returns Created ServiceAccount ApiObject
342
+ *
343
+ * @example
344
+ * ```typescript
345
+ * awsResources.addECRServiceAccount({
346
+ * name: 'ecr-service-account',
347
+ * roleArn: 'arn:aws:iam::123456789012:role/ECRAccessRole'
348
+ * });
349
+ * ```
350
+ *
351
+ * @since 2.8.0+
352
+ */
192
353
  addECRServiceAccount(spec) {
193
354
  const annotations = {
194
355
  'eks.amazonaws.com/role-arn': spec.roleArn,
@@ -202,6 +363,7 @@ export class AWSResources extends BaseResourceProvider {
202
363
  },
203
364
  automountToken: spec.automountServiceAccountToken ?? true,
204
365
  });
366
+ // Add image pull secrets if specified
205
367
  if (spec.imagePullSecrets) {
206
368
  spec.imagePullSecrets.forEach((secret) => {
207
369
  serviceAccount.addSecret(kplus.Secret.fromSecretName(this.chart, `${spec.name}-ecr-secret-${secret.name}`, secret.name));