timonel 3.0.0-beta.1 ā 3.1.0-beta.1
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 +192 -0
- package/README.md +606 -119
- package/SECURITY.md +25 -11
- package/dist/cli.js +54 -15
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/lib/helm.js +28 -1
- package/dist/lib/helmChartWriter.js +27 -8
- package/dist/lib/policy/configurationLoader.d.ts +46 -0
- package/dist/lib/policy/configurationLoader.js +251 -0
- package/dist/lib/policy/errorContextGenerator.d.ts +63 -0
- package/dist/lib/policy/errorContextGenerator.js +302 -0
- package/dist/lib/policy/errors.d.ts +40 -0
- package/dist/lib/policy/errors.js +109 -0
- package/dist/lib/policy/index.d.ts +11 -0
- package/dist/lib/policy/index.js +10 -0
- package/dist/lib/policy/parallelExecutor.d.ts +58 -0
- package/dist/lib/policy/parallelExecutor.js +215 -0
- package/dist/lib/policy/pluginLoader.d.ts +41 -0
- package/dist/lib/policy/pluginLoader.js +220 -0
- package/dist/lib/policy/pluginRegistry.d.ts +14 -0
- package/dist/lib/policy/pluginRegistry.js +69 -0
- package/dist/lib/policy/policyEngine.d.ts +39 -0
- package/dist/lib/policy/policyEngine.js +495 -0
- package/dist/lib/policy/resultAggregator.d.ts +8 -0
- package/dist/lib/policy/resultAggregator.js +138 -0
- package/dist/lib/policy/resultFormatter.d.ts +25 -0
- package/dist/lib/policy/resultFormatter.js +217 -0
- package/dist/lib/policy/types.d.ts +111 -0
- package/dist/lib/policy/types.js +1 -0
- package/dist/lib/policy/validationCache.d.ts +58 -0
- package/dist/lib/policy/validationCache.js +289 -0
- package/dist/lib/resources/baseResourceProvider.js +5 -0
- package/dist/lib/resources/cloud/aws/awsResources.js +2 -1
- package/dist/lib/resources/cloud/aws/karpenterResources.js +16 -2
- package/dist/lib/rutter.d.ts +7 -2
- package/dist/lib/rutter.js +177 -8
- package/dist/lib/security.js +4 -4
- package/dist/lib/templates/flexible-subchart.js +18 -7
- package/dist/lib/templates/umbrella-chart.js +29 -18
- package/dist/lib/umbrellaRutter.d.ts +1 -1
- package/dist/lib/umbrellaRutter.js +21 -9
- package/dist/lib/utils/envVarsLoader.js +13 -7
- package/dist/lib/utils/helmHelpers.js +10 -2
- package/dist/lib/utils/helmYamlSerializer.js +19 -9
- package/dist/lib/utils/logger.js +54 -39
- package/dist/lib/utils/valuesRef.js +9 -0
- package/dist/lib/validation/inputValidator.d.ts +26 -0
- package/dist/lib/validation/inputValidator.js +176 -0
- package/dist/types/index.d.ts +27 -0
- package/dist/types/index.js +1 -0
- package/package.json +21 -19
package/README.md
CHANGED
|
@@ -17,18 +17,107 @@ directory.
|
|
|
17
17
|
|
|
18
18
|
## ⨠Key Features
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- **š§ Flexible resource creation** with built-in methods and `addManifest()` for custom resources
|
|
24
|
-
- **š Multi-environment support** with automatic values files generation
|
|
25
|
-
- **āļø Umbrella Charts** for managing multiple subcharts as a single unit
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
### Core Capabilities
|
|
21
|
+
|
|
22
|
+
- **š Type-safe API** with strict TypeScript and cdk8s constructs
|
|
23
|
+
- **š§ Flexible resource creation** with built-in methods and `addManifest()` for custom resources
|
|
24
|
+
- **š Multi-environment support** with automatic values files generation
|
|
25
|
+
- **āļø Umbrella Charts** for managing multiple subcharts as a single unit
|
|
26
|
+
- **ā” Minimal CLI** (`tl`) for scaffolding, synthesis, validation, and deployment
|
|
27
|
+
- **š¦ Flexible subchart templates** supporting both cdk8s and cdk8s-plus-33
|
|
28
|
+
|
|
29
|
+
### Type-Safe Helm Helpers (v3.0+)
|
|
30
|
+
|
|
31
|
+
#### ValuesRef System (NEW in v3.0 - RECOMMENDED)
|
|
32
|
+
|
|
33
|
+
Type-safe proxy-based values references with full IDE support:
|
|
34
|
+
|
|
35
|
+
- Import: `import { valuesRef } from 'timonel'`
|
|
36
|
+
- **Comparison operators**: `eq`, `ne`, `gt`, `ge`, `lt`, `le`
|
|
37
|
+
- **Logical operators**: `not`, `and`, `or`
|
|
38
|
+
- **String functions**: `quote`, `upper`, `lower`, `trim`, `replace`, `contains`
|
|
39
|
+
- **Default values**: `default()`
|
|
40
|
+
- **Type checking**: `kindIs`, `hasKey`
|
|
41
|
+
- **YAML functions**: `toYaml`, `toJson`, `nindent`, `indent`
|
|
42
|
+
- **Field-level conditionals**: `v.if()`, `v.ifElse()` - Complex conditional logic
|
|
43
|
+
- **Range loops**: `v.range()` - Type-safe iteration
|
|
44
|
+
- **Context switching**: `v.with()` - Scoped value access
|
|
45
|
+
|
|
46
|
+
#### Composable Helpers
|
|
47
|
+
|
|
48
|
+
Template definition and inclusion helpers:
|
|
49
|
+
|
|
50
|
+
- `helmInclude`, `helmDefine`, `helmVar`, `helmBlock`, `helmComment`, `helmFragment`
|
|
51
|
+
- `template`, `include`, `quote`, `indent`
|
|
52
|
+
|
|
53
|
+
#### Value Reference Helpers
|
|
54
|
+
|
|
55
|
+
Useful string-based utilities (no ValuesRef equivalent):
|
|
56
|
+
|
|
57
|
+
- `requiredValuesRef` - Required value with validation
|
|
58
|
+
- `numberRef`, `boolRef`, `floatRef` - Type-cast references (int, bool, float64)
|
|
59
|
+
- `base64Ref` - Base64 encoding
|
|
60
|
+
|
|
61
|
+
#### Legacy Helpers (NOT RECOMMENDED)
|
|
62
|
+
|
|
63
|
+
**ā ļø Use ValuesRef system instead:**
|
|
64
|
+
|
|
65
|
+
- `valuesRef(path)` ā use `v.path` (ValuesRef system)
|
|
66
|
+
- `stringRef()` ā use `v.quote()` (ValuesRef system)
|
|
67
|
+
- `defaultRef()` ā use `v.default()` (ValuesRef system)
|
|
68
|
+
- `jsonRef()` ā use `v.toJson()` (ValuesRef system)
|
|
69
|
+
- `conditionalRef()` ā use `v.if()` (ValuesRef system)
|
|
70
|
+
- `helmIf`, `helmIfSimple` ā use `v.if()` (ValuesRef system)
|
|
71
|
+
- `helmRange` ā use `v.range()` (ValuesRef system)
|
|
72
|
+
- `helmWith` ā use `v.with()` (ValuesRef system)
|
|
73
|
+
- `helmIfElseIf` ā use `v.if()` with nested conditions
|
|
74
|
+
|
|
75
|
+
### Enhanced Helm Helpers
|
|
76
|
+
|
|
77
|
+
- **Environment Helpers**: `envRef`, `envDefault`, `envRequired`, `envFromSecret`, `envFromConfigMap`
|
|
78
|
+
- **GitOps Helpers**: `gitBranch`, `gitCommit`, `gitTag`, `gitopsAnnotations`
|
|
79
|
+
- **Observability Helpers**: `prometheusAnnotations`, `datadogAnnotations`, `tracingAnnotations`
|
|
80
|
+
- **Validation Helpers**: `validateRequired`, `validatePattern`, `validateRange`, `validateEnum`
|
|
81
|
+
- **Standard Helpers**: 40+ built-in Helm helpers (chart.name, chart.fullname, chart.labels, etc.)
|
|
82
|
+
|
|
83
|
+
### Cloud Integrations
|
|
84
|
+
|
|
85
|
+
- **AWS Resources**:
|
|
86
|
+
- EBS/EFS StorageClass with encryption and performance options
|
|
87
|
+
- ALB Ingress with SSL/TLS and health checks
|
|
88
|
+
- IRSA ServiceAccount for pod-level IAM roles
|
|
89
|
+
- ECR integration
|
|
90
|
+
- Karpenter NodePool, NodeClaim, and EC2NodeClass
|
|
91
|
+
- **Karpenter Features**:
|
|
92
|
+
- Disruption budgets and consolidation policies
|
|
93
|
+
- Instance type selection and requirements
|
|
94
|
+
- Spot instance support
|
|
95
|
+
- Custom AMI and user data
|
|
96
|
+
|
|
97
|
+
### Security & Validation
|
|
98
|
+
|
|
99
|
+
- **š”ļø Security-first approach**:
|
|
100
|
+
- Input validation (CWE-20, CWE-22/23)
|
|
101
|
+
- Path traversal prevention
|
|
102
|
+
- Command injection prevention (CWE-78/77/88)
|
|
103
|
+
- Log injection protection (CWE-117)
|
|
104
|
+
- Code injection prevention (CWE-94)
|
|
105
|
+
- **š Policy Engine** (NEW):
|
|
106
|
+
- Extensible validation framework for Kubernetes manifests
|
|
107
|
+
- Plugin-based architecture for custom policy rules
|
|
108
|
+
- Zero-impact integration (completely optional)
|
|
109
|
+
- Support for security, compliance, and best practice policies
|
|
110
|
+
- **NetworkPolicy support** for pod-level network isolation
|
|
111
|
+
- **Helm chart validation** with `validateHelmYaml`
|
|
112
|
+
- **SecurityUtils** for path validation and sanitization
|
|
113
|
+
|
|
114
|
+
### Developer Experience
|
|
115
|
+
|
|
116
|
+
- **Structured logging** with Pino (JSON format, performance tracking)
|
|
117
|
+
- **Environment variables loader** for external configuration
|
|
118
|
+
- **YAML serialization** with Helm template preservation
|
|
119
|
+
- **TypeScript strict mode** with all compiler checks enabled
|
|
120
|
+
- **Comprehensive error handling** with detailed messages
|
|
32
121
|
|
|
33
122
|
## š Quick Start
|
|
34
123
|
|
|
@@ -128,6 +217,64 @@ chart.addManifest(
|
|
|
128
217
|
chart.write('./dist');
|
|
129
218
|
```
|
|
130
219
|
|
|
220
|
+
### Policy Engine Integration
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import { Rutter, PolicyEngine } from 'timonel';
|
|
224
|
+
import { securityPolicies } from '@mycompany/k8s-security-policies';
|
|
225
|
+
|
|
226
|
+
// Create policy engine with custom plugins
|
|
227
|
+
const policyEngine = new PolicyEngine().use(securityPolicies).configure({
|
|
228
|
+
timeout: 5000,
|
|
229
|
+
parallel: true,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const chart = new Rutter({
|
|
233
|
+
meta: {
|
|
234
|
+
name: 'secure-app',
|
|
235
|
+
version: '1.0.0',
|
|
236
|
+
},
|
|
237
|
+
// Optional policy validation
|
|
238
|
+
policyEngine,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Policies validate manifests before chart generation
|
|
242
|
+
chart.write('./dist'); // Fails if policy violations found
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Creating Custom Policy Plugins
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { PolicyPlugin, PolicyViolation } from 'timonel';
|
|
249
|
+
|
|
250
|
+
export const mySecurityPolicy: PolicyPlugin = {
|
|
251
|
+
name: 'my-security-policy',
|
|
252
|
+
version: '1.0.0',
|
|
253
|
+
description: 'Custom security validation rules',
|
|
254
|
+
|
|
255
|
+
async validate(manifests, context) {
|
|
256
|
+
const violations: PolicyViolation[] = [];
|
|
257
|
+
|
|
258
|
+
for (const manifest of manifests) {
|
|
259
|
+
if (manifest.kind === 'Deployment') {
|
|
260
|
+
// Check for security context
|
|
261
|
+
if (!manifest.spec?.template?.spec?.securityContext) {
|
|
262
|
+
violations.push({
|
|
263
|
+
plugin: this.name,
|
|
264
|
+
severity: 'error',
|
|
265
|
+
message: 'Deployment must specify securityContext',
|
|
266
|
+
resourcePath: `${manifest.kind}/${manifest.metadata?.name}`,
|
|
267
|
+
suggestion: 'Add spec.template.spec.securityContext to your Deployment',
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return violations;
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
```
|
|
277
|
+
|
|
131
278
|
### Umbrella Chart with Multiple Services
|
|
132
279
|
|
|
133
280
|
```typescript
|
|
@@ -153,146 +300,478 @@ const umbrellaConfig = {
|
|
|
153
300
|
export const umbrella = new UmbrellaChartTemplate(umbrellaConfig);
|
|
154
301
|
```
|
|
155
302
|
|
|
156
|
-
### Type-Safe Helm Helpers
|
|
303
|
+
### Using Type-Safe Helm Helpers
|
|
304
|
+
|
|
305
|
+
#### ValuesRef System (Recommended)
|
|
306
|
+
|
|
307
|
+
The new ValuesRef system provides a type-safe, proxy-based approach to Helm values with full IDE support.
|
|
157
308
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
`helmFragment`.
|
|
309
|
+
**ā ļø Important:** This is completely different from the legacy `valuesRef(path: string)` helper.
|
|
310
|
+
The new system uses generics and returns a proxy object with methods.
|
|
161
311
|
|
|
162
|
-
|
|
312
|
+
```typescript
|
|
313
|
+
import { valuesRef } from 'timonel';
|
|
163
314
|
|
|
164
|
-
|
|
315
|
+
interface MyValues {
|
|
316
|
+
replicaCount: number;
|
|
317
|
+
image: { repository: string; tag: string };
|
|
318
|
+
autoscaling: { enabled: boolean; minReplicas: number };
|
|
319
|
+
}
|
|
165
320
|
|
|
166
|
-
|
|
167
|
-
loaded from external sources (e.g., Vault during CI/CD).
|
|
321
|
+
const v = valuesRef<MyValues>();
|
|
168
322
|
|
|
169
|
-
|
|
323
|
+
// Type-safe value references with IDE autocomplete
|
|
324
|
+
const replicas = v.replicaCount; // {{ .Values.replicaCount }}
|
|
325
|
+
const imageTag = v.image.tag; // {{ .Values.image.tag }}
|
|
170
326
|
|
|
171
|
-
|
|
327
|
+
// Comparison operators
|
|
328
|
+
const isProd = v.environment.eq('production'); // eq .Values.environment "production"
|
|
329
|
+
const hasReplicas = v.replicaCount.gt(1); // gt .Values.replicaCount 1
|
|
172
330
|
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
331
|
+
// Logical operators
|
|
332
|
+
const notEnabled = v.autoscaling.enabled.not(); // not .Values.autoscaling.enabled
|
|
333
|
+
|
|
334
|
+
// String functions
|
|
335
|
+
const upperEnv = v.environment.upper(); // .Values.environment | upper
|
|
336
|
+
const quotedTag = v.image.tag.quote(); // .Values.image.tag | quote
|
|
337
|
+
|
|
338
|
+
// Default values
|
|
339
|
+
const port = v.port.default(8080); // {{ .Values.port | default 8080 }}
|
|
340
|
+
|
|
341
|
+
// Field-level conditionals
|
|
342
|
+
const deployment = {
|
|
343
|
+
spec: {
|
|
344
|
+
replicas: v.if(notEnabled, v.replicaCount), // Conditionally include field
|
|
345
|
+
},
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// Range loops
|
|
349
|
+
const envVars = v.env.range((item, index) => ({
|
|
350
|
+
name: item.name,
|
|
351
|
+
value: item.value,
|
|
352
|
+
}));
|
|
353
|
+
|
|
354
|
+
// Context switching
|
|
355
|
+
const dbConfig = v.database.with((db) => ({
|
|
356
|
+
host: db.host,
|
|
357
|
+
port: db.port,
|
|
358
|
+
}));
|
|
178
359
|
```
|
|
179
360
|
|
|
180
|
-
|
|
361
|
+
#### Template Composition Helpers
|
|
181
362
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
363
|
+
Use these helpers for template definitions and inclusions:
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
import { helmInclude, helmDefine, helmFragment } from 'timonel';
|
|
367
|
+
|
|
368
|
+
// Template inclusion with pipe
|
|
369
|
+
const labels = helmInclude('chart.labels', '.', { pipe: 'nindent 4' });
|
|
370
|
+
|
|
371
|
+
// Define a named template
|
|
372
|
+
const myTemplate = helmDefine('myapp.config', {
|
|
373
|
+
key: 'value',
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// Combine multiple constructs
|
|
377
|
+
const combined = helmFragment(helmInclude('chart.labels', '.'), { customKey: 'customValue' });
|
|
186
378
|
```
|
|
187
379
|
|
|
188
|
-
|
|
380
|
+
#### Legacy Flow Control (NOT RECOMMENDED)
|
|
381
|
+
|
|
382
|
+
**ā ļø These are legacy and NOT RECOMMENDED. Use ValuesRef system (v.if, v.range, v.with)
|
|
383
|
+
instead:**
|
|
189
384
|
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
value: { { .Values.global.env.VERSION | default "1.0.0" } }
|
|
385
|
+
```typescript
|
|
386
|
+
// ā OLD WAY - string-based valuesRef (no type safety)
|
|
387
|
+
const oldRef = valuesRef('.Values.production');
|
|
194
388
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
389
|
+
// ā
NEW WAY - ValuesRef system (type-safe)
|
|
390
|
+
const v = valuesRef<MyValues>();
|
|
391
|
+
const newRef = v.production; // {{ .Values.production }}
|
|
392
|
+
|
|
393
|
+
// ā OLD WAY - helmIf, helmRange, helmWith (string-based)
|
|
394
|
+
const config = helmIf('.Values.production', { replicas: 5 }, { replicas: 1 });
|
|
395
|
+
|
|
396
|
+
// ā
NEW WAY - v.if(), v.range(), v.with() (type-safe)
|
|
397
|
+
const config = v.if(v.production, { replicas: 5 });
|
|
202
398
|
```
|
|
203
399
|
|
|
400
|
+
**Why ValuesRef is Better:**
|
|
401
|
+
|
|
402
|
+
- ā
**100% Type-Safe** - Catch errors at compile time with TypeScript generics
|
|
403
|
+
- ā
**No Raw Strings** - Eliminate manual template interpolation and typos
|
|
404
|
+
- ā
**Full IDE Support** - Autocomplete, type hints, and refactoring support
|
|
405
|
+
- ā
**Proxy-based** - Chainable methods for complex logic
|
|
406
|
+
- ā
**Composable** - Nest and combine operations naturally
|
|
407
|
+
- ā **Legacy helpers** - String-based, error-prone, no IDE support
|
|
408
|
+
|
|
409
|
+
**Migration:** Replace `valuesRef(path)` with `v.path`. Replace `helmIf`, `helmRange`, `helmWith`
|
|
410
|
+
with `v.if()`, `v.range()`, `v.with()`.
|
|
411
|
+
|
|
412
|
+
**Learn more:** See the
|
|
413
|
+
[Type-Safe Helm Helpers Guide](https://github.com/KenkoGeek/timonel/wiki/Helm-Helpers-System) for
|
|
414
|
+
complete documentation, examples, and best practices.
|
|
415
|
+
|
|
416
|
+
## š Policy Engine
|
|
417
|
+
|
|
418
|
+
The Policy Engine provides extensible validation for Kubernetes manifests through a
|
|
419
|
+
plugin-based architecture. It's completely optional and has zero impact on existing users.
|
|
420
|
+
|
|
421
|
+
### Key Features
|
|
422
|
+
|
|
423
|
+
- **š Plugin Architecture**: Extensible through external npm packages
|
|
424
|
+
- **ā” Zero Impact**: Completely optional with no performance overhead when unused
|
|
425
|
+
- **š”ļø Security Focus**: Built-in support for security and compliance policies
|
|
426
|
+
- **š Async Support**: Handles both synchronous and asynchronous validation plugins
|
|
427
|
+
- **š Rich Reporting**: Detailed violation reports with suggestions and context
|
|
428
|
+
- **ā±ļø Timeout Protection**: Configurable timeouts prevent hanging validations
|
|
429
|
+
- **š§ Configurable**: Environment-specific policy configuration support
|
|
430
|
+
- **š Performance Optimized**: Parallel execution, caching, and resource monitoring
|
|
431
|
+
- **š Error Resilience**: Graceful degradation and retry mechanisms
|
|
432
|
+
- **š Observability**: Structured logging and performance metrics
|
|
433
|
+
|
|
434
|
+
### Quick Start
|
|
435
|
+
|
|
204
436
|
```typescript
|
|
205
|
-
import { Rutter,
|
|
437
|
+
import { Rutter, PolicyEngine } from 'timonel';
|
|
438
|
+
|
|
439
|
+
// Optional: Add policy validation
|
|
440
|
+
const policyEngine = new PolicyEngine({
|
|
441
|
+
timeout: 10000,
|
|
442
|
+
parallel: true,
|
|
443
|
+
gracefulDegradation: true,
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
// Register plugins
|
|
447
|
+
await policyEngine.use(await import('@mycompany/security-policies'));
|
|
448
|
+
await policyEngine.use(await import('@kubernetes/best-practices'));
|
|
206
449
|
|
|
207
450
|
const chart = new Rutter({
|
|
208
|
-
meta: {
|
|
209
|
-
|
|
210
|
-
version: '1.0.0',
|
|
211
|
-
description: 'Simple web application',
|
|
212
|
-
},
|
|
213
|
-
defaultValues: {
|
|
214
|
-
replicas: 3,
|
|
215
|
-
image: {
|
|
216
|
-
repository: 'nginx',
|
|
217
|
-
tag: 'latest',
|
|
218
|
-
},
|
|
219
|
-
},
|
|
451
|
+
meta: { name: 'my-app', version: '1.0.0' },
|
|
452
|
+
policyEngine, // ā Completely optional
|
|
220
453
|
});
|
|
221
454
|
|
|
222
|
-
//
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
455
|
+
chart.write('./dist'); // Validates before writing
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Available Policy Plugins
|
|
459
|
+
|
|
460
|
+
**Built-in Examples:**
|
|
461
|
+
|
|
462
|
+
- **Security Plugin** - Comprehensive security validation (security contexts, RBAC, network policies)
|
|
463
|
+
- **Best Practices Plugin** - Kubernetes best practices (resource limits, naming, probes)
|
|
464
|
+
- **AWS Plugin** - AWS-specific validations (EKS, ALB, IRSA, cost optimization)
|
|
465
|
+
|
|
466
|
+
**Community Plugins:**
|
|
467
|
+
|
|
468
|
+
- `@kubernetes/pod-security-standards` - Official Kubernetes PSS validation
|
|
469
|
+
- `@open-policy-agent/timonel-plugin` - OPA Rego policy integration
|
|
470
|
+
- `@falco/security-policies` - Falco runtime security rules
|
|
471
|
+
|
|
472
|
+
**Enterprise Plugins:**
|
|
473
|
+
|
|
474
|
+
- `@company/compliance-policies` - Organization-specific compliance rules
|
|
475
|
+
- `@aws/well-architected-policies` - AWS Well-Architected Framework validation
|
|
476
|
+
- `@security/cis-benchmarks` - CIS Kubernetes Benchmark validation
|
|
477
|
+
|
|
478
|
+
### Creating Custom Policies
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
import { PolicyPlugin, PolicyViolation, ValidationContext } from 'timonel';
|
|
482
|
+
|
|
483
|
+
export const customSecurityPolicy: PolicyPlugin = {
|
|
484
|
+
name: 'custom-security-policy',
|
|
485
|
+
version: '1.0.0',
|
|
486
|
+
description: 'Custom security validation rules',
|
|
487
|
+
|
|
488
|
+
// Optional: Configuration schema for validation
|
|
489
|
+
configSchema: {
|
|
490
|
+
type: 'object',
|
|
491
|
+
properties: {
|
|
492
|
+
strictMode: { type: 'boolean', default: false },
|
|
493
|
+
allowedNamespaces: { type: 'array', items: { type: 'string' } },
|
|
230
494
|
},
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
spec
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
495
|
+
},
|
|
496
|
+
|
|
497
|
+
async validate(manifests: unknown[], context: ValidationContext): Promise<PolicyViolation[]> {
|
|
498
|
+
const violations: PolicyViolation[] = [];
|
|
499
|
+
const config = context.config as { strictMode?: boolean; allowedNamespaces?: string[] };
|
|
500
|
+
|
|
501
|
+
for (const manifest of manifests) {
|
|
502
|
+
if (manifest.kind === 'Deployment') {
|
|
503
|
+
// Validate security context
|
|
504
|
+
if (!manifest.spec?.template?.spec?.securityContext) {
|
|
505
|
+
violations.push({
|
|
506
|
+
plugin: this.name,
|
|
507
|
+
severity: config?.strictMode ? 'error' : 'warning',
|
|
508
|
+
message: 'Deployment should specify securityContext',
|
|
509
|
+
resourcePath: `${manifest.kind}/${manifest.metadata?.name}`,
|
|
510
|
+
field: 'spec.template.spec.securityContext',
|
|
511
|
+
suggestion: 'Add securityContext with runAsNonRoot: true',
|
|
512
|
+
context: {
|
|
513
|
+
kubernetesVersion: context.kubernetesVersion,
|
|
514
|
+
environment: context.environment,
|
|
246
515
|
},
|
|
247
|
-
|
|
248
|
-
}
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Validate namespace restrictions
|
|
520
|
+
const namespace = manifest.metadata?.namespace || 'default';
|
|
521
|
+
if (config?.allowedNamespaces && !config.allowedNamespaces.includes(namespace)) {
|
|
522
|
+
violations.push({
|
|
523
|
+
plugin: this.name,
|
|
524
|
+
severity: 'error',
|
|
525
|
+
message: `Deployment in unauthorized namespace: ${namespace}`,
|
|
526
|
+
resourcePath: `${manifest.kind}/${manifest.metadata?.name}`,
|
|
527
|
+
field: 'metadata.namespace',
|
|
528
|
+
suggestion: `Deploy to allowed namespaces: ${config.allowedNamespaces.join(', ')}`,
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
return violations;
|
|
535
|
+
},
|
|
536
|
+
};
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
### Advanced Configuration
|
|
540
|
+
|
|
541
|
+
```typescript
|
|
542
|
+
const policyEngine = new PolicyEngine({
|
|
543
|
+
// Execution settings
|
|
544
|
+
timeout: 15000, // 15 second timeout per plugin
|
|
545
|
+
parallel: true, // Run plugins in parallel for better performance
|
|
546
|
+
failFast: false, // Collect all violations before failing
|
|
547
|
+
gracefulDegradation: true, // Continue on plugin failures
|
|
548
|
+
|
|
549
|
+
// Performance optimization
|
|
550
|
+
cacheOptions: {
|
|
551
|
+
maxSize: 1000, // Cache up to 1000 validation results
|
|
552
|
+
ttl: 300000, // 5 minute cache TTL
|
|
553
|
+
enableStats: true, // Enable cache performance monitoring
|
|
554
|
+
},
|
|
555
|
+
|
|
556
|
+
// Parallel execution tuning
|
|
557
|
+
parallelOptions: {
|
|
558
|
+
maxConcurrency: 4, // Run up to 4 plugins concurrently
|
|
559
|
+
enableResourceMonitoring: true,
|
|
560
|
+
},
|
|
561
|
+
|
|
562
|
+
// Retry configuration
|
|
563
|
+
retryConfig: {
|
|
564
|
+
maxAttempts: 3,
|
|
565
|
+
baseDelay: 1000,
|
|
566
|
+
retryOnTimeout: true,
|
|
567
|
+
retryOnPluginError: false,
|
|
568
|
+
},
|
|
569
|
+
|
|
570
|
+
// Plugin-specific configuration
|
|
571
|
+
pluginConfig: {
|
|
572
|
+
'security-plugin': {
|
|
573
|
+
strictMode: true,
|
|
574
|
+
allowedNamespaces: ['default', 'kube-system'],
|
|
575
|
+
securityContext: {
|
|
576
|
+
required: true,
|
|
577
|
+
runAsNonRoot: true,
|
|
578
|
+
},
|
|
579
|
+
},
|
|
580
|
+
'best-practices-plugin': {
|
|
581
|
+
enforceResourceLimits: true,
|
|
582
|
+
requireLabels: ['app', 'version', 'environment'],
|
|
583
|
+
maxReplicas: 50,
|
|
584
|
+
},
|
|
585
|
+
'aws-plugin': {
|
|
586
|
+
region: 'us-west-2',
|
|
587
|
+
enforceTagging: true,
|
|
588
|
+
costOptimization: {
|
|
589
|
+
enabled: true,
|
|
590
|
+
maxInstanceSize: 'xlarge',
|
|
249
591
|
},
|
|
250
592
|
},
|
|
251
593
|
},
|
|
252
|
-
|
|
253
|
-
);
|
|
594
|
+
});
|
|
254
595
|
|
|
255
|
-
//
|
|
256
|
-
|
|
596
|
+
// Register plugins
|
|
597
|
+
await policyEngine.use(securityPolicies);
|
|
598
|
+
await policyEngine.use(bestPracticesPolicies);
|
|
599
|
+
await policyEngine.use(awsPolicies);
|
|
257
600
|
```
|
|
258
601
|
|
|
259
|
-
|
|
260
|
-
import { UmbrellaChartTemplate } from 'timonel';
|
|
602
|
+
### Environment-Specific Policies
|
|
261
603
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
chart: frontendChartFunction,
|
|
270
|
-
},
|
|
271
|
-
{
|
|
272
|
-
name: 'backend',
|
|
273
|
-
version: '1.0.0',
|
|
274
|
-
chart: backendChartFunction,
|
|
604
|
+
```typescript
|
|
605
|
+
// Load different policies based on environment
|
|
606
|
+
const createPolicyEngine = (environment: string) => {
|
|
607
|
+
const engine = new PolicyEngine({
|
|
608
|
+
environment,
|
|
609
|
+
configurationLoader: {
|
|
610
|
+
configurationFiles: ['config/policy-engine.json', `config/environments/${environment}.json`],
|
|
275
611
|
},
|
|
276
|
-
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
// Base security policies for all environments
|
|
615
|
+
await engine.use(baseSecurity);
|
|
616
|
+
|
|
617
|
+
// Environment-specific policies
|
|
618
|
+
switch (environment) {
|
|
619
|
+
case 'production':
|
|
620
|
+
await engine.use(strictSecurity);
|
|
621
|
+
await engine.use(compliancePolicies);
|
|
622
|
+
await engine.use(awsPolicies);
|
|
623
|
+
break;
|
|
624
|
+
case 'staging':
|
|
625
|
+
await engine.use(moderateSecurity);
|
|
626
|
+
await engine.use(awsPolicies);
|
|
627
|
+
break;
|
|
628
|
+
case 'development':
|
|
629
|
+
// Minimal policies for development
|
|
630
|
+
await engine.use(basicSecurity);
|
|
631
|
+
break;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
return engine;
|
|
277
635
|
};
|
|
636
|
+
```
|
|
278
637
|
|
|
279
|
-
|
|
638
|
+
### Integration with CI/CD
|
|
639
|
+
|
|
640
|
+
```typescript
|
|
641
|
+
// In your CI/CD pipeline
|
|
642
|
+
import { Rutter, PolicyEngine, PolicyEngineError } from 'timonel';
|
|
643
|
+
|
|
644
|
+
const validateChart = async (chartPath: string, environment: string) => {
|
|
645
|
+
const policyEngine = await createPolicyEngine(environment);
|
|
646
|
+
|
|
647
|
+
try {
|
|
648
|
+
const chart = new Rutter({
|
|
649
|
+
meta: { name: 'my-app', version: process.env.VERSION },
|
|
650
|
+
policyEngine,
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
await chart.write(chartPath);
|
|
654
|
+
|
|
655
|
+
// Log validation success with metrics
|
|
656
|
+
const stats = policyEngine.getCacheStats();
|
|
657
|
+
console.log('ā
Chart validation passed', {
|
|
658
|
+
environment,
|
|
659
|
+
cacheHitRate: stats.hitRate,
|
|
660
|
+
pluginCount: policyEngine.getPluginCount(),
|
|
661
|
+
});
|
|
662
|
+
} catch (error) {
|
|
663
|
+
if (error instanceof PolicyEngineError) {
|
|
664
|
+
console.error('ā Policy violations found:');
|
|
665
|
+
|
|
666
|
+
// Group violations by severity
|
|
667
|
+
const errors = error.violations.filter((v) => v.severity === 'error');
|
|
668
|
+
const warnings = error.violations.filter((v) => v.severity === 'warning');
|
|
669
|
+
|
|
670
|
+
if (errors.length > 0) {
|
|
671
|
+
console.error(`\nšØ Errors (${errors.length}):`);
|
|
672
|
+
errors.forEach((v) => {
|
|
673
|
+
console.error(` ⢠${v.resourcePath}: ${v.message}`);
|
|
674
|
+
if (v.suggestion) {
|
|
675
|
+
console.error(` š” ${v.suggestion}`);
|
|
676
|
+
}
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
if (warnings.length > 0) {
|
|
681
|
+
console.warn(`\nā ļø Warnings (${warnings.length}):`);
|
|
682
|
+
warnings.forEach((v) => {
|
|
683
|
+
console.warn(` ⢠${v.resourcePath}: ${v.message}`);
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Fail CI/CD on errors, but allow warnings
|
|
688
|
+
if (errors.length > 0) {
|
|
689
|
+
process.exit(1);
|
|
690
|
+
}
|
|
691
|
+
} else {
|
|
692
|
+
throw error;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
// Usage in GitHub Actions, GitLab CI, etc.
|
|
698
|
+
await validateChart('./dist', process.env.ENVIRONMENT || 'development');
|
|
280
699
|
```
|
|
281
700
|
|
|
282
|
-
|
|
283
|
-
`helmRange`, `helmWith`, `helmInclude`, `helmDefine`, `helmVar`, `helmBlock`, `helmComment`, and
|
|
284
|
-
`helmFragment`.
|
|
701
|
+
### Plugin Ecosystem
|
|
285
702
|
|
|
286
|
-
|
|
703
|
+
The Policy Engine supports a rich ecosystem of plugins for various use cases:
|
|
287
704
|
|
|
288
|
-
|
|
289
|
-
- ā
No Raw Strings - eliminate manual template interpolation
|
|
290
|
-
- ā
Composable - nest and combine helpers freely
|
|
291
|
-
- ā
Full IDE Support - autocomplete and type hints
|
|
705
|
+
#### Security & Compliance
|
|
292
706
|
|
|
293
|
-
**
|
|
294
|
-
|
|
295
|
-
|
|
707
|
+
- **Pod Security Standards** - Kubernetes PSS validation
|
|
708
|
+
- **CIS Benchmarks** - Center for Internet Security benchmarks
|
|
709
|
+
- **NIST Framework** - NIST Cybersecurity Framework compliance
|
|
710
|
+
- **PCI DSS** - Payment Card Industry compliance
|
|
711
|
+
- **SOC 2** - Service Organization Control 2 compliance
|
|
712
|
+
|
|
713
|
+
#### Cloud Provider Integrations
|
|
714
|
+
|
|
715
|
+
- **AWS Well-Architected** - AWS best practices and cost optimization
|
|
716
|
+
- **Azure Security Center** - Azure-specific security policies
|
|
717
|
+
- **GCP Security Command Center** - Google Cloud security validation
|
|
718
|
+
|
|
719
|
+
#### Development & Operations
|
|
720
|
+
|
|
721
|
+
- **GitOps Policies** - GitOps workflow validation
|
|
722
|
+
- **Resource Optimization** - Cost and performance optimization
|
|
723
|
+
- **Observability** - Monitoring and logging best practices
|
|
724
|
+
- **Backup & Recovery** - Data protection policies
|
|
725
|
+
|
|
726
|
+
#### Creating Plugin Packages
|
|
727
|
+
|
|
728
|
+
```typescript
|
|
729
|
+
// package.json for a policy plugin
|
|
730
|
+
{
|
|
731
|
+
"name": "@mycompany/k8s-security-policies",
|
|
732
|
+
"version": "1.0.0",
|
|
733
|
+
"description": "Security policies for Kubernetes manifests",
|
|
734
|
+
"main": "dist/index.js",
|
|
735
|
+
"types": "dist/index.d.ts",
|
|
736
|
+
"keywords": ["timonel", "policy", "security", "kubernetes"],
|
|
737
|
+
"peerDependencies": {
|
|
738
|
+
"timonel": "^3.0.0"
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// src/index.ts
|
|
743
|
+
export { SecurityPlugin } from './security-plugin.js';
|
|
744
|
+
export { CompliancePlugin } from './compliance-plugin.js';
|
|
745
|
+
export type { SecurityConfig, ComplianceConfig } from './types.js';
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
### Performance & Monitoring
|
|
749
|
+
|
|
750
|
+
The Policy Engine includes comprehensive performance monitoring:
|
|
751
|
+
|
|
752
|
+
```typescript
|
|
753
|
+
// Monitor policy engine performance
|
|
754
|
+
const result = await policyEngine.validate(manifests, { name: 'example-chart', version: '1.0.0' });
|
|
755
|
+
|
|
756
|
+
console.log('Validation Performance:', {
|
|
757
|
+
executionTime: result.metadata.executionTime,
|
|
758
|
+
pluginCount: result.metadata.pluginCount,
|
|
759
|
+
manifestCount: result.metadata.manifestCount,
|
|
760
|
+
violationsFound: result.violations.length,
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
// Cache performance monitoring
|
|
764
|
+
const cacheStats = policyEngine.getCacheStats();
|
|
765
|
+
console.log('Cache Performance:', {
|
|
766
|
+
hitRate: cacheStats.hitRate,
|
|
767
|
+
totalHits: cacheStats.hits,
|
|
768
|
+
totalMisses: cacheStats.misses,
|
|
769
|
+
cacheSize: cacheStats.size,
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
// Clear cache when needed
|
|
773
|
+
policyEngine.invalidateCache({ all: true });
|
|
774
|
+
```
|
|
296
775
|
|
|
297
776
|
## š Documentation
|
|
298
777
|
|
|
@@ -300,6 +779,14 @@ complete documentation, examples, and best practices.
|
|
|
300
779
|
documentation
|
|
301
780
|
- **[CLI Reference](https://github.com/KenkoGeek/timonel/wiki/CLI-Reference)** - Command-line
|
|
302
781
|
interface guide
|
|
782
|
+
- **[Policy Engine Guide](https://github.com/KenkoGeek/timonel/wiki/Policy-Engine)** -
|
|
783
|
+
Policy validation and plugin development
|
|
784
|
+
- **[Plugin Development Guide](https://github.com/KenkoGeek/timonel/wiki/Plugin-Development)** -
|
|
785
|
+
Creating custom policy plugins
|
|
786
|
+
- **[Configuration Reference](https://github.com/KenkoGeek/timonel/wiki/Policy-Configuration)** -
|
|
787
|
+
Policy engine configuration options
|
|
788
|
+
- **[Policy Examples](https://github.com/KenkoGeek/timonel/wiki/Policy-Examples)** - Example plugins
|
|
789
|
+
and usage patterns
|
|
303
790
|
- **[Examples](https://github.com/KenkoGeek/timonel/wiki/Examples)** - Real-world usage examples
|
|
304
791
|
- **[Best Practices](https://github.com/KenkoGeek/timonel/wiki/Best-Practices)** - Recommended
|
|
305
792
|
patterns and practices
|
|
@@ -324,10 +811,10 @@ If you get `Error: Cannot find module 'cdk8s'` when running `tl umbrella synth`:
|
|
|
324
811
|
"version": "1.0.0",
|
|
325
812
|
"type": "module",
|
|
326
813
|
"dependencies": {
|
|
327
|
-
"cdk8s": "^2.70.
|
|
328
|
-
"cdk8s-plus-33": "^2.
|
|
329
|
-
"constructs": "^10.4.
|
|
330
|
-
"timonel": "^
|
|
814
|
+
"cdk8s": "^2.70.28",
|
|
815
|
+
"cdk8s-plus-33": "^2.4.6",
|
|
816
|
+
"constructs": "^10.4.3",
|
|
817
|
+
"timonel": "^3.0.0-beta.1"
|
|
331
818
|
},
|
|
332
819
|
"devDependencies": {
|
|
333
820
|
"@types/node": "^24.5.2",
|
|
@@ -362,7 +849,7 @@ MIT
|
|
|
362
849
|
[security-url]: SECURITY.md
|
|
363
850
|
[pnpm-badge]: https://img.shields.io/badge/pm-pnpm-ffd95a?logo=pnpm&logoColor=fff&labelColor=24292e
|
|
364
851
|
[pnpm-url]: https://pnpm.io/
|
|
365
|
-
[node-badge]: https://img.shields.io/badge/node-%3E%
|
|
852
|
+
[node-badge]: https://img.shields.io/badge/node-%3E%3D22-339933?logo=node.js&logoColor=fff
|
|
366
853
|
[node-url]: https://nodejs.org/
|
|
367
854
|
[ts-badge]: https://img.shields.io/badge/TypeScript-5.x-3178C6?logo=typescript&logoColor=fff
|
|
368
855
|
[ts-url]: https://www.typescriptlang.org/
|