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.
- package/CHANGELOG.md +7 -0
- package/README.md +323 -695
- package/dist/cli.js +275 -15
- package/dist/index.d.ts +5 -1
- package/dist/index.js +12 -0
- package/dist/lib/helm.d.ts +471 -0
- package/dist/lib/helm.js +483 -0
- package/dist/lib/helmChartWriter.d.ts +157 -0
- package/dist/lib/helmChartWriter.js +171 -1
- package/dist/lib/policy/configurationLoader.d.ts +132 -0
- package/dist/lib/policy/configurationLoader.js +132 -0
- package/dist/lib/policy/errorContextGenerator.d.ts +89 -0
- package/dist/lib/policy/errorContextGenerator.js +99 -2
- package/dist/lib/policy/errors.d.ts +35 -0
- package/dist/lib/policy/errors.js +36 -0
- package/dist/lib/policy/index.d.ts +9 -0
- package/dist/lib/policy/index.js +16 -0
- package/dist/lib/policy/parallelExecutor.d.ts +90 -0
- package/dist/lib/policy/parallelExecutor.js +86 -3
- package/dist/lib/policy/pluginLoader.d.ts +92 -0
- package/dist/lib/policy/pluginLoader.js +92 -1
- package/dist/lib/policy/pluginRegistry.d.ts +54 -0
- package/dist/lib/policy/pluginRegistry.js +56 -0
- package/dist/lib/policy/policyEngine.d.ts +137 -0
- package/dist/lib/policy/policyEngine.js +191 -5
- package/dist/lib/policy/resultAggregator.d.ts +46 -0
- package/dist/lib/policy/resultAggregator.js +69 -1
- package/dist/lib/policy/resultFormatter.d.ts +88 -0
- package/dist/lib/policy/resultFormatter.js +101 -0
- package/dist/lib/policy/types.d.ts +136 -0
- package/dist/lib/policy/types.js +8 -0
- package/dist/lib/policy/validationCache.d.ts +146 -0
- package/dist/lib/policy/validationCache.js +142 -6
- package/dist/lib/resources/baseResourceProvider.d.ts +45 -0
- package/dist/lib/resources/baseResourceProvider.js +48 -1
- package/dist/lib/resources/cloud/aws/awsResources.d.ts +192 -0
- package/dist/lib/resources/cloud/aws/awsResources.js +163 -1
- package/dist/lib/resources/cloud/aws/karpenterResources.d.ts +131 -0
- package/dist/lib/resources/cloud/aws/karpenterResources.js +77 -0
- package/dist/lib/rutter.d.ts +381 -3
- package/dist/lib/rutter.js +439 -28
- package/dist/lib/security.d.ts +123 -0
- package/dist/lib/security.js +162 -4
- package/dist/lib/templates/flexible-subchart.d.ts +52 -0
- package/dist/lib/templates/flexible-subchart.js +70 -0
- package/dist/lib/templates/umbrella-chart.d.ts +27 -0
- package/dist/lib/templates/umbrella-chart.js +89 -0
- package/dist/lib/types.d.ts +26 -0
- package/dist/lib/umbrella.d.ts +23 -0
- package/dist/lib/umbrella.js +23 -0
- package/dist/lib/umbrellaRutter.d.ts +75 -0
- package/dist/lib/umbrellaRutter.js +82 -2
- package/dist/lib/utils/envVarsLoader.d.ts +49 -0
- package/dist/lib/utils/envVarsLoader.js +53 -0
- package/dist/lib/utils/helmConstructSerializer.d.ts +17 -0
- package/dist/lib/utils/helmConstructSerializer.js +22 -0
- package/dist/lib/utils/helmControlStructures.d.ts +194 -0
- package/dist/lib/utils/helmControlStructures.js +180 -0
- package/dist/lib/utils/helmHelpers/envHelpers.d.ts +13 -0
- package/dist/lib/utils/helmHelpers/envHelpers.js +13 -0
- package/dist/lib/utils/helmHelpers/gitopsHelpers.d.ts +13 -0
- package/dist/lib/utils/helmHelpers/gitopsHelpers.js +13 -0
- package/dist/lib/utils/helmHelpers/index.d.ts +74 -0
- package/dist/lib/utils/helmHelpers/index.js +85 -1
- package/dist/lib/utils/helmHelpers/observabilityHelpers.d.ts +13 -0
- package/dist/lib/utils/helmHelpers/observabilityHelpers.js +13 -0
- package/dist/lib/utils/helmHelpers/types.d.ts +23 -0
- package/dist/lib/utils/helmHelpers/types.js +4 -0
- package/dist/lib/utils/helmHelpers/validationHelpers.d.ts +13 -0
- package/dist/lib/utils/helmHelpers/validationHelpers.js +13 -0
- package/dist/lib/utils/helmHelpers.d.ts +62 -0
- package/dist/lib/utils/helmHelpers.js +77 -0
- package/dist/lib/utils/helmYamlSerializer.d.ts +77 -0
- package/dist/lib/utils/helmYamlSerializer.js +398 -21
- package/dist/lib/utils/logger.d.ts +153 -0
- package/dist/lib/utils/logger.js +170 -2
- package/dist/lib/utils/valuesRef.d.ts +181 -50
- package/dist/lib/utils/valuesRef.js +168 -170
- package/dist/lib/validation/inputValidator.d.ts +45 -0
- package/dist/lib/validation/inputValidator.js +67 -2
- package/dist/types/index.d.ts +34 -0
- package/dist/types/index.js +3 -0
- 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
|
}
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/lib/umbrella.d.ts
CHANGED
|
@@ -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';
|
package/dist/lib/umbrella.js
CHANGED
|
@@ -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
|
}
|