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,9 +1,17 @@
1
+ /**
2
+ * @fileoverview Flexible subchart template that supports any cdk8s/cdk8s-plus-33 construct
3
+ * @since 2.8.4
4
+ */
1
5
  import { writeFileSync, mkdirSync, existsSync } from 'fs';
2
6
  import { join } from 'path';
3
7
  import { Chart } from 'cdk8s';
4
8
  import { SecurityUtils } from '../security.js';
5
9
  import { dumpHelmAwareYaml } from '../utils/helmYamlSerializer.js';
6
10
  import { generateHelpersTemplate } from '../utils/helmHelpers.js';
11
+ /**
12
+ * Flexible subchart that can accept any cdk8s construct or function
13
+ * @since 2.8.4
14
+ */
7
15
  export class FlexibleSubchart extends Chart {
8
16
  constructor(scope, id, config) {
9
17
  super(scope, id);
@@ -12,23 +20,40 @@ export class FlexibleSubchart extends Chart {
12
20
  this._manifests = [];
13
21
  this.configure();
14
22
  }
23
+ /**
24
+ * Add any cdk8s construct
25
+ * @param construct - Any cdk8s construct
26
+ * @param id - Unique identifier
27
+ */
15
28
  addConstruct(construct, id) {
16
29
  if (construct) {
17
30
  this._constructs.push({ construct, id: id || `construct-${this._constructs.length}` });
18
31
  }
19
32
  }
33
+ /**
34
+ * Add any manifest (for addManifest compatibility)
35
+ * @param manifest - Any manifest object
36
+ * @param id - Unique identifier
37
+ */
20
38
  addManifest(manifest, id) {
21
39
  if (manifest) {
22
40
  this._manifests.push({ manifest, id: id || `manifest-${this._manifests.length}` });
23
41
  }
24
42
  }
43
+ /**
44
+ * Configure the subchart with any provided construct or manifest
45
+ * @private
46
+ */
25
47
  configure() {
48
+ // Add any provided construct
26
49
  if (this.config.construct) {
27
50
  this.addConstruct(this.config.construct);
28
51
  }
52
+ // Add any provided manifest
29
53
  if (this.config.manifest) {
30
54
  this.addManifest(this.config.manifest);
31
55
  }
56
+ // Add any additional properties as constructs
32
57
  Object.entries(this.config).forEach(([key, value]) => {
33
58
  if (key !== 'name' &&
34
59
  key !== 'version' &&
@@ -40,10 +65,18 @@ export class FlexibleSubchart extends Chart {
40
65
  }
41
66
  });
42
67
  }
68
+ /**
69
+ * Write Helm chart files for this subchart
70
+ * @param outputDir - Directory to write the Helm chart files
71
+ */
43
72
  writeHelmChart(outputDir) {
73
+ // Ensure output directory exists
74
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
44
75
  if (!existsSync(outputDir)) {
76
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
45
77
  mkdirSync(outputDir, { recursive: true });
46
78
  }
79
+ // Create Chart.yaml for the subchart
47
80
  const subchartYaml = {
48
81
  apiVersion: 'v2',
49
82
  name: this.config.name,
@@ -55,38 +88,56 @@ export class FlexibleSubchart extends Chart {
55
88
  const chartYamlPath = SecurityUtils.validatePath(join(outputDir, 'Chart.yaml'), process.cwd(), {
56
89
  allowAbsolute: true,
57
90
  });
91
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- validated path
58
92
  writeFileSync(chartYamlPath, dumpHelmAwareYaml(subchartYaml));
93
+ // Create values.yaml for the subchart (filter out functions and non-serializable objects)
59
94
  const subchartValues = {
60
95
  enabled: true,
61
96
  ...Object.fromEntries(Object.entries(this.config).filter(([key, value]) => key !== 'chart' && typeof value !== 'function' && value !== null && value !== undefined)),
62
97
  };
63
98
  const valuesYamlPath = SecurityUtils.validatePath(join(outputDir, 'values.yaml'), process.cwd(), { allowAbsolute: true });
99
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- validated path
64
100
  writeFileSync(valuesYamlPath, dumpHelmAwareYaml(subchartValues));
101
+ // Create templates directory
65
102
  const templatesDir = SecurityUtils.validatePath(join(outputDir, 'templates'), process.cwd(), {
66
103
  allowAbsolute: true,
67
104
  });
105
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- validated path
68
106
  if (!existsSync(templatesDir)) {
107
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- validated path
69
108
  mkdirSync(templatesDir, { recursive: true });
70
109
  }
110
+ // Create _helpers.tpl for the subchart
71
111
  const helpersTpl = generateHelpersTemplate('aws', undefined, {
72
112
  includeKubernetes: true,
73
113
  includeSprig: true,
74
114
  });
75
115
  const helpersTplPath = SecurityUtils.validatePath(join(templatesDir, '_helpers.tpl'), process.cwd(), { allowAbsolute: true });
116
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- validated path
76
117
  writeFileSync(helpersTplPath, helpersTpl);
118
+ // Generate templates for manifests
77
119
  this._manifests.forEach((item) => {
78
120
  if (item && typeof item === 'object' && 'manifest' in item && 'id' in item) {
79
121
  const { manifest, id } = item;
80
122
  if (manifest && typeof manifest === 'object') {
81
123
  const templateContent = this._generateManifestTemplate(manifest, id);
82
124
  const manifestPath = SecurityUtils.validatePath(join(templatesDir, `${id}.yaml`), process.cwd(), { allowAbsolute: true });
125
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- validated path
83
126
  writeFileSync(manifestPath, templateContent);
84
127
  }
85
128
  }
86
129
  });
87
130
  console.log(`Created flexible Helm chart for subchart: ${this.config.name}`);
88
131
  }
132
+ /**
133
+ * Generate Helm template for a manifest
134
+ * @param manifest - The manifest object
135
+ * @param id - Template identifier
136
+ * @returns Generated template content
137
+ * @private
138
+ */
89
139
  _generateManifestTemplate(manifest, id) {
140
+ // Convert the manifest to a Helm template
90
141
  if (typeof manifest !== 'object' || manifest === null) {
91
142
  return dumpHelmAwareYaml({});
92
143
  }
@@ -104,16 +155,35 @@ export class FlexibleSubchart extends Chart {
104
155
  };
105
156
  return dumpHelmAwareYaml(template);
106
157
  }
158
+ /**
159
+ * Get all constructs added to this subchart
160
+ */
107
161
  getConstructs() {
108
162
  return this._constructs;
109
163
  }
164
+ /**
165
+ * Get all manifests added to this subchart
166
+ */
110
167
  getManifests() {
111
168
  return this._manifests;
112
169
  }
113
170
  }
171
+ /**
172
+ * Create a flexible subchart that can accept any construct
173
+ * @param scope - Parent chart scope
174
+ * @param id - Unique identifier
175
+ * @param config - Subchart configuration
176
+ * @returns FlexibleSubchart instance
177
+ */
114
178
  export function createFlexibleSubchart(scope, id, config) {
115
179
  return new FlexibleSubchart(scope, id, config);
116
180
  }
181
+ /**
182
+ * Generate a simple subchart template using Rutter addManifest()
183
+ * @param name Subchart name
184
+ * @returns Template string for chart.ts with simple Rutter implementation
185
+ * @since 2.11.0
186
+ */
117
187
  export function generateFlexibleSubchartTemplate(name) {
118
188
  return `import { App } from 'cdk8s';
119
189
  import { Rutter, helmInclude, helmIf, helmWith, createHelmExpression as helm } from 'timonel';
@@ -1,10 +1,25 @@
1
1
  import { App, Chart } from 'cdk8s';
2
2
  import type { ChartProps } from '../types.js';
3
+ /**
4
+ * Generate an umbrella chart template with direct subchart imports
5
+ * @param name Chart name
6
+ * @returns Template string for umbrella.ts
7
+ * @since 2.11.0
8
+ */
3
9
  export declare function generateUmbrellaChart(name: string): string;
10
+ /**
11
+ * UmbrellaChart class for managing multiple subcharts
12
+ * @since 2.8.4
13
+ */
4
14
  export declare class UmbrellaChartTemplate extends Chart {
5
15
  private readonly config;
6
16
  private _umbrellaRutter?;
7
17
  constructor(scope: App, id: string, config: ChartProps);
18
+ /**
19
+ * Configure the umbrella chart with basic resources and prepare UmbrellaRutter
20
+ * @since 2.8.4
21
+ * @private
22
+ */
8
23
  private configure;
9
24
  private _addService;
10
25
  private _addSubchart;
@@ -20,6 +35,18 @@ export declare class UmbrellaChartTemplate extends Chart {
20
35
  private _ensureDirectoryExists;
21
36
  private _processAssets;
22
37
  private _cleanupTempDir;
38
+ /**
39
+ * Create a basic Helm chart structure for subcharts that don't have writeHelmChart
40
+ * @since 2.8.4
41
+ * @param subchartName - Name of the subchart
42
+ * @param subchartDir - Directory to write the subchart files
43
+ * @private
44
+ */
23
45
  private _createBasicSubchart;
46
+ /**
47
+ * Write Helm chart files using basic Helm structure
48
+ * @since 2.8.4
49
+ * @param outputDir - Directory to write the Helm chart files
50
+ */
24
51
  writeHelmChart(outputDir: string): void;
25
52
  }
@@ -6,6 +6,12 @@ import { SecurityUtils } from '../security.js';
6
6
  import { dumpHelmAwareYaml } from '../utils/helmYamlSerializer.js';
7
7
  import { generateHelpersTemplate } from '../utils/helmHelpers.js';
8
8
  import { createFlexibleSubchart } from './flexible-subchart.js';
9
+ /**
10
+ * Generate an umbrella chart template with direct subchart imports
11
+ * @param name Chart name
12
+ * @returns Template string for umbrella.ts
13
+ * @since 2.11.0
14
+ */
9
15
  export function generateUmbrellaChart(name) {
10
16
  return `import { App } from 'cdk8s';
11
17
  import { Rutter, helmInclude, helmIf, helmWith, createHelmExpression as helm } from 'timonel';
@@ -163,13 +169,23 @@ if (import.meta.url === new URL(import.meta.url).href) {
163
169
 
164
170
  export default synth;`;
165
171
  }
172
+ /**
173
+ * UmbrellaChart class for managing multiple subcharts
174
+ * @since 2.8.4
175
+ */
166
176
  export class UmbrellaChartTemplate extends Chart {
167
177
  constructor(scope, id, config) {
168
178
  super(scope, id);
169
179
  this.config = config;
170
180
  this.configure();
171
181
  }
182
+ /**
183
+ * Configure the umbrella chart with basic resources and prepare UmbrellaRutter
184
+ * @since 2.8.4
185
+ * @private
186
+ */
172
187
  configure() {
188
+ // Create a basic ConfigMap to indicate the umbrella chart is working
173
189
  new ApiObject(this, 'umbrella-info', {
174
190
  apiVersion: 'v1',
175
191
  kind: 'ConfigMap',
@@ -188,9 +204,12 @@ export class UmbrellaChartTemplate extends Chart {
188
204
  'subcharts.count': String(this.config.subcharts?.length || 0),
189
205
  },
190
206
  });
207
+ // Note: Namespace is handled by writeHelmChart() method in templates/namespace.yaml
208
+ // Add services
191
209
  this.config.services?.forEach((svc, index) => {
192
210
  this._addService(svc, index);
193
211
  });
212
+ // Add subcharts
194
213
  this.config.subcharts?.forEach((subchart, index) => {
195
214
  this._addSubchart(subchart, index);
196
215
  });
@@ -228,10 +247,12 @@ export class UmbrellaChartTemplate extends Chart {
228
247
  else if (subchart.chart && typeof subchart.chart === 'object') {
229
248
  this._handleObjectChart(subchart, flexibleSubchart);
230
249
  }
250
+ // Sanitize subchart name for logging to prevent log injection
231
251
  const sanitizedName = subchart.name.replace(/[\r\n]/g, '');
232
252
  console.log(`Added flexible subchart: ${sanitizedName}`);
233
253
  }
234
254
  catch (_error) {
255
+ // Sanitize subchart name for logging to prevent log injection
235
256
  const sanitizedName = subchart.name.replace(/[\r\n]/g, '');
236
257
  console.warn(`Failed to add subchart ${sanitizedName}:`, _error);
237
258
  this._createFallbackSubchart(subchart, index);
@@ -252,6 +273,7 @@ export class UmbrellaChartTemplate extends Chart {
252
273
  version: subchart.version || '1.0.0',
253
274
  description: `${subchart.name} subchart (fallback)`,
254
275
  });
276
+ // Sanitize subchart name for logging to prevent log injection
255
277
  const sanitizedName = subchart.name.replace(/[\r\n]/g, '');
256
278
  console.log(`Created fallback subchart: ${sanitizedName}`);
257
279
  }
@@ -267,6 +289,7 @@ export class UmbrellaChartTemplate extends Chart {
267
289
  }
268
290
  }
269
291
  catch (error) {
292
+ // Sanitize subchart name for logging to prevent log injection
270
293
  const sanitizedName = subchart.name.replace(/[\r\n]/g, '');
271
294
  console.log(`Failed to process subchart ${sanitizedName}:`, error);
272
295
  }
@@ -274,9 +297,11 @@ export class UmbrellaChartTemplate extends Chart {
274
297
  _handleObjectChart(subchart, flexibleSubchart) {
275
298
  const chartObj = subchart.chart;
276
299
  if (chartObj.constructor && chartObj.constructor.name !== 'Object') {
300
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- FlexibleSubchart method
277
301
  flexibleSubchart.addConstruct(subchart.chart);
278
302
  }
279
303
  else {
304
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- FlexibleSubchart method
280
305
  flexibleSubchart.addManifest(subchart.chart);
281
306
  }
282
307
  }
@@ -302,6 +327,7 @@ export class UmbrellaChartTemplate extends Chart {
302
327
  const children = node?.children;
303
328
  children?.forEach((child) => {
304
329
  if (child instanceof Chart) {
330
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- FlexibleSubchart method
305
331
  flexibleSubchart.addConstruct(child);
306
332
  }
307
333
  });
@@ -309,9 +335,11 @@ export class UmbrellaChartTemplate extends Chart {
309
335
  _copyTemplates(subchartName, tempDir) {
310
336
  const tempTemplatesDir = join(tempDir, 'templates');
311
337
  const subchartTemplatesDir = join('dist', 'charts', subchartName, 'templates');
338
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
312
339
  if (existsSync(tempTemplatesDir)) {
313
340
  this._ensureDirectoryExists(join('dist', 'charts', subchartName));
314
341
  this._ensureDirectoryExists(subchartTemplatesDir);
342
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
315
343
  const templateFiles = readdirSync(tempTemplatesDir);
316
344
  templateFiles.forEach((file) => {
317
345
  if (file.endsWith('.yaml') || file.endsWith('.yml') || file.endsWith('.tpl')) {
@@ -323,7 +351,9 @@ export class UmbrellaChartTemplate extends Chart {
323
351
  }
324
352
  }
325
353
  _ensureDirectoryExists(dirPath) {
354
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
326
355
  if (!existsSync(dirPath)) {
356
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
327
357
  mkdirSync(dirPath, { recursive: true });
328
358
  }
329
359
  }
@@ -343,17 +373,27 @@ export class UmbrellaChartTemplate extends Chart {
343
373
  }
344
374
  }
345
375
  catch (error) {
376
+ // Sanitize asset id for logging to prevent log injection
346
377
  const sanitizedId = asset.id.replace(/[\r\n]/g, '');
347
378
  console.log(`Failed to parse asset ${sanitizedId}:`, error);
348
379
  }
349
380
  });
350
381
  }
351
382
  _cleanupTempDir(tempDir) {
383
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
352
384
  if (existsSync(tempDir)) {
353
385
  rmSync(tempDir, { recursive: true, force: true });
354
386
  }
355
387
  }
388
+ /**
389
+ * Create a basic Helm chart structure for subcharts that don't have writeHelmChart
390
+ * @since 2.8.4
391
+ * @param subchartName - Name of the subchart
392
+ * @param subchartDir - Directory to write the subchart files
393
+ * @private
394
+ */
356
395
  _createBasicSubchart(subchartName, subchartDir) {
396
+ // Create Chart.yaml for the subchart
357
397
  const subchartYaml = {
358
398
  apiVersion: 'v2',
359
399
  name: subchartName,
@@ -362,7 +402,9 @@ export class UmbrellaChartTemplate extends Chart {
362
402
  version: '1.0.0',
363
403
  appVersion: '1.0.0',
364
404
  };
405
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
365
406
  writeFileSync(join(subchartDir, 'Chart.yaml'), dumpHelmAwareYaml(subchartYaml));
407
+ // Create values.yaml for the subchart
366
408
  const subchartValues = {
367
409
  enabled: true,
368
410
  replicas: 1,
@@ -371,23 +413,39 @@ export class UmbrellaChartTemplate extends Chart {
371
413
  tag: 'latest',
372
414
  },
373
415
  };
416
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
374
417
  writeFileSync(join(subchartDir, 'values.yaml'), dumpHelmAwareYaml(subchartValues));
418
+ // Create templates directory
375
419
  const templatesDir = join(subchartDir, 'templates');
420
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
376
421
  if (!existsSync(templatesDir)) {
422
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
377
423
  mkdirSync(templatesDir, { recursive: true });
378
424
  }
425
+ // Create _helpers.tpl for the subchart
379
426
  const helpersTpl = generateHelpersTemplate('aws', undefined, {
380
427
  includeKubernetes: true,
381
428
  includeSprig: true,
382
429
  });
430
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
383
431
  writeFileSync(join(templatesDir, '_helpers.tpl'), helpersTpl);
432
+ // Sanitize subchart name for logging to prevent log injection
384
433
  const sanitizedName = subchartName.replace(/[\r\n]/g, '');
385
434
  console.log(`Created basic Helm chart structure for subchart: ${sanitizedName}`);
386
435
  }
436
+ /**
437
+ * Write Helm chart files using basic Helm structure
438
+ * @since 2.8.4
439
+ * @param outputDir - Directory to write the Helm chart files
440
+ */
387
441
  writeHelmChart(outputDir) {
442
+ // Ensure output directory exists
443
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
388
444
  if (!existsSync(outputDir)) {
445
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
389
446
  mkdirSync(outputDir, { recursive: true });
390
447
  }
448
+ // Create Chart.yaml
391
449
  const chartYaml = {
392
450
  apiVersion: 'v2',
393
451
  name: this.config.name,
@@ -401,11 +459,14 @@ export class UmbrellaChartTemplate extends Chart {
401
459
  repository: 'file://./charts/' + subchart.name,
402
460
  })) || [],
403
461
  };
462
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
404
463
  writeFileSync(join(outputDir, 'Chart.yaml'), dumpHelmAwareYaml(chartYaml));
464
+ // Create values.yaml
405
465
  const valuesYaml = {
406
466
  global: {
407
467
  namespace: this.config.name,
408
468
  },
469
+ // Add subchart values
409
470
  ...Object.fromEntries(this.config.subcharts?.map((subchart) => [
410
471
  subchart.name,
411
472
  {
@@ -413,16 +474,25 @@ export class UmbrellaChartTemplate extends Chart {
413
474
  },
414
475
  ]) || []),
415
476
  };
477
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
416
478
  writeFileSync(join(outputDir, 'values.yaml'), dumpHelmAwareYaml(valuesYaml));
479
+ // Create charts directory
417
480
  const chartsDir = join(outputDir, 'charts');
481
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
418
482
  if (!existsSync(chartsDir)) {
483
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
419
484
  mkdirSync(chartsDir, { recursive: true });
420
485
  }
486
+ // Generate Helm charts for each subchart
487
+ // eslint-disable-next-line sonarjs/cognitive-complexity
421
488
  this.config.subcharts?.forEach((subchart) => {
422
489
  const subchartDir = SecurityUtils.validatePath(join(chartsDir, subchart.name), process.cwd(), { allowAbsolute: true });
490
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- validated path
423
491
  if (!existsSync(subchartDir)) {
492
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- validated path
424
493
  mkdirSync(subchartDir, { recursive: true });
425
494
  }
495
+ // Create a flexible subchart that can handle any type of input
426
496
  const { name: _name, version: _version, description: _description, ...subchartProps } = subchart;
427
497
  const flexibleSubchart = createFlexibleSubchart(this, `${subchart.name}-chart`, {
428
498
  name: subchart.name,
@@ -430,10 +500,14 @@ export class UmbrellaChartTemplate extends Chart {
430
500
  description: subchart.description || `${subchart.name} subchart`,
431
501
  ...subchartProps,
432
502
  });
503
+ // Handle different types of chart inputs
433
504
  if (typeof subchart.chart === 'function') {
434
505
  try {
506
+ // Try calling with scope and id parameters
435
507
  const chartInstance = subchart.chart(this, `${subchart.name}-chart`);
508
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
436
509
  if (chartInstance && typeof chartInstance.writeHelmChart === 'function') {
510
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
437
511
  chartInstance.writeHelmChart(subchartDir);
438
512
  }
439
513
  else {
@@ -441,9 +515,12 @@ export class UmbrellaChartTemplate extends Chart {
441
515
  }
442
516
  }
443
517
  catch {
518
+ // If that fails, try calling without parameters
444
519
  try {
445
520
  const chartInstance = subchart.chart();
521
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
446
522
  if (chartInstance && typeof chartInstance.writeHelmChart === 'function') {
523
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
447
524
  chartInstance.writeHelmChart(subchartDir);
448
525
  }
449
526
  else {
@@ -451,6 +528,7 @@ export class UmbrellaChartTemplate extends Chart {
451
528
  }
452
529
  }
453
530
  catch (fallbackError) {
531
+ // Sanitize subchart name for logging to prevent log injection
454
532
  const sanitizedName = subchart.name.replace(/[\r\n]/g, '');
455
533
  console.warn(`Failed to create subchart ${sanitizedName}:`, fallbackError);
456
534
  flexibleSubchart.writeHelmChart(subchartDir);
@@ -458,24 +536,32 @@ export class UmbrellaChartTemplate extends Chart {
458
536
  }
459
537
  }
460
538
  else if (subchart.chart && typeof subchart.chart === 'object') {
539
+ // If it's an object, try to use it as a construct or manifest
461
540
  if (subchart.chart.constructor && subchart.chart.constructor.name !== 'Object') {
541
+ // It's a cdk8s construct, add it to the flexible subchart
462
542
  flexibleSubchart.addConstruct(subchart.chart);
463
543
  }
464
544
  else {
545
+ // It's a manifest object, add it as a manifest
465
546
  flexibleSubchart.addManifest(subchart.chart);
466
547
  }
467
548
  flexibleSubchart.writeHelmChart(subchartDir);
468
549
  }
469
550
  else {
551
+ // Use the flexible subchart as fallback
470
552
  flexibleSubchart.writeHelmChart(subchartDir);
471
553
  }
472
554
  });
555
+ // Create templates directory
473
556
  const templatesDir = SecurityUtils.validatePath(join(outputDir, 'templates'), process.cwd(), {
474
557
  allowAbsolute: true,
475
558
  });
559
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- validated path
476
560
  if (!existsSync(templatesDir)) {
561
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- validated path
477
562
  mkdirSync(templatesDir, { recursive: true });
478
563
  }
564
+ // Create shared namespace.yaml in templates
479
565
  const namespaceYaml = {
480
566
  apiVersion: 'v1',
481
567
  kind: 'Namespace',
@@ -490,11 +576,14 @@ export class UmbrellaChartTemplate extends Chart {
490
576
  },
491
577
  };
492
578
  const namespaceYamlPath = SecurityUtils.validatePath(join(templatesDir, 'namespace.yaml'), process.cwd(), { allowAbsolute: true });
579
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- validated path
493
580
  writeFileSync(namespaceYamlPath, dumpHelmAwareYaml(namespaceYaml));
581
+ // Create _helpers.tpl using programmatic generation
494
582
  const helpersTpl = generateHelpersTemplate('aws', undefined, {
495
583
  includeKubernetes: true,
496
584
  includeSprig: true,
497
585
  });
586
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
498
587
  writeFileSync(join(templatesDir, '_helpers.tpl'), helpersTpl);
499
588
  }
500
589
  }
@@ -1,29 +1,55 @@
1
1
  import type { Chart } from 'cdk8s';
2
2
  import type { TimonelLogger } from './utils/logger.js';
3
+ /**
4
+ * Configuration used by the legacy `UmbrellaChartTemplate` compatibility API.
5
+ *
6
+ * New library code should normally build subcharts with `Rutter` and compose them with
7
+ * `UmbrellaRutter`. This interface remains public for the template/CLI compatibility layer.
8
+ */
3
9
  export interface ChartProps {
10
+ /** Helm chart name. */
4
11
  name: string;
12
+ /** Helm chart semantic version. */
5
13
  version: string;
14
+ /** Human-readable chart description. */
6
15
  description: string;
16
+ /** Optional default Kubernetes namespace. */
7
17
  namespace?: string;
18
+ /** Labels applied by compatibility template helpers. */
8
19
  labels?: Record<string, string>;
20
+ /** Annotations applied by compatibility template helpers. */
9
21
  annotations?: Record<string, string>;
22
+ /** Optional service descriptors generated by the umbrella compatibility template. */
10
23
  services?: Array<{
11
24
  name: string;
12
25
  port: number;
13
26
  targetPort: number;
14
27
  }>;
28
+ /** Optional subchart descriptors consumed by the umbrella compatibility template. */
15
29
  subcharts?: Array<{
16
30
  name: string;
17
31
  chart: Chart | ((scope: Chart, id: string) => Chart) | unknown;
18
32
  version?: string;
19
33
  enabled?: boolean;
34
+ /** Additional template-specific properties. */
20
35
  [key: string]: unknown;
21
36
  }>;
37
+ /** Additional template-specific properties retained for compatibility. */
22
38
  [key: string]: unknown;
39
+ /**
40
+ * Custom logger instance.
41
+ * @since 2.13.0
42
+ */
23
43
  logger?: TimonelLogger;
24
44
  }
45
+ /**
46
+ * Serializable subchart entry stored by the CLI in `umbrella.config.json`.
47
+ */
25
48
  export interface SubchartProps {
49
+ /** Subchart name. */
26
50
  name: string;
51
+ /** Subchart version recorded in the CLI configuration. */
27
52
  version: string;
53
+ /** Project-relative path to the subchart TypeScript entry point. */
28
54
  path: string;
29
55
  }
@@ -1,3 +1,26 @@
1
+ /**
2
+ * @fileoverview Umbrella chart utilities for managing multiple subcharts as a single unit
3
+ * @since 2.8.0+
4
+ */
1
5
  import type { UmbrellaRutter, UmbrellaRutterProps } from './umbrellaRutter.js';
6
+ /**
7
+ * Create an umbrella chart from multiple Rutter instances
8
+ *
9
+ * @param props - Umbrella chart configuration
10
+ * @returns UmbrellaRutter instance for managing subcharts
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const umbrella = createUmbrella({
15
+ * meta: { name: 'my-umbrella', version: '1.0.0' },
16
+ * subcharts: [
17
+ * { name: 'frontend', rutter: frontendChart },
18
+ * { name: 'backend', rutter: backendChart }
19
+ * ]
20
+ * });
21
+ * ```
22
+ *
23
+ * @since 2.8.0+
24
+ */
2
25
  export declare function createUmbrella(props: UmbrellaRutterProps): UmbrellaRutter;
3
26
  export type { UmbrellaRutterProps, SubchartSpec } from './umbrellaRutter.js';
@@ -1,4 +1,27 @@
1
+ /**
2
+ * @fileoverview Umbrella chart utilities for managing multiple subcharts as a single unit
3
+ * @since 2.8.0+
4
+ */
1
5
  import { UmbrellaRutter as UmbrellaRutterClass } from './umbrellaRutter.js';
6
+ /**
7
+ * Create an umbrella chart from multiple Rutter instances
8
+ *
9
+ * @param props - Umbrella chart configuration
10
+ * @returns UmbrellaRutter instance for managing subcharts
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const umbrella = createUmbrella({
15
+ * meta: { name: 'my-umbrella', version: '1.0.0' },
16
+ * subcharts: [
17
+ * { name: 'frontend', rutter: frontendChart },
18
+ * { name: 'backend', rutter: backendChart }
19
+ * ]
20
+ * });
21
+ * ```
22
+ *
23
+ * @since 2.8.0+
24
+ */
2
25
  export function createUmbrella(props) {
3
26
  return new UmbrellaRutterClass(props);
4
27
  }