timonel 2.8.0 → 2.8.3
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/CHANGELOG.md +12 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +319 -191
- package/dist/index.d.ts +0 -5
- package/dist/index.js +0 -6
- package/dist/lib/helm.d.ts +0 -472
- package/dist/lib/helm.js +0 -481
- package/dist/lib/helmChartWriter.d.ts +0 -178
- package/dist/lib/helmChartWriter.js +0 -180
- package/dist/lib/resources/baseResourceProvider.d.ts +0 -46
- package/dist/lib/resources/baseResourceProvider.js +1 -47
- package/dist/lib/resources/cloud/aws/awsResources.d.ts +0 -144
- package/dist/lib/resources/cloud/aws/awsResources.js +1 -163
- package/dist/lib/resources/cloud/aws/karpenterResources.d.ts +0 -132
- package/dist/lib/resources/cloud/aws/karpenterResources.js +0 -75
- package/dist/lib/rutter.d.ts +0 -324
- package/dist/lib/rutter.js +8 -352
- package/dist/lib/security.d.ts +0 -119
- package/dist/lib/security.js +4 -160
- package/dist/lib/umbrella.d.ts +0 -24
- package/dist/lib/umbrella.js +0 -24
- package/dist/lib/umbrellaRutter.d.ts +0 -71
- package/dist/lib/umbrellaRutter.js +2 -82
- package/dist/lib/utils/helmHelpers.d.ts +0 -39
- package/dist/lib/utils/helmHelpers.js +0 -32
- package/package.json +1 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/helm.d.ts.map +0 -1
- package/dist/lib/helm.js.map +0 -1
- package/dist/lib/helmChartWriter.d.ts.map +0 -1
- package/dist/lib/helmChartWriter.js.map +0 -1
- package/dist/lib/resources/baseResourceProvider.d.ts.map +0 -1
- package/dist/lib/resources/baseResourceProvider.js.map +0 -1
- package/dist/lib/resources/cloud/aws/awsResources.d.ts.map +0 -1
- package/dist/lib/resources/cloud/aws/awsResources.js.map +0 -1
- package/dist/lib/resources/cloud/aws/karpenterResources.d.ts.map +0 -1
- package/dist/lib/resources/cloud/aws/karpenterResources.js.map +0 -1
- package/dist/lib/rutter.d.ts.map +0 -1
- package/dist/lib/rutter.js.map +0 -1
- package/dist/lib/security.d.ts.map +0 -1
- package/dist/lib/security.js.map +0 -1
- package/dist/lib/umbrella.d.ts.map +0 -1
- package/dist/lib/umbrella.js.map +0 -1
- package/dist/lib/umbrellaRutter.d.ts.map +0 -1
- package/dist/lib/umbrellaRutter.js.map +0 -1
- package/dist/lib/utils/helmHelpers.d.ts.map +0 -1
- package/dist/lib/utils/helmHelpers.js.map +0 -1
package/dist/lib/rutter.js
CHANGED
|
@@ -5,13 +5,6 @@ import { HelmChartWriter } from './helmChartWriter.js';
|
|
|
5
5
|
import { AWSResources } from './resources/cloud/aws/awsResources.js';
|
|
6
6
|
import { KarpenterResources } from './resources/cloud/aws/karpenterResources.js';
|
|
7
7
|
import { generateHelpersTemplate } from './utils/helmHelpers.js';
|
|
8
|
-
/**
|
|
9
|
-
* Rutter class with modular architecture
|
|
10
|
-
* Provides a clean API while delegating to specialized resource providers
|
|
11
|
-
* Maintains full backward compatibility with the original Rutter class
|
|
12
|
-
*
|
|
13
|
-
* @since 2.4.0
|
|
14
|
-
*/
|
|
15
8
|
export class Rutter {
|
|
16
9
|
constructor(props) {
|
|
17
10
|
this.assets = [];
|
|
@@ -19,286 +12,47 @@ export class Rutter {
|
|
|
19
12
|
this.meta = props.meta;
|
|
20
13
|
this.defaultValues = props.defaultValues ?? {};
|
|
21
14
|
this.envValues = props.envValues ?? {};
|
|
22
|
-
// Create CDK8s infrastructure
|
|
23
15
|
this.app = new App();
|
|
24
16
|
this.chart = new Chart(this.app, props.meta.name, {
|
|
25
17
|
...props.chartProps,
|
|
26
18
|
...(props.namespace ? { namespace: props.namespace } : {}),
|
|
27
19
|
});
|
|
28
|
-
// Initialize resource providers
|
|
29
20
|
this.awsResources = new AWSResources(this.chart);
|
|
30
21
|
this.karpenterResources = new KarpenterResources(this.chart);
|
|
31
22
|
}
|
|
32
|
-
// AWS Resources
|
|
33
|
-
/**
|
|
34
|
-
* Creates an AWS EBS StorageClass
|
|
35
|
-
* @param spec - EBS StorageClass specification
|
|
36
|
-
* @returns Created StorageClass ApiObject
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```typescript
|
|
40
|
-
* rutter.addAWSEBSStorageClass({
|
|
41
|
-
* name: 'fast-ebs',
|
|
42
|
-
* volumeType: 'gp3',
|
|
43
|
-
* encrypted: true,
|
|
44
|
-
* allowVolumeExpansion: true
|
|
45
|
-
* });
|
|
46
|
-
* ```
|
|
47
|
-
*
|
|
48
|
-
* @since 1.0.0
|
|
49
|
-
*/
|
|
50
23
|
addAWSEBSStorageClass(spec) {
|
|
51
24
|
return this.awsResources.addEBSStorageClass(spec);
|
|
52
25
|
}
|
|
53
|
-
/**
|
|
54
|
-
* Creates an AWS EFS StorageClass
|
|
55
|
-
* @param spec - EFS StorageClass specification
|
|
56
|
-
* @returns Created StorageClass ApiObject
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* ```typescript
|
|
60
|
-
* rutter.addAWSEFSStorageClass({
|
|
61
|
-
* name: 'efs-storage',
|
|
62
|
-
* fileSystemId: 'fs-12345678',
|
|
63
|
-
* directoryPerms: '0755'
|
|
64
|
-
* });
|
|
65
|
-
* ```
|
|
66
|
-
*
|
|
67
|
-
* @since 1.0.0
|
|
68
|
-
*/
|
|
69
26
|
addAWSEFSStorageClass(spec) {
|
|
70
27
|
return this.awsResources.addEFSStorageClass(spec);
|
|
71
28
|
}
|
|
72
|
-
/**
|
|
73
|
-
* Creates an AWS IRSA ServiceAccount
|
|
74
|
-
* @param spec - IRSA ServiceAccount specification
|
|
75
|
-
* @returns Created ServiceAccount ApiObject
|
|
76
|
-
*
|
|
77
|
-
* @example
|
|
78
|
-
* ```typescript
|
|
79
|
-
* rutter.addAWSIRSAServiceAccount({
|
|
80
|
-
* name: 'my-service-account',
|
|
81
|
-
* roleArn: 'arn:aws:iam::ACCOUNT_ID:role/MyRole'
|
|
82
|
-
* });
|
|
83
|
-
* ```
|
|
84
|
-
*
|
|
85
|
-
* @since 1.0.0
|
|
86
|
-
*/
|
|
87
29
|
addAWSIRSAServiceAccount(spec) {
|
|
88
30
|
return this.awsResources.addIRSAServiceAccount(spec);
|
|
89
31
|
}
|
|
90
|
-
/**
|
|
91
|
-
* Creates an AWS ALB Ingress
|
|
92
|
-
* @param spec - ALB Ingress specification
|
|
93
|
-
* @returns Created Ingress ApiObject
|
|
94
|
-
*
|
|
95
|
-
* @example
|
|
96
|
-
* ```typescript
|
|
97
|
-
* rutter.addAWSALBIngress({
|
|
98
|
-
* name: 'web-ingress',
|
|
99
|
-
* rules: [{
|
|
100
|
-
* paths: [{
|
|
101
|
-
* path: '/',
|
|
102
|
-
* pathType: 'Prefix',
|
|
103
|
-
* backend: { service: { name: 'web-service', port: { number: 80 } } }
|
|
104
|
-
* }]
|
|
105
|
-
* }],
|
|
106
|
-
* scheme: 'internet-facing'
|
|
107
|
-
* });
|
|
108
|
-
* ```
|
|
109
|
-
*
|
|
110
|
-
* @since 1.0.0
|
|
111
|
-
*/
|
|
112
32
|
addAWSALBIngress(spec) {
|
|
113
33
|
return this.awsResources.addALBIngress(spec);
|
|
114
34
|
}
|
|
115
|
-
// AWS Karpenter Resources
|
|
116
|
-
/**
|
|
117
|
-
* Creates a Karpenter NodePool resource
|
|
118
|
-
* @param spec - NodePool specification
|
|
119
|
-
* @returns Created NodePool ApiObject
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* ```typescript
|
|
123
|
-
* rutter.addKarpenterNodePool({
|
|
124
|
-
* name: 'default-nodepool',
|
|
125
|
-
* template: {
|
|
126
|
-
* spec: {
|
|
127
|
-
* nodeClassRef: {
|
|
128
|
-
* apiVersion: 'karpenter.k8s.aws/v1beta1',
|
|
129
|
-
* kind: 'EC2NodeClass',
|
|
130
|
-
* name: 'default'
|
|
131
|
-
* }
|
|
132
|
-
* }
|
|
133
|
-
* }
|
|
134
|
-
* });
|
|
135
|
-
* ```
|
|
136
|
-
*
|
|
137
|
-
* @since 2.7.0
|
|
138
|
-
*/
|
|
139
35
|
addKarpenterNodePool(spec) {
|
|
140
36
|
return this.karpenterResources.addKarpenterNodePool(spec);
|
|
141
37
|
}
|
|
142
|
-
/**
|
|
143
|
-
* Creates a Karpenter NodeClaim resource
|
|
144
|
-
* @param spec - NodeClaim specification
|
|
145
|
-
* @returns Created NodeClaim ApiObject
|
|
146
|
-
*
|
|
147
|
-
* @example
|
|
148
|
-
* ```typescript
|
|
149
|
-
* rutter.addKarpenterNodeClaim({
|
|
150
|
-
* name: 'my-node-claim',
|
|
151
|
-
* nodeClassRef: {
|
|
152
|
-
* apiVersion: 'karpenter.k8s.aws/v1beta1',
|
|
153
|
-
* kind: 'EC2NodeClass',
|
|
154
|
-
* name: 'default'
|
|
155
|
-
* }
|
|
156
|
-
* });
|
|
157
|
-
* ```
|
|
158
|
-
*
|
|
159
|
-
* @since 2.7.0
|
|
160
|
-
*/
|
|
161
38
|
addKarpenterNodeClaim(spec) {
|
|
162
39
|
return this.karpenterResources.addKarpenterNodeClaim(spec);
|
|
163
40
|
}
|
|
164
|
-
/**
|
|
165
|
-
* Creates a Karpenter EC2NodeClass resource
|
|
166
|
-
* @param spec - EC2NodeClass specification
|
|
167
|
-
* @returns Created EC2NodeClass ApiObject
|
|
168
|
-
*
|
|
169
|
-
* @example
|
|
170
|
-
* ```typescript
|
|
171
|
-
* rutter.addKarpenterEC2NodeClass({
|
|
172
|
-
* name: 'default',
|
|
173
|
-
* amiFamily: 'AL2',
|
|
174
|
-
* subnetSelectorTerms: [{ tags: { 'karpenter.sh/discovery': 'my-cluster' } }],
|
|
175
|
-
* securityGroupSelectorTerms: [{ tags: { 'karpenter.sh/discovery': 'my-cluster' } }]
|
|
176
|
-
* });
|
|
177
|
-
* ```
|
|
178
|
-
*
|
|
179
|
-
* @since 2.7.0
|
|
180
|
-
*/
|
|
181
41
|
addKarpenterEC2NodeClass(spec) {
|
|
182
42
|
return this.karpenterResources.addKarpenterEC2NodeClass(spec);
|
|
183
43
|
}
|
|
184
|
-
/**
|
|
185
|
-
* Creates a Karpenter NodePool with optimized disruption settings for cost efficiency
|
|
186
|
-
* @param spec - NodePool specification with disruption optimization
|
|
187
|
-
* @returns Created NodePool ApiObject
|
|
188
|
-
*
|
|
189
|
-
* @example
|
|
190
|
-
* ```typescript
|
|
191
|
-
* rutter.addKarpenterNodePoolWithDisruption({
|
|
192
|
-
* name: 'cost-optimized',
|
|
193
|
-
* nodeClassRef: {
|
|
194
|
-
* apiVersion: 'karpenter.k8s.aws/v1beta1',
|
|
195
|
-
* kind: 'EC2NodeClass',
|
|
196
|
-
* name: 'default'
|
|
197
|
-
* },
|
|
198
|
-
* consolidationPolicy: 'WhenEmptyOrUnderutilized',
|
|
199
|
-
* consolidateAfter: '30s',
|
|
200
|
-
* expireAfter: '24h',
|
|
201
|
-
* disruptionBudgets: [
|
|
202
|
-
* { nodes: '20%' },
|
|
203
|
-
* { nodes: '0', schedule: '0 9 * * 1-5', duration: '8h' }
|
|
204
|
-
* ]
|
|
205
|
-
* });
|
|
206
|
-
* ```
|
|
207
|
-
*
|
|
208
|
-
* @since 2.7.1
|
|
209
|
-
*/
|
|
210
44
|
addKarpenterNodePoolWithDisruption(spec) {
|
|
211
45
|
return this.karpenterResources.addKarpenterNodePoolWithDisruption(spec);
|
|
212
46
|
}
|
|
213
|
-
/**
|
|
214
|
-
* Creates a Karpenter NodePool with scheduling constraints and priorities
|
|
215
|
-
* @param spec - NodePool specification with scheduling optimization
|
|
216
|
-
* @returns Created NodePool ApiObject
|
|
217
|
-
*
|
|
218
|
-
* @example
|
|
219
|
-
* ```typescript
|
|
220
|
-
* rutter.addKarpenterNodePoolWithScheduling({
|
|
221
|
-
* name: 'gpu-workloads',
|
|
222
|
-
* nodeClassRef: {
|
|
223
|
-
* apiVersion: 'karpenter.k8s.aws/v1beta1',
|
|
224
|
-
* kind: 'EC2NodeClass',
|
|
225
|
-
* name: 'gpu-nodeclass'
|
|
226
|
-
* },
|
|
227
|
-
* requirements: [
|
|
228
|
-
* { key: 'node.kubernetes.io/instance-type', operator: 'In', values: ['g4dn.xlarge', 'g4dn.2xlarge'] }
|
|
229
|
-
* ],
|
|
230
|
-
* taints: [
|
|
231
|
-
* { key: 'nvidia.com/gpu', effect: 'NoSchedule' }
|
|
232
|
-
* ],
|
|
233
|
-
* terminationGracePeriod: '60s',
|
|
234
|
-
* weight: 100
|
|
235
|
-
* });
|
|
236
|
-
* ```
|
|
237
|
-
*
|
|
238
|
-
* @since 2.7.1
|
|
239
|
-
*/
|
|
240
47
|
addKarpenterNodePoolWithScheduling(spec) {
|
|
241
48
|
return this.karpenterResources.addKarpenterNodePoolWithScheduling(spec);
|
|
242
49
|
}
|
|
243
|
-
// AWS ECR ServiceAccount
|
|
244
|
-
/**
|
|
245
|
-
* Creates a ServiceAccount with ECR access annotations
|
|
246
|
-
* @param spec - ECR ServiceAccount specification
|
|
247
|
-
* @returns Created ServiceAccount ApiObject
|
|
248
|
-
*
|
|
249
|
-
* @example
|
|
250
|
-
* ```typescript
|
|
251
|
-
* rutter.addAWSECRServiceAccount({
|
|
252
|
-
* name: 'ecr-service-account',
|
|
253
|
-
* roleArn: 'arn:aws:iam::ACCOUNT_ID:role/ECRAccessRole'
|
|
254
|
-
* });
|
|
255
|
-
* ```
|
|
256
|
-
*
|
|
257
|
-
* @since 2.7.0
|
|
258
|
-
*/
|
|
259
50
|
addAWSECRServiceAccount(spec) {
|
|
260
51
|
return this.awsResources.addECRServiceAccount(spec);
|
|
261
52
|
}
|
|
262
|
-
// Utility methods
|
|
263
|
-
/**
|
|
264
|
-
* Adds a Kubernetes manifest to the chart using CDK8S
|
|
265
|
-
*
|
|
266
|
-
* This method allows you to add any Kubernetes manifest (CRDs, custom resources, etc.)
|
|
267
|
-
* either as YAML strings or as objects. The manifest will be processed using CDK8S
|
|
268
|
-
* for better type safety and validation.
|
|
269
|
-
*
|
|
270
|
-
* @param yamlOrObject - Kubernetes manifest as YAML string or object
|
|
271
|
-
* @param id - Unique identifier for the manifest (required for multiple manifests)
|
|
272
|
-
*
|
|
273
|
-
* @example
|
|
274
|
-
* ```typescript
|
|
275
|
-
* // Using YAML string for CRD
|
|
276
|
-
* rutter.addManifest(`
|
|
277
|
-
* apiVersion: apiextensions.k8s.io/v1
|
|
278
|
-
* kind: CustomResourceDefinition
|
|
279
|
-
* metadata:
|
|
280
|
-
* name: example.com
|
|
281
|
-
* spec:
|
|
282
|
-
* group: example.com
|
|
283
|
-
* versions: []
|
|
284
|
-
* `, 'my-crd');
|
|
285
|
-
*
|
|
286
|
-
* // Using object for any Kubernetes resource
|
|
287
|
-
* rutter.addManifest({
|
|
288
|
-
* apiVersion: 'v1',
|
|
289
|
-
* kind: 'ConfigMap',
|
|
290
|
-
* metadata: { name: 'my-config' },
|
|
291
|
-
* data: { key: 'value' }
|
|
292
|
-
* }, 'my-configmap');
|
|
293
|
-
* ```
|
|
294
|
-
*
|
|
295
|
-
* @since 3.0.0
|
|
296
|
-
* @note Consider using cdk8s-plus constructs for better type safety when available
|
|
297
|
-
*/
|
|
298
53
|
addManifest(yamlOrObject, id) {
|
|
299
54
|
let manifestObject;
|
|
300
55
|
if (typeof yamlOrObject === 'string') {
|
|
301
|
-
// Parse YAML string to object
|
|
302
56
|
try {
|
|
303
57
|
manifestObject = YAML.parse(yamlOrObject);
|
|
304
58
|
}
|
|
@@ -307,15 +61,12 @@ export class Rutter {
|
|
|
307
61
|
}
|
|
308
62
|
}
|
|
309
63
|
else if (typeof yamlOrObject === 'object' && yamlOrObject !== null) {
|
|
310
|
-
// Use object directly
|
|
311
64
|
manifestObject = yamlOrObject;
|
|
312
65
|
}
|
|
313
66
|
else {
|
|
314
67
|
throw new Error('addManifest() requires either a YAML string or an object');
|
|
315
68
|
}
|
|
316
|
-
// Validate basic Kubernetes manifest structure
|
|
317
69
|
this.validateManifestStructure(manifestObject);
|
|
318
|
-
// Create CDK8S ApiObject from the manifest
|
|
319
70
|
return new ApiObject(this.chart, id, {
|
|
320
71
|
apiVersion: manifestObject['apiVersion'],
|
|
321
72
|
kind: manifestObject['kind'],
|
|
@@ -323,54 +74,24 @@ export class Rutter {
|
|
|
323
74
|
spec: manifestObject['spec'],
|
|
324
75
|
});
|
|
325
76
|
}
|
|
326
|
-
/**
|
|
327
|
-
* Adds a Kubernetes manifest wrapped in a Helm conditional
|
|
328
|
-
*
|
|
329
|
-
* This method creates a manifest that will only be rendered if the specified
|
|
330
|
-
* condition evaluates to true. The condition is checked against .Values in Helm.
|
|
331
|
-
*
|
|
332
|
-
* @param manifestObject - JavaScript object representing the Kubernetes manifest
|
|
333
|
-
* @param condition - Path to the condition value in .Values (e.g., 'createNamespace')
|
|
334
|
-
* @param id - Unique identifier for this manifest within the chart
|
|
335
|
-
* @returns The created ApiObject instance
|
|
336
|
-
* @throws {Error} If the manifest structure is incorrect or condition path is invalid
|
|
337
|
-
*
|
|
338
|
-
* @example
|
|
339
|
-
* ```typescript
|
|
340
|
-
* // Add a namespace that's only created if .Values.createNamespace is true
|
|
341
|
-
* rutter.addConditionalManifest(
|
|
342
|
-
* {
|
|
343
|
-
* apiVersion: 'v1',
|
|
344
|
-
* kind: 'Namespace',
|
|
345
|
-
* metadata: {
|
|
346
|
-
* name: valuesRef('namespace'),
|
|
347
|
-
* labels: {
|
|
348
|
-
* environment: conditionalRef('environment', 'environment')
|
|
349
|
-
* }
|
|
350
|
-
* }
|
|
351
|
-
* },
|
|
352
|
-
* 'createNamespace',
|
|
353
|
-
* 'namespace'
|
|
354
|
-
* );
|
|
355
|
-
* ```
|
|
356
|
-
*
|
|
357
|
-
* @since 2.7.4
|
|
358
|
-
*/
|
|
359
77
|
addConditionalManifest(manifestObject, condition, id) {
|
|
360
|
-
// Validate condition path
|
|
361
78
|
if (!condition || typeof condition !== 'string') {
|
|
362
79
|
throw new Error('Condition must be a non-empty string');
|
|
363
80
|
}
|
|
364
|
-
// Validate basic Kubernetes manifest structure
|
|
365
81
|
this.validateManifestStructure(manifestObject);
|
|
366
|
-
|
|
82
|
+
let helmCondition;
|
|
83
|
+
if (condition.startsWith('{{') && condition.endsWith('}}')) {
|
|
84
|
+
helmCondition = condition.slice(2, -2).trim();
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
helmCondition = `.Values.${condition}`;
|
|
88
|
+
}
|
|
367
89
|
const conditionalAsset = {
|
|
368
90
|
id,
|
|
369
|
-
yaml: `{{- if
|
|
91
|
+
yaml: `{{- if ${helmCondition} }}\n${YAML.stringify(manifestObject)}{{- end }}`,
|
|
370
92
|
target: 'templates',
|
|
371
93
|
};
|
|
372
94
|
this.assets.push(conditionalAsset);
|
|
373
|
-
// Create a placeholder CDK8S ApiObject for consistency
|
|
374
95
|
return new ApiObject(this.chart, id, {
|
|
375
96
|
apiVersion: manifestObject['apiVersion'],
|
|
376
97
|
kind: manifestObject['kind'],
|
|
@@ -384,12 +105,6 @@ export class Rutter {
|
|
|
384
105
|
spec: manifestObject['spec'],
|
|
385
106
|
});
|
|
386
107
|
}
|
|
387
|
-
/**
|
|
388
|
-
* Validates the structure of a Kubernetes manifest object
|
|
389
|
-
* @param manifest - The manifest object to validate
|
|
390
|
-
* @private
|
|
391
|
-
* @since 3.0.0
|
|
392
|
-
*/
|
|
393
108
|
validateManifestStructure(manifest) {
|
|
394
109
|
if (!manifest['apiVersion'] || typeof manifest['apiVersion'] !== 'string') {
|
|
395
110
|
throw new Error('Kubernetes manifest must have a valid apiVersion');
|
|
@@ -406,7 +121,6 @@ export class Rutter {
|
|
|
406
121
|
if (!metadata['name'] || typeof metadata['name'] !== 'string') {
|
|
407
122
|
throw new Error('Kubernetes manifest metadata must have a valid name');
|
|
408
123
|
}
|
|
409
|
-
// Additional validation for specific resource types
|
|
410
124
|
const kind = manifest['kind'];
|
|
411
125
|
if (kind === 'CustomResourceDefinition') {
|
|
412
126
|
if (!manifest['spec'] || typeof manifest['spec'] !== 'object' || manifest['spec'] === null) {
|
|
@@ -421,59 +135,26 @@ export class Rutter {
|
|
|
421
135
|
}
|
|
422
136
|
}
|
|
423
137
|
}
|
|
424
|
-
/**
|
|
425
|
-
* Gets chart metadata
|
|
426
|
-
* @returns Chart metadata
|
|
427
|
-
*
|
|
428
|
-
* @since 1.0.0
|
|
429
|
-
*/
|
|
430
138
|
getMeta() {
|
|
431
139
|
return { ...this.meta };
|
|
432
140
|
}
|
|
433
|
-
/**
|
|
434
|
-
* Gets default values
|
|
435
|
-
* @returns Default values object
|
|
436
|
-
*
|
|
437
|
-
* @since 1.0.0
|
|
438
|
-
*/
|
|
439
141
|
getDefaultValues() {
|
|
440
142
|
return { ...this.defaultValues };
|
|
441
143
|
}
|
|
442
|
-
/**
|
|
443
|
-
* Gets environment-specific values
|
|
444
|
-
* @returns Environment values object
|
|
445
|
-
*
|
|
446
|
-
* @since 1.0.0
|
|
447
|
-
*/
|
|
448
144
|
getEnvValues() {
|
|
449
145
|
return { ...this.envValues };
|
|
450
146
|
}
|
|
451
|
-
/**
|
|
452
|
-
* Gets all assets (CRDs, etc.)
|
|
453
|
-
* @returns Array of assets
|
|
454
|
-
*
|
|
455
|
-
* @since 1.0.0
|
|
456
|
-
*/
|
|
457
147
|
getAssets() {
|
|
458
148
|
return [...this.assets];
|
|
459
149
|
}
|
|
460
|
-
/**
|
|
461
|
-
* Converts the chart to SynthAsset array for HelmChartWriter
|
|
462
|
-
* @returns Array of synthesized assets
|
|
463
|
-
*
|
|
464
|
-
* @since 2.4.0
|
|
465
|
-
*/
|
|
466
150
|
toSynthArray() {
|
|
467
|
-
// Get ApiObject IDs before synthesis
|
|
468
151
|
const apiObjectIds = [];
|
|
469
152
|
for (const child of this.chart.node.children) {
|
|
470
153
|
if (child instanceof ApiObject) {
|
|
471
154
|
apiObjectIds.push(child.node.id);
|
|
472
155
|
}
|
|
473
156
|
}
|
|
474
|
-
// Use cdk8s Testing.synth to obtain manifest objects
|
|
475
157
|
const manifestObjs = Testing.synth(this.chart);
|
|
476
|
-
// Enforce common labels best-practice on all rendered objects
|
|
477
158
|
const enriched = manifestObjs.map((obj) => {
|
|
478
159
|
if (obj && typeof obj === 'object') {
|
|
479
160
|
const o = obj;
|
|
@@ -488,10 +169,8 @@ export class Rutter {
|
|
|
488
169
|
'app.kubernetes.io/managed-by': '{{ .Release.Service }}',
|
|
489
170
|
'app.kubernetes.io/part-of': helm.chartName,
|
|
490
171
|
};
|
|
491
|
-
// Apply defaults only if not already set
|
|
492
172
|
for (const [key, value] of Object.entries(defaults)) {
|
|
493
173
|
if (!(key in labels)) {
|
|
494
|
-
// eslint-disable-next-line security/detect-object-injection -- Safe: controlled label assignment
|
|
495
174
|
labels[key] = value;
|
|
496
175
|
}
|
|
497
176
|
}
|
|
@@ -500,7 +179,6 @@ export class Rutter {
|
|
|
500
179
|
});
|
|
501
180
|
const synthAssets = [];
|
|
502
181
|
if (this.props.singleManifestFile) {
|
|
503
|
-
// Combine all resources into single manifest
|
|
504
182
|
const combinedYaml = enriched
|
|
505
183
|
.map((obj) => this.processHelmTemplates(YAML.stringify(obj).trim()))
|
|
506
184
|
.filter(Boolean)
|
|
@@ -509,47 +187,28 @@ export class Rutter {
|
|
|
509
187
|
synthAssets.push({ id: manifestId, yaml: combinedYaml });
|
|
510
188
|
}
|
|
511
189
|
else {
|
|
512
|
-
// Create separate files for each resource (default behavior)
|
|
513
190
|
enriched.forEach((obj, index) => {
|
|
514
191
|
const yaml = this.processHelmTemplates(YAML.stringify(obj).trim());
|
|
515
192
|
if (yaml) {
|
|
516
|
-
// Use descriptive name from ApiObject ID if available, otherwise fallback to generic name
|
|
517
|
-
// eslint-disable-next-line security/detect-object-injection
|
|
518
193
|
const apiObjectId = apiObjectIds[index];
|
|
519
194
|
const manifestId = apiObjectId || `manifest-${index + 1}`;
|
|
520
195
|
synthAssets.push({ id: manifestId, yaml });
|
|
521
196
|
}
|
|
522
197
|
});
|
|
523
198
|
}
|
|
524
|
-
// Add any additional assets (CRDs, etc.)
|
|
525
199
|
this.assets.forEach((asset) => {
|
|
526
200
|
synthAssets.push({ id: asset.id, yaml: asset.yaml });
|
|
527
201
|
});
|
|
528
202
|
return synthAssets;
|
|
529
203
|
}
|
|
530
|
-
/**
|
|
531
|
-
* Process YAML content to remove quotes from Helm templates
|
|
532
|
-
* This fixes the issue where YAML.stringify adds quotes around Helm template expressions
|
|
533
|
-
* Removes quotes from all Helm template expressions
|
|
534
|
-
*/
|
|
535
204
|
processHelmTemplates(yaml) {
|
|
536
|
-
// Remove quotes from Helm template expressions
|
|
537
|
-
// Match patterns like "{{ .Values.replicas | int }}", "{{ .Release.Name }}", etc.
|
|
538
|
-
// Handle both key-value pairs and standalone values
|
|
539
205
|
return yaml
|
|
540
206
|
.replace(/": "\{\{([^}]+)\}\}"/g, ': {{ $1 }}')
|
|
541
207
|
.replace(/: "\{\{([^}]+)\}\}"/g, ': {{ $1 }}')
|
|
542
208
|
.replace(/"\{\{([^}]+)\}\}"/g, '{{ $1 }}')
|
|
543
209
|
.replace(/": "\.nan"/g, ': .nan');
|
|
544
210
|
}
|
|
545
|
-
/**
|
|
546
|
-
* Writes the Helm chart to the specified output directory
|
|
547
|
-
* @param outDir - Output directory path
|
|
548
|
-
*
|
|
549
|
-
* @since 1.0.0
|
|
550
|
-
*/
|
|
551
211
|
write(outDir) {
|
|
552
|
-
// Generate helpers template
|
|
553
212
|
let helpersContent;
|
|
554
213
|
if (this.props.helpersTpl) {
|
|
555
214
|
if (typeof this.props.helpersTpl === 'string') {
|
|
@@ -567,7 +226,6 @@ ${helper.template}
|
|
|
567
226
|
}
|
|
568
227
|
}
|
|
569
228
|
else {
|
|
570
|
-
// Auto-generate standard helpers
|
|
571
229
|
helpersContent = generateHelpersTemplate(this.props.cloudProvider);
|
|
572
230
|
}
|
|
573
231
|
HelmChartWriter.write({
|
|
@@ -580,6 +238,4 @@ ${helper.template}
|
|
|
580
238
|
});
|
|
581
239
|
}
|
|
582
240
|
}
|
|
583
|
-
// Constants for labels
|
|
584
241
|
Rutter.HELPER_NAME = 'chart.name';
|
|
585
|
-
//# sourceMappingURL=rutter.js.map
|
package/dist/lib/security.d.ts
CHANGED
|
@@ -1,137 +1,18 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Security utilities for input validation and sanitization
|
|
3
|
-
* Focused on CLI tool security concerns: path traversal, injection prevention
|
|
4
|
-
* @since 2.2.0
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Security utilities for input validation and sanitization
|
|
8
|
-
* Focused on CLI tool security concerns: path traversal, injection prevention
|
|
9
|
-
*
|
|
10
|
-
* @since 2.2.0
|
|
11
|
-
*/
|
|
12
1
|
export declare class SecurityUtils {
|
|
13
|
-
/**
|
|
14
|
-
* Validates and sanitizes file paths to prevent path traversal attacks
|
|
15
|
-
* @param inputPath - The path to validate
|
|
16
|
-
* @param allowedBasePath - The base path that the input should be within
|
|
17
|
-
* @returns Sanitized path if valid
|
|
18
|
-
* @throws Error if path is invalid or contains traversal sequences
|
|
19
|
-
*
|
|
20
|
-
* @since 2.2.0
|
|
21
|
-
*/
|
|
22
2
|
static validatePath(inputPath: string, allowedBasePath: string): string;
|
|
23
|
-
/**
|
|
24
|
-
* Sanitizes log messages to prevent log injection attacks
|
|
25
|
-
* @param message - The message to sanitize
|
|
26
|
-
* @returns Sanitized message with control characters removed
|
|
27
|
-
*
|
|
28
|
-
* @since 2.2.0
|
|
29
|
-
*/
|
|
30
3
|
static sanitizeLogMessage(message: string): string;
|
|
31
|
-
/**
|
|
32
|
-
* Sanitizes environment names to prevent path traversal (CWE-22)
|
|
33
|
-
* @param env - Environment name to sanitize
|
|
34
|
-
* @returns Sanitized environment name
|
|
35
|
-
* @throws Error if environment name is invalid
|
|
36
|
-
*
|
|
37
|
-
* @since 2.2.0
|
|
38
|
-
*/
|
|
39
4
|
static sanitizeEnvironmentName(env: string): string;
|
|
40
|
-
/**
|
|
41
|
-
* Validates TypeScript file extensions for dynamic imports
|
|
42
|
-
* @param filePath - The file path to validate
|
|
43
|
-
* @returns True if the file has a valid TypeScript extension
|
|
44
|
-
*
|
|
45
|
-
* @since 2.2.0
|
|
46
|
-
*/
|
|
47
5
|
static isValidTypeScriptFile(filePath: string): boolean;
|
|
48
|
-
/**
|
|
49
|
-
* Validates if a path is safe for use in Helm templates
|
|
50
|
-
* Enhanced validation with better security checks and Helm best practices
|
|
51
|
-
* @param templatePath - The template path to validate
|
|
52
|
-
* @returns True if the path is valid for Helm templates
|
|
53
|
-
*
|
|
54
|
-
* @since 2.2.0
|
|
55
|
-
*/
|
|
56
6
|
static isValidHelmTemplatePath(templatePath: string): boolean;
|
|
57
|
-
/**
|
|
58
|
-
* Validates chart names according to Helm conventions
|
|
59
|
-
* @param chartName - Chart name to validate
|
|
60
|
-
* @returns True if chart name follows Helm naming rules
|
|
61
|
-
*
|
|
62
|
-
* @since 2.2.0
|
|
63
|
-
*/
|
|
64
7
|
static isValidChartName(chartName: string): boolean;
|
|
65
|
-
/**
|
|
66
|
-
* Validates subchart names according to Helm conventions
|
|
67
|
-
* @param subchartName - Subchart name to validate
|
|
68
|
-
* @returns True if subchart name is valid
|
|
69
|
-
*
|
|
70
|
-
* @since 2.2.0
|
|
71
|
-
*/
|
|
72
8
|
static isValidSubchartName(subchartName: string): boolean;
|
|
73
|
-
/**
|
|
74
|
-
* Sanitizes environment variable names and values for Kubernetes security
|
|
75
|
-
* Prevents injection attacks and ensures compliance with Kubernetes naming rules
|
|
76
|
-
* @param name - Environment variable name to sanitize
|
|
77
|
-
* @param value - Environment variable value to sanitize
|
|
78
|
-
* @returns Object with sanitized name and value
|
|
79
|
-
* @throws Error if name or value contains dangerous patterns
|
|
80
|
-
*
|
|
81
|
-
* @since 2.6.0
|
|
82
|
-
*/
|
|
83
9
|
static sanitizeEnvVar(name: string, value: string): {
|
|
84
10
|
name: string;
|
|
85
11
|
value: string;
|
|
86
12
|
};
|
|
87
|
-
/**
|
|
88
|
-
* Validates container image tags for security best practices
|
|
89
|
-
* Prevents use of dangerous tags and ensures proper versioning
|
|
90
|
-
* @param tag - Image tag to validate
|
|
91
|
-
* @returns True if tag is valid and secure
|
|
92
|
-
* @throws Error if tag violates security policies
|
|
93
|
-
*
|
|
94
|
-
* @since 2.6.0
|
|
95
|
-
*/
|
|
96
13
|
static validateImageTag(tag: string): boolean;
|
|
97
|
-
/**
|
|
98
|
-
* Generates secure names for Kubernetes secrets
|
|
99
|
-
* Ensures names follow RFC 1123 and are safe for Kubernetes
|
|
100
|
-
* @param baseName - Base name for the secret
|
|
101
|
-
* @param suffix - Optional suffix to append
|
|
102
|
-
* @returns Secure secret name
|
|
103
|
-
* @throws Error if generated name is invalid
|
|
104
|
-
*
|
|
105
|
-
* @since 2.6.0
|
|
106
|
-
*/
|
|
107
14
|
static generateSecretName(baseName: string, suffix?: string): string;
|
|
108
|
-
/**
|
|
109
|
-
* Sanitizes the base name for secret generation using safe string methods
|
|
110
|
-
* @param baseName - Base name to sanitize
|
|
111
|
-
* @returns Sanitized base name
|
|
112
|
-
* @throws Error if no valid characters remain
|
|
113
|
-
*
|
|
114
|
-
* @since 2.6.0
|
|
115
|
-
*/
|
|
116
15
|
private static sanitizeBaseName;
|
|
117
|
-
/**
|
|
118
|
-
* Appends suffix to sanitized base name using safe string methods
|
|
119
|
-
* @param baseName - Sanitized base name
|
|
120
|
-
* @param suffix - Suffix to append
|
|
121
|
-
* @returns Base name with suffix
|
|
122
|
-
* @throws Error if suffix is invalid
|
|
123
|
-
*
|
|
124
|
-
* @since 2.6.0
|
|
125
|
-
*/
|
|
126
16
|
private static appendSuffix;
|
|
127
|
-
/**
|
|
128
|
-
* Truncates name if it exceeds length limits
|
|
129
|
-
* @param name - Name to potentially truncate
|
|
130
|
-
* @param suffix - Original suffix for preservation
|
|
131
|
-
* @returns Truncated name if needed
|
|
132
|
-
*
|
|
133
|
-
* @since 2.6.0
|
|
134
|
-
*/
|
|
135
17
|
private static truncateIfNeeded;
|
|
136
18
|
}
|
|
137
|
-
//# sourceMappingURL=security.d.ts.map
|