timonel 0.4.0 → 2.0.0
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 +56 -0
- package/README.md +343 -9
- package/dist/cli.js +32 -72
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -20
- package/dist/index.js.map +1 -1
- package/dist/lib/HelmChartWriter.js +11 -53
- package/dist/lib/HelmChartWriter.js.map +1 -1
- package/dist/lib/Rutter.d.ts +292 -4
- package/dist/lib/Rutter.d.ts.map +1 -1
- package/dist/lib/Rutter.js +587 -56
- package/dist/lib/Rutter.js.map +1 -1
- package/dist/lib/UmbrellaRutter.d.ts +2 -2
- package/dist/lib/UmbrellaRutter.d.ts.map +1 -1
- package/dist/lib/UmbrellaRutter.js +12 -20
- package/dist/lib/UmbrellaRutter.js.map +1 -1
- package/dist/lib/helm.js +11 -24
- package/dist/lib/helm.js.map +1 -1
- package/dist/lib/umbrella.d.ts +2 -2
- package/dist/lib/umbrella.d.ts.map +1 -1
- package/dist/lib/umbrella.js +3 -6
- package/dist/lib/umbrella.js.map +1 -1
- package/package.json +17 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,59 @@
|
|
|
1
|
+
# [2.0.0](https://github.com/KenkoGeek/timonel/compare/v1.0.0...v2.0.0) (2025-09-07)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
- **ci:** remove redundant publish workflow and configure release token ([fcea159](https://github.com/KenkoGeek/timonel/commit/fcea15914617e372a2aafc8a30001cc54ec8bff6))
|
|
6
|
+
- **examples:** update timonel dependency to ^1.0.0 ([3d1f692](https://github.com/KenkoGeek/timonel/commit/3d1f6922448648c7efe57cc1fdde9a5808e04d7e))
|
|
7
|
+
- **helm:** remove automatic numbering from template files ([#20](https://github.com/KenkoGeek/timonel/issues/20)) ([f75748a](https://github.com/KenkoGeek/timonel/commit/f75748aee974a254f576807f26396b026262b42c))
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- **ci:** add automatic CHANGELOG.md formatting to semantic-release ([6846b4d](https://github.com/KenkoGeek/timonel/commit/6846b4de2cfd411b7b9b9724d67830cf192ad2b9))
|
|
12
|
+
- **core:** add Azure Application Gateway Ingress Controller (AGIC) support ([#19](https://github.com/KenkoGeek/timonel/issues/19)) ([75bbb99](https://github.com/KenkoGeek/timonel/commit/75bbb998981ca6492b09ad12c54e03050b307c27))
|
|
13
|
+
- **core:** add Azure Disk StorageClass helper for AKS ([#18](https://github.com/KenkoGeek/timonel/issues/18)) ([5fb29de](https://github.com/KenkoGeek/timonel/commit/5fb29de260c4cabf6732520b0834cf0d0421a33a))
|
|
14
|
+
|
|
15
|
+
### BREAKING CHANGES
|
|
16
|
+
|
|
17
|
+
- **helm:** Template files no longer have automatic numbering prefixes
|
|
18
|
+
|
|
19
|
+
- refactor(helm): unify template naming strategy and add breaking change notice
|
|
20
|
+
|
|
21
|
+
* Simplify file naming logic with unified approach
|
|
22
|
+
* Use consistent naming strategy for single and multiple documents
|
|
23
|
+
* Add breaking change warning in README for numbered filename dependencies
|
|
24
|
+
* Improve code maintainability with cleaner implementation
|
|
25
|
+
|
|
26
|
+
Addresses PR review feedback for better consistency and user awareness.
|
|
27
|
+
|
|
28
|
+
# [1.0.0](https://github.com/KenkoGeek/timonel/compare/v0.4.0...v1.0.0) (2025-09-07)
|
|
29
|
+
|
|
30
|
+
### Bug Fixes
|
|
31
|
+
|
|
32
|
+
- **ci:** configure GitHub App token for semantic-release bypass - Use RELEASE_TOKEN from npm-prd environment for checkout and semantic-release ([0d385d1](https://github.com/KenkoGeek/timonel/commit/0d385d1084a45de3ab731094e87196239811e6fb))
|
|
33
|
+
- **ci:** disable body-max-line-length for semantic-release compatibility - Set body-max-line-length to 0 (disabled) to allow long changelog entries - Fixes semantic-release commit validation failures - Maintains other commitlint rules for developer commits ([b215f65](https://github.com/KenkoGeek/timonel/commit/b215f65bccb69a1cfca79084e6a9c96954fb478a))
|
|
34
|
+
- **ci:** disable footer line length limit for semantic-release commits ([d5ae4dc](https://github.com/KenkoGeek/timonel/commit/d5ae4dc83e68f8fade4a8289d1ce4e2bae5046dd))
|
|
35
|
+
- **ci:** disable footer-leading-blank for semantic-release compatibility - Set footer-leading-blank to 0 (disabled) to allow semantic-release footer format ([2f8c6c8](https://github.com/KenkoGeek/timonel/commit/2f8c6c863c6aabd1d3f3d8022b43fefecb02f010))
|
|
36
|
+
- **ci:** replace CodeQL with security check in release validation ([#15](https://github.com/KenkoGeek/timonel/issues/15)) ([b8cecea](https://github.com/KenkoGeek/timonel/commit/b8cecea1eaf0bb6af3e6fd2f6bc38c2fb2c09f4d))
|
|
37
|
+
- **ci:** resolve release workflow issues ([#16](https://github.com/KenkoGeek/timonel/issues/16)) ([ed5dc9b](https://github.com/KenkoGeek/timonel/commit/ed5dc9b3d86b531d4495d4d05dd913340333322c))
|
|
38
|
+
|
|
39
|
+
### Features
|
|
40
|
+
|
|
41
|
+
- add manual release workflow with GitHub Actions ([1035b2e](https://github.com/KenkoGeek/timonel/commit/1035b2e18fbb808e57438353c865ecd129d9e04d))
|
|
42
|
+
- add NetworkPolicy helpers for Zero Trust network security ([#13](https://github.com/KenkoGeek/timonel/issues/13)) ([cee3b58](https://github.com/KenkoGeek/timonel/commit/cee3b5876de839ca3cf16dd6ca6e3b76626392ce))
|
|
43
|
+
- **ci:** add required status checks validation to release workflow ([#14](https://github.com/KenkoGeek/timonel/issues/14)) ([7f8665f](https://github.com/KenkoGeek/timonel/commit/7f8665fa908215cc92a4dbefb7fec00de98464bb))
|
|
44
|
+
- **ci:** implement automated semantic release with conventional commits ([02ce189](https://github.com/KenkoGeek/timonel/commit/02ce18943efd8019168b5f9af29be0140a9e1524))
|
|
45
|
+
- **ci:** implement automated semantic release with conventional commits ([bb94fda](https://github.com/KenkoGeek/timonel/commit/bb94fda3e80bf3e010e7b53bdd1794f88060408a))
|
|
46
|
+
- **core:** add NetworkPolicy helpers for Zero Trust network security ([34ac6bd](https://github.com/KenkoGeek/timonel/commit/34ac6bda3956e5fe326b72e9831bd4bb8bc660da))
|
|
47
|
+
|
|
48
|
+
### Performance Improvements
|
|
49
|
+
|
|
50
|
+
- **ci:** homogenize CI/CD workflows and optimize release pipeline ([#17](https://github.com/KenkoGeek/timonel/issues/17)) ([4622d11](https://github.com/KenkoGeek/timonel/commit/4622d113e5753a5ff69c82a1e3784ecf61c34689))
|
|
51
|
+
|
|
52
|
+
### BREAKING CHANGES
|
|
53
|
+
|
|
54
|
+
- **ci:** ESLint configuration migrated to flat config format
|
|
55
|
+
- **ci:** ESLint configuration migrated to flat config format
|
|
56
|
+
|
|
1
57
|
# Changelog
|
|
2
58
|
|
|
3
59
|
All notable changes to this project will be documented in this file.
|
package/README.md
CHANGED
|
@@ -186,6 +186,11 @@ rutter.write('dist/charts/my-app');
|
|
|
186
186
|
|
|
187
187
|
### Custom Manifest Naming
|
|
188
188
|
|
|
189
|
+
> **⚠️ Breaking Change Notice**: Starting from v1.1.0, template files no longer include
|
|
190
|
+
> automatic numbering prefixes (0000-, 0001-, etc.). Files now use descriptive names
|
|
191
|
+
> following Helm best practices. If your scripts or tools depend on numbered filenames,
|
|
192
|
+
> please update them accordingly.
|
|
193
|
+
|
|
189
194
|
Timonel provides flexible options for naming your Kubernetes manifest files:
|
|
190
195
|
|
|
191
196
|
#### Single Manifest File
|
|
@@ -210,9 +215,9 @@ const rutter = new Rutter({
|
|
|
210
215
|
});
|
|
211
216
|
|
|
212
217
|
// Generates:
|
|
213
|
-
// templates/
|
|
214
|
-
// templates/
|
|
215
|
-
// templates/
|
|
218
|
+
// templates/my-app-deployment-web.yaml
|
|
219
|
+
// templates/my-app-service-web.yaml
|
|
220
|
+
// templates/my-app-configmap-config.yaml
|
|
216
221
|
```
|
|
217
222
|
|
|
218
223
|
#### Default Behavior
|
|
@@ -224,9 +229,9 @@ const rutter = new Rutter({
|
|
|
224
229
|
});
|
|
225
230
|
|
|
226
231
|
// Generates:
|
|
227
|
-
// templates/
|
|
228
|
-
// templates/
|
|
229
|
-
// templates/
|
|
232
|
+
// templates/deployment-web.yaml
|
|
233
|
+
// templates/service-web.yaml
|
|
234
|
+
// templates/configmap-config.yaml
|
|
230
235
|
```
|
|
231
236
|
|
|
232
237
|
## Umbrella Charts
|
|
@@ -315,9 +320,13 @@ shared values, and multi-environment support.
|
|
|
315
320
|
(`toString`, `float64`).
|
|
316
321
|
- For numeric fields (ports, replicas), use literal values or template strings with proper casting.
|
|
317
322
|
|
|
318
|
-
##
|
|
323
|
+
## Multi-Cloud Support
|
|
324
|
+
|
|
325
|
+
Timonel provides comprehensive cloud-specific helpers for major Kubernetes platforms:
|
|
326
|
+
|
|
327
|
+
### AWS Multi-Cloud Support
|
|
319
328
|
|
|
320
|
-
|
|
329
|
+
Comprehensive AWS-specific helpers for EKS deployments:
|
|
321
330
|
|
|
322
331
|
### IRSA (IAM Roles for Service Accounts)
|
|
323
332
|
|
|
@@ -429,6 +438,331 @@ rutter.addAWSSecretProviderClass({
|
|
|
429
438
|
});
|
|
430
439
|
```
|
|
431
440
|
|
|
441
|
+
### Azure Multi-Cloud Support
|
|
442
|
+
|
|
443
|
+
Azure-specific helpers for AKS deployments:
|
|
444
|
+
|
|
445
|
+
#### Azure Disk Storage Classes
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
// Premium ZRS disk for production workloads
|
|
449
|
+
rutter.addAzureDiskStorageClass({
|
|
450
|
+
name: 'azure-premium-zrs',
|
|
451
|
+
skuName: 'Premium_ZRS',
|
|
452
|
+
fsType: 'ext4',
|
|
453
|
+
cachingMode: 'ReadWrite',
|
|
454
|
+
allowVolumeExpansion: true,
|
|
455
|
+
volumeBindingMode: 'WaitForFirstConsumer',
|
|
456
|
+
tags: {
|
|
457
|
+
Environment: 'production',
|
|
458
|
+
Application: 'database',
|
|
459
|
+
},
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
// Standard SSD for cost-optimized workloads
|
|
463
|
+
rutter.addAzureDiskStorageClass({
|
|
464
|
+
name: 'azure-standard-ssd',
|
|
465
|
+
skuName: 'StandardSSD_LRS',
|
|
466
|
+
fsType: 'ext4',
|
|
467
|
+
cachingMode: 'ReadOnly',
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
// Ultra SSD for high-performance workloads
|
|
471
|
+
rutter.addAzureDiskStorageClass({
|
|
472
|
+
name: 'azure-ultra-ssd',
|
|
473
|
+
skuName: 'UltraSSD_LRS',
|
|
474
|
+
fsType: 'ext4',
|
|
475
|
+
cachingMode: 'None',
|
|
476
|
+
diskIOPSReadWrite: 2000,
|
|
477
|
+
diskMBpsReadWrite: 200,
|
|
478
|
+
logicalSectorSize: 4096,
|
|
479
|
+
});
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
#### Azure Application Gateway Ingress Controller (AGIC)
|
|
483
|
+
|
|
484
|
+
Comprehensive AGIC support for AKS deployments with advanced features:
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
// AGIC Ingress with SSL and health checks
|
|
488
|
+
rutter.addAzureAGICIngress({
|
|
489
|
+
name: 'app-ingress',
|
|
490
|
+
rules: [
|
|
491
|
+
{
|
|
492
|
+
host: 'app.example.com',
|
|
493
|
+
paths: [
|
|
494
|
+
{
|
|
495
|
+
path: '/',
|
|
496
|
+
pathType: 'Prefix',
|
|
497
|
+
backend: { service: { name: 'app-service', port: { number: 80 } } },
|
|
498
|
+
},
|
|
499
|
+
],
|
|
500
|
+
},
|
|
501
|
+
],
|
|
502
|
+
sslRedirect: true,
|
|
503
|
+
backendProtocol: 'https',
|
|
504
|
+
healthProbePath: '/health',
|
|
505
|
+
healthProbeInterval: 30,
|
|
506
|
+
cookieBasedAffinity: true,
|
|
507
|
+
requestTimeout: 60,
|
|
508
|
+
appgwSslCertificate: 'my-ssl-cert',
|
|
509
|
+
wafPolicyForPath:
|
|
510
|
+
'/subscriptions/sub-id/resourceGroups/rg/providers/Microsoft.Network/applicationGatewayWebApplicationFirewallPolicies/waf-policy',
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// Advanced AGIC features
|
|
514
|
+
rutter.addAzureAGICIngress({
|
|
515
|
+
name: 'advanced-ingress',
|
|
516
|
+
rules: [
|
|
517
|
+
/* rules */
|
|
518
|
+
],
|
|
519
|
+
backendPathPrefix: '/api/v1',
|
|
520
|
+
backendHostname: 'internal.example.com',
|
|
521
|
+
usePrivateIp: true,
|
|
522
|
+
overrideFrontendPort: 8080,
|
|
523
|
+
connectionDraining: true,
|
|
524
|
+
connectionDrainingTimeout: 60,
|
|
525
|
+
hostnameExtension: ['api.example.com', 'admin.example.com'],
|
|
526
|
+
appgwTrustedRootCertificate: ['root-cert-1', 'root-cert-2'],
|
|
527
|
+
rewriteRuleSet: 'custom-rewrite-rules',
|
|
528
|
+
rulePriority: 100,
|
|
529
|
+
});
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
## Network Security with NetworkPolicies
|
|
533
|
+
|
|
534
|
+
Timonel provides comprehensive NetworkPolicy helpers for implementing Zero Trust network security
|
|
535
|
+
in Kubernetes:
|
|
536
|
+
|
|
537
|
+
### Zero Trust Network Security
|
|
538
|
+
|
|
539
|
+
Implement defense-in-depth with deny-by-default policies:
|
|
540
|
+
|
|
541
|
+
```typescript
|
|
542
|
+
// 1. Deny all traffic by default (recommended starting point)
|
|
543
|
+
rutter.addDenyAllNetworkPolicy('default-deny-all');
|
|
544
|
+
|
|
545
|
+
// 2. Allow specific traffic as needed
|
|
546
|
+
rutter.addAllowFromPodsNetworkPolicy({
|
|
547
|
+
name: 'allow-frontend-to-backend',
|
|
548
|
+
targetPodSelector: { app: 'backend' },
|
|
549
|
+
sourcePodSelector: { app: 'frontend' },
|
|
550
|
+
ports: [{ protocol: 'TCP', port: 8080 }],
|
|
551
|
+
});
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### Advanced NetworkPolicy Examples
|
|
555
|
+
|
|
556
|
+
#### Multi-tier Application Security
|
|
557
|
+
|
|
558
|
+
```typescript
|
|
559
|
+
// Web tier - allow external traffic on port 80/443
|
|
560
|
+
rutter.addNetworkPolicy({
|
|
561
|
+
name: 'web-tier-policy',
|
|
562
|
+
podSelector: { matchLabels: { tier: 'web' } },
|
|
563
|
+
policyTypes: ['Ingress', 'Egress'],
|
|
564
|
+
ingress: [
|
|
565
|
+
{
|
|
566
|
+
ports: [
|
|
567
|
+
{ protocol: 'TCP', port: 80 },
|
|
568
|
+
{ protocol: 'TCP', port: 443 },
|
|
569
|
+
],
|
|
570
|
+
},
|
|
571
|
+
],
|
|
572
|
+
egress: [
|
|
573
|
+
// Allow access to app tier
|
|
574
|
+
{
|
|
575
|
+
to: [{ podSelector: { matchLabels: { tier: 'app' } } }],
|
|
576
|
+
ports: [{ protocol: 'TCP', port: 8080 }],
|
|
577
|
+
},
|
|
578
|
+
// Allow DNS resolution
|
|
579
|
+
{
|
|
580
|
+
to: [{ namespaceSelector: { matchLabels: { name: 'kube-system' } } }],
|
|
581
|
+
ports: [
|
|
582
|
+
{ protocol: 'UDP', port: 53 },
|
|
583
|
+
{ protocol: 'TCP', port: 53 },
|
|
584
|
+
],
|
|
585
|
+
},
|
|
586
|
+
],
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
// App tier - only allow traffic from web tier
|
|
590
|
+
rutter.addNetworkPolicy({
|
|
591
|
+
name: 'app-tier-policy',
|
|
592
|
+
podSelector: { matchLabels: { tier: 'app' } },
|
|
593
|
+
policyTypes: ['Ingress', 'Egress'],
|
|
594
|
+
ingress: [
|
|
595
|
+
{
|
|
596
|
+
from: [{ podSelector: { matchLabels: { tier: 'web' } } }],
|
|
597
|
+
ports: [{ protocol: 'TCP', port: 8080 }],
|
|
598
|
+
},
|
|
599
|
+
],
|
|
600
|
+
egress: [
|
|
601
|
+
// Allow access to database
|
|
602
|
+
{
|
|
603
|
+
to: [{ podSelector: { matchLabels: { tier: 'database' } } }],
|
|
604
|
+
ports: [{ protocol: 'TCP', port: 5432 }],
|
|
605
|
+
},
|
|
606
|
+
// Allow external API calls (with CIDR restrictions)
|
|
607
|
+
{
|
|
608
|
+
to: [
|
|
609
|
+
{
|
|
610
|
+
ipBlock: {
|
|
611
|
+
cidr: '0.0.0.0/0',
|
|
612
|
+
except: ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'],
|
|
613
|
+
},
|
|
614
|
+
},
|
|
615
|
+
],
|
|
616
|
+
ports: [{ protocol: 'TCP', port: 443 }],
|
|
617
|
+
},
|
|
618
|
+
],
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
// Database tier - most restrictive
|
|
622
|
+
rutter.addNetworkPolicy({
|
|
623
|
+
name: 'database-tier-policy',
|
|
624
|
+
podSelector: { matchLabels: { tier: 'database' } },
|
|
625
|
+
policyTypes: ['Ingress', 'Egress'],
|
|
626
|
+
ingress: [
|
|
627
|
+
{
|
|
628
|
+
from: [{ podSelector: { matchLabels: { tier: 'app' } } }],
|
|
629
|
+
ports: [{ protocol: 'TCP', port: 5432 }],
|
|
630
|
+
},
|
|
631
|
+
],
|
|
632
|
+
egress: [
|
|
633
|
+
// Only allow DNS resolution
|
|
634
|
+
{
|
|
635
|
+
to: [{ namespaceSelector: { matchLabels: { name: 'kube-system' } } }],
|
|
636
|
+
ports: [
|
|
637
|
+
{ protocol: 'UDP', port: 53 },
|
|
638
|
+
{ protocol: 'TCP', port: 53 },
|
|
639
|
+
],
|
|
640
|
+
},
|
|
641
|
+
],
|
|
642
|
+
});
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
#### Cross-Namespace Communication
|
|
646
|
+
|
|
647
|
+
```typescript
|
|
648
|
+
// Allow traffic from monitoring namespace
|
|
649
|
+
rutter.addAllowFromNamespaceNetworkPolicy({
|
|
650
|
+
name: 'allow-monitoring',
|
|
651
|
+
targetPodSelector: { app: 'backend' },
|
|
652
|
+
sourceNamespaceSelector: { name: 'monitoring' },
|
|
653
|
+
ports: [{ protocol: 'TCP', port: 9090 }], // Prometheus metrics
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
// Allow traffic to shared services namespace
|
|
657
|
+
rutter.addNetworkPolicy({
|
|
658
|
+
name: 'allow-to-shared-services',
|
|
659
|
+
podSelector: { matchLabels: { app: 'backend' } },
|
|
660
|
+
policyTypes: ['Egress'],
|
|
661
|
+
egress: [
|
|
662
|
+
{
|
|
663
|
+
to: [
|
|
664
|
+
{
|
|
665
|
+
namespaceSelector: { matchLabels: { name: 'shared-services' } },
|
|
666
|
+
podSelector: { matchLabels: { app: 'redis' } },
|
|
667
|
+
},
|
|
668
|
+
],
|
|
669
|
+
ports: [{ protocol: 'TCP', port: 6379 }],
|
|
670
|
+
},
|
|
671
|
+
],
|
|
672
|
+
});
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
### Security Best Practices
|
|
676
|
+
|
|
677
|
+
#### 1. Start with Deny-All Policies
|
|
678
|
+
|
|
679
|
+
```typescript
|
|
680
|
+
// Always start with deny-all for maximum security
|
|
681
|
+
rutter.addDenyAllNetworkPolicy('default-deny-all');
|
|
682
|
+
|
|
683
|
+
// Then add specific allow rules
|
|
684
|
+
rutter.addAllowFromPodsNetworkPolicy({
|
|
685
|
+
name: 'allow-specific-communication',
|
|
686
|
+
targetPodSelector: { app: 'api' },
|
|
687
|
+
sourcePodSelector: { app: 'frontend' },
|
|
688
|
+
ports: [{ protocol: 'TCP', port: 8080 }],
|
|
689
|
+
});
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
#### 2. Separate Ingress and Egress Policies
|
|
693
|
+
|
|
694
|
+
```typescript
|
|
695
|
+
// Separate policies for better maintainability
|
|
696
|
+
rutter.addDenyAllIngressNetworkPolicy('deny-all-ingress');
|
|
697
|
+
rutter.addDenyAllEgressNetworkPolicy('deny-all-egress');
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
#### 3. Use CIDR Blocks for External Access
|
|
701
|
+
|
|
702
|
+
```typescript
|
|
703
|
+
// Restrict external access to specific IP ranges
|
|
704
|
+
rutter.addNetworkPolicy({
|
|
705
|
+
name: 'external-api-access',
|
|
706
|
+
podSelector: { matchLabels: { app: 'backend' } },
|
|
707
|
+
policyTypes: ['Egress'],
|
|
708
|
+
egress: [
|
|
709
|
+
{
|
|
710
|
+
to: [
|
|
711
|
+
{
|
|
712
|
+
ipBlock: {
|
|
713
|
+
cidr: '203.0.113.0/24', // Specific external service
|
|
714
|
+
},
|
|
715
|
+
},
|
|
716
|
+
],
|
|
717
|
+
ports: [{ protocol: 'TCP', port: 443 }],
|
|
718
|
+
},
|
|
719
|
+
],
|
|
720
|
+
});
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
#### 4. Include DNS Resolution
|
|
724
|
+
|
|
725
|
+
```typescript
|
|
726
|
+
// Always allow DNS for name resolution
|
|
727
|
+
const dnsEgressRule = {
|
|
728
|
+
to: [{ namespaceSelector: { matchLabels: { name: 'kube-system' } } }],
|
|
729
|
+
ports: [
|
|
730
|
+
{ protocol: 'UDP', port: 53 },
|
|
731
|
+
{ protocol: 'TCP', port: 53 },
|
|
732
|
+
],
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
rutter.addNetworkPolicy({
|
|
736
|
+
name: 'app-with-dns',
|
|
737
|
+
podSelector: { matchLabels: { app: 'backend' } },
|
|
738
|
+
policyTypes: ['Egress'],
|
|
739
|
+
egress: [dnsEgressRule /* other rules */],
|
|
740
|
+
});
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
### Basic NetworkPolicy
|
|
744
|
+
|
|
745
|
+
```typescript
|
|
746
|
+
// Custom NetworkPolicy with full control
|
|
747
|
+
rutter.addNetworkPolicy({
|
|
748
|
+
name: 'custom-policy',
|
|
749
|
+
podSelector: { matchLabels: { app: 'backend' } },
|
|
750
|
+
policyTypes: ['Ingress', 'Egress'],
|
|
751
|
+
ingress: [
|
|
752
|
+
{
|
|
753
|
+
from: [{ podSelector: { matchLabels: { app: 'frontend' } } }],
|
|
754
|
+
ports: [{ protocol: 'TCP', port: 8080 }],
|
|
755
|
+
},
|
|
756
|
+
],
|
|
757
|
+
egress: [
|
|
758
|
+
{
|
|
759
|
+
to: [{ podSelector: { matchLabels: { app: 'database' } } }],
|
|
760
|
+
ports: [{ protocol: 'TCP', port: 5432 }],
|
|
761
|
+
},
|
|
762
|
+
],
|
|
763
|
+
});
|
|
764
|
+
```
|
|
765
|
+
|
|
432
766
|
## Multi-environment values
|
|
433
767
|
|
|
434
768
|
Provide `envValues` in the `Rutter` constructor to automatically create
|
|
@@ -457,7 +791,7 @@ Provide `envValues` in the `Rutter` constructor to automatically create
|
|
|
457
791
|
- ✅ Auto-scaling helpers (HPA, VPA, PodDisruptionBudget)
|
|
458
792
|
- ✅ AWS multi-cloud support (EBS, EFS, ALB, IRSA, Secrets Manager, Parameter Store)
|
|
459
793
|
- ✅ Custom manifest naming and file organization
|
|
460
|
-
- Azure multi-cloud support (
|
|
794
|
+
- ✅ Azure multi-cloud support (Azure Disk StorageClass, AGIC)
|
|
461
795
|
- GCP multi-cloud support (GKE-specific helpers)
|
|
462
796
|
- Richer CLI (resource generators, diff)
|
|
463
797
|
- Template validation and testing utilities
|
package/dist/cli.js
CHANGED
|
@@ -1,42 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
-
}
|
|
9
|
-
Object.defineProperty(o, k2, desc);
|
|
10
|
-
}) : (function(o, m, k, k2) {
|
|
11
|
-
if (k2 === undefined) k2 = k;
|
|
12
|
-
o[k2] = m[k];
|
|
13
|
-
}));
|
|
14
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
-
}) : function(o, v) {
|
|
17
|
-
o["default"] = v;
|
|
18
|
-
});
|
|
19
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
-
var ownKeys = function(o) {
|
|
21
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
-
var ar = [];
|
|
23
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
-
return ar;
|
|
25
|
-
};
|
|
26
|
-
return ownKeys(o);
|
|
27
|
-
};
|
|
28
|
-
return function (mod) {
|
|
29
|
-
if (mod && mod.__esModule) return mod;
|
|
30
|
-
var result = {};
|
|
31
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
-
__setModuleDefault(result, mod);
|
|
33
|
-
return result;
|
|
34
|
-
};
|
|
35
|
-
})();
|
|
36
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
-
const fs = __importStar(require("fs"));
|
|
38
|
-
const path = __importStar(require("path"));
|
|
39
|
-
const cp = __importStar(require("child_process"));
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as cp from 'child_process';
|
|
40
5
|
const HELM_INSTALL_URL = 'https://helm.sh/docs/intro/install/';
|
|
41
6
|
const HELM_ENV_VAR_MSG = 'Or set HELM_BIN environment variable to helm binary path.';
|
|
42
7
|
function usageAndExit(msg) {
|
|
@@ -139,7 +104,6 @@ async function cmdValidate(projectDir, silent = false) {
|
|
|
139
104
|
}
|
|
140
105
|
finally {
|
|
141
106
|
// Cleanup temp directory
|
|
142
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
|
|
143
107
|
if (fs.existsSync(tempDir)) {
|
|
144
108
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
145
109
|
}
|
|
@@ -158,10 +122,11 @@ async function cmdSynth(projectDir, out, flags) {
|
|
|
158
122
|
process.exit(1);
|
|
159
123
|
}
|
|
160
124
|
// Enable TS runtime with specific config
|
|
161
|
-
|
|
125
|
+
const { register } = await import('ts-node');
|
|
126
|
+
register({
|
|
162
127
|
transpileOnly: true,
|
|
163
128
|
compilerOptions: {
|
|
164
|
-
module: '
|
|
129
|
+
module: 'ESNext',
|
|
165
130
|
moduleResolution: 'node',
|
|
166
131
|
},
|
|
167
132
|
});
|
|
@@ -172,29 +137,34 @@ async function cmdSynth(projectDir, out, flags) {
|
|
|
172
137
|
console.error('Module path must be within current working directory');
|
|
173
138
|
process.exit(1);
|
|
174
139
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
140
|
+
try {
|
|
141
|
+
const mod = await import(resolvedPath);
|
|
142
|
+
const runner = mod.default || mod.run || mod.synth;
|
|
143
|
+
if (typeof runner !== 'function') {
|
|
144
|
+
console.error('chart.ts must export a default/run/synth function');
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
// Apply --set overrides if provided
|
|
148
|
+
if (flags?.set &&
|
|
149
|
+
Object.keys(flags.set).length > 0 &&
|
|
150
|
+
mod.rutter &&
|
|
151
|
+
typeof mod.rutter.setValues === 'function') {
|
|
152
|
+
mod.rutter.setValues(flags.set);
|
|
153
|
+
}
|
|
154
|
+
const outDir = out || path.join(path.dirname(chartTs), 'dist');
|
|
155
|
+
if (flags?.dryRun) {
|
|
156
|
+
log(`[DRY RUN] Would write chart to ${outDir}`, flags.silent);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
|
|
160
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
161
|
+
await Promise.resolve(runner(outDir));
|
|
162
|
+
log(`Chart written to ${outDir}`, flags?.silent);
|
|
188
163
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
return;
|
|
164
|
+
catch (error) {
|
|
165
|
+
console.error(`Failed to import module: ${error instanceof Error ? error.message : error}`);
|
|
166
|
+
process.exit(1);
|
|
193
167
|
}
|
|
194
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
|
|
195
|
-
fs.mkdirSync(outDir, { recursive: true });
|
|
196
|
-
await Promise.resolve(runner(outDir));
|
|
197
|
-
log(`Chart written to ${outDir}`, flags?.silent);
|
|
198
168
|
}
|
|
199
169
|
async function cmdDiff(projectDir, chartDir, silent = false) {
|
|
200
170
|
if (!projectDir || !chartDir)
|
|
@@ -218,7 +188,6 @@ async function cmdDiff(projectDir, chartDir, silent = false) {
|
|
|
218
188
|
}
|
|
219
189
|
finally {
|
|
220
190
|
// Cleanup temp directory
|
|
221
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
|
|
222
191
|
if (fs.existsSync(tempDir)) {
|
|
223
192
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
224
193
|
}
|
|
@@ -268,7 +237,6 @@ async function cmdDeploy(projectDir, releaseName, flags) {
|
|
|
268
237
|
}
|
|
269
238
|
finally {
|
|
270
239
|
// Cleanup temp directory
|
|
271
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
|
|
272
240
|
if (fs.existsSync(tempDir)) {
|
|
273
241
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
274
242
|
}
|
|
@@ -324,12 +292,10 @@ async function cmdUmbrellaAdd(subchartName, silent = false) {
|
|
|
324
292
|
if (!subchartName)
|
|
325
293
|
usageAndExit(MISSING_SUBCHART_MSG);
|
|
326
294
|
const configFile = path.join(process.cwd(), UMBRELLA_CONFIG_FILE);
|
|
327
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
|
|
328
295
|
if (!fs.existsSync(configFile)) {
|
|
329
296
|
console.error(`${UMBRELLA_CONFIG_FILE} not found. Run \`tl umbrella init\` first.`);
|
|
330
297
|
process.exit(1);
|
|
331
298
|
}
|
|
332
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
|
|
333
299
|
const config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
|
|
334
300
|
// Create subchart directory and scaffold
|
|
335
301
|
const subchartDir = path.join(process.cwd(), 'charts', subchartName);
|
|
@@ -344,19 +310,16 @@ async function cmdUmbrellaAdd(subchartName, silent = false) {
|
|
|
344
310
|
version: '0.1.0',
|
|
345
311
|
path: `./charts/${subchartName}/chart.ts`,
|
|
346
312
|
});
|
|
347
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
|
|
348
313
|
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
|
|
349
314
|
log(`Subchart ${subchartName} added to umbrella`, silent);
|
|
350
315
|
}
|
|
351
316
|
async function cmdUmbrellaSynth(outDir, flags) {
|
|
352
317
|
const configFile = path.join(process.cwd(), UMBRELLA_CONFIG_FILE);
|
|
353
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
|
|
354
318
|
if (!fs.existsSync(configFile)) {
|
|
355
319
|
console.error(`${UMBRELLA_CONFIG_FILE} not found. Run \`tl umbrella init\` first.`);
|
|
356
320
|
process.exit(1);
|
|
357
321
|
}
|
|
358
322
|
const umbrellaFile = path.join(process.cwd(), 'umbrella.ts');
|
|
359
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool needs dynamic paths
|
|
360
323
|
if (!fs.existsSync(umbrellaFile)) {
|
|
361
324
|
console.error('umbrella.ts not found.');
|
|
362
325
|
process.exit(1);
|
|
@@ -376,7 +339,6 @@ async function cmdUmbrellaSynth(outDir, flags) {
|
|
|
376
339
|
console.error('Module path must be within current working directory');
|
|
377
340
|
process.exit(1);
|
|
378
341
|
}
|
|
379
|
-
// eslint-disable-next-line security/detect-non-literal-require -- CLI tool needs dynamic module loading
|
|
380
342
|
const mod = require(resolvedPath);
|
|
381
343
|
const runner = mod.default || mod.run || mod.synth;
|
|
382
344
|
if (typeof runner !== 'function') {
|
|
@@ -622,10 +584,8 @@ function parseArgs() {
|
|
|
622
584
|
return { cmd, args, flags };
|
|
623
585
|
}
|
|
624
586
|
function showVersion() {
|
|
625
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI needs to read package.json
|
|
626
587
|
const packagePath = path.join(__dirname, '..', 'package.json');
|
|
627
588
|
try {
|
|
628
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI needs to read package.json
|
|
629
589
|
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
630
590
|
console.log(`timonel v${packageJson.version}`);
|
|
631
591
|
}
|