@stacksjs/ts-cloud-core 0.1.7 → 0.1.9
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/package.json +7 -6
- package/src/advanced-features.test.ts +465 -0
- package/src/aws/cloudformation.ts +421 -0
- package/src/aws/cloudfront.ts +158 -0
- package/src/aws/credentials.test.ts +132 -0
- package/src/aws/credentials.ts +545 -0
- package/src/aws/index.ts +87 -0
- package/src/aws/s3.test.ts +188 -0
- package/src/aws/s3.ts +1088 -0
- package/src/aws/signature.test.ts +670 -0
- package/src/aws/signature.ts +1155 -0
- package/src/backup/disaster-recovery.test.ts +726 -0
- package/src/backup/disaster-recovery.ts +500 -0
- package/src/backup/index.ts +34 -0
- package/src/backup/manager.test.ts +498 -0
- package/src/backup/manager.ts +432 -0
- package/src/cicd/circleci.ts +430 -0
- package/src/cicd/github-actions.ts +424 -0
- package/src/cicd/gitlab-ci.ts +255 -0
- package/src/cicd/index.ts +8 -0
- package/src/cli/history.ts +396 -0
- package/src/cli/index.ts +10 -0
- package/src/cli/progress.ts +458 -0
- package/src/cli/repl.ts +454 -0
- package/src/cli/suggestions.ts +327 -0
- package/src/cli/table.test.ts +319 -0
- package/src/cli/table.ts +332 -0
- package/src/cloudformation/builder.test.ts +327 -0
- package/src/cloudformation/builder.ts +378 -0
- package/src/cloudformation/builders/api-gateway.ts +449 -0
- package/src/cloudformation/builders/cache.ts +334 -0
- package/src/cloudformation/builders/cdn.ts +278 -0
- package/src/cloudformation/builders/compute.ts +485 -0
- package/src/cloudformation/builders/database.ts +392 -0
- package/src/cloudformation/builders/functions.ts +343 -0
- package/src/cloudformation/builders/messaging.ts +140 -0
- package/src/cloudformation/builders/monitoring.ts +300 -0
- package/src/cloudformation/builders/network.ts +264 -0
- package/src/cloudformation/builders/queue.ts +147 -0
- package/src/cloudformation/builders/security.ts +399 -0
- package/src/cloudformation/builders/storage.ts +285 -0
- package/src/cloudformation/index.ts +30 -0
- package/src/cloudformation/types.ts +173 -0
- package/src/compliance/aws-config.ts +543 -0
- package/src/compliance/cloudtrail.ts +376 -0
- package/src/compliance/compliance.test.ts +423 -0
- package/src/compliance/guardduty.ts +446 -0
- package/src/compliance/index.ts +66 -0
- package/src/compliance/security-hub.ts +456 -0
- package/src/containers/build-optimization.ts +416 -0
- package/src/containers/containers.test.ts +508 -0
- package/src/containers/image-scanning.ts +360 -0
- package/src/containers/index.ts +9 -0
- package/src/containers/registry.ts +293 -0
- package/src/containers/service-mesh.ts +520 -0
- package/src/database/database.test.ts +762 -0
- package/src/database/index.ts +9 -0
- package/src/database/migrations.ts +444 -0
- package/src/database/performance.ts +528 -0
- package/src/database/replicas.ts +534 -0
- package/src/database/users.ts +494 -0
- package/src/dependency-graph.ts +143 -0
- package/src/deployment/ab-testing.ts +582 -0
- package/src/deployment/blue-green.ts +452 -0
- package/src/deployment/canary.ts +500 -0
- package/src/deployment/deployment.test.ts +526 -0
- package/src/deployment/index.ts +61 -0
- package/src/deployment/progressive.ts +62 -0
- package/src/dns/dns.test.ts +641 -0
- package/src/dns/dnssec.ts +315 -0
- package/src/dns/index.ts +8 -0
- package/src/dns/resolver.ts +496 -0
- package/src/dns/routing.ts +593 -0
- package/src/email/advanced/analytics.ts +445 -0
- package/src/email/advanced/index.ts +11 -0
- package/src/email/advanced/rules.ts +465 -0
- package/src/email/advanced/scheduling.ts +352 -0
- package/src/email/advanced/search.ts +412 -0
- package/src/email/advanced/shared-mailboxes.ts +404 -0
- package/src/email/advanced/templates.ts +455 -0
- package/src/email/advanced/threading.ts +281 -0
- package/src/email/analytics.ts +467 -0
- package/src/email/bounce-handling.ts +425 -0
- package/src/email/email.test.ts +431 -0
- package/src/email/handlers/__tests__/inbound.test.ts +38 -0
- package/src/email/handlers/__tests__/outbound.test.ts +37 -0
- package/src/email/handlers/converter.ts +227 -0
- package/src/email/handlers/feedback.ts +228 -0
- package/src/email/handlers/inbound.ts +169 -0
- package/src/email/handlers/outbound.ts +178 -0
- package/src/email/index.ts +15 -0
- package/src/email/reputation.ts +303 -0
- package/src/email/templates.ts +352 -0
- package/src/errors/index.test.ts +434 -0
- package/src/errors/index.ts +416 -0
- package/src/health-checks/index.ts +40 -0
- package/src/index.ts +360 -0
- package/src/intrinsic-functions.ts +118 -0
- package/src/lambda/concurrency.ts +330 -0
- package/src/lambda/destinations.ts +345 -0
- package/src/lambda/dlq.ts +425 -0
- package/src/lambda/index.ts +11 -0
- package/src/lambda/lambda.test.ts +840 -0
- package/src/lambda/layers.ts +263 -0
- package/src/lambda/versions.ts +376 -0
- package/src/lambda/vpc.ts +399 -0
- package/src/local/config.ts +114 -0
- package/src/local/index.ts +6 -0
- package/src/local/mock-aws.ts +351 -0
- package/src/modules/ai.ts +340 -0
- package/src/modules/api.ts +478 -0
- package/src/modules/auth.ts +805 -0
- package/src/modules/cache.ts +417 -0
- package/src/modules/cdn.ts +1062 -0
- package/src/modules/communication.ts +1094 -0
- package/src/modules/compute.ts +3348 -0
- package/src/modules/database.ts +554 -0
- package/src/modules/deployment.ts +1079 -0
- package/src/modules/dns.ts +337 -0
- package/src/modules/email.ts +1538 -0
- package/src/modules/filesystem.ts +515 -0
- package/src/modules/index.ts +32 -0
- package/src/modules/messaging.ts +486 -0
- package/src/modules/monitoring.ts +2086 -0
- package/src/modules/network.ts +664 -0
- package/src/modules/parameter-store.ts +325 -0
- package/src/modules/permissions.ts +1081 -0
- package/src/modules/phone.ts +494 -0
- package/src/modules/queue.ts +1260 -0
- package/src/modules/redirects.ts +464 -0
- package/src/modules/registry.ts +699 -0
- package/src/modules/search.ts +401 -0
- package/src/modules/secrets.ts +416 -0
- package/src/modules/security.ts +731 -0
- package/src/modules/sms.ts +389 -0
- package/src/modules/storage.ts +1120 -0
- package/src/modules/workflow.ts +680 -0
- package/src/multi-account/config.ts +521 -0
- package/src/multi-account/index.ts +7 -0
- package/src/multi-account/manager.ts +427 -0
- package/src/multi-region/cross-region.ts +410 -0
- package/src/multi-region/index.ts +8 -0
- package/src/multi-region/manager.ts +483 -0
- package/src/multi-region/regions.ts +435 -0
- package/src/network-security/index.ts +48 -0
- package/src/observability/index.ts +9 -0
- package/src/observability/logs.ts +522 -0
- package/src/observability/metrics.ts +460 -0
- package/src/observability/observability.test.ts +782 -0
- package/src/observability/synthetics.ts +568 -0
- package/src/observability/xray.ts +358 -0
- package/src/phone/advanced/analytics.ts +349 -0
- package/src/phone/advanced/callbacks.ts +428 -0
- package/src/phone/advanced/index.ts +8 -0
- package/src/phone/advanced/ivr-builder.ts +504 -0
- package/src/phone/advanced/recording.ts +310 -0
- package/src/phone/handlers/__tests__/incoming-call.test.ts +40 -0
- package/src/phone/handlers/incoming-call.ts +117 -0
- package/src/phone/handlers/missed-call.ts +116 -0
- package/src/phone/handlers/voicemail.ts +179 -0
- package/src/phone/index.ts +9 -0
- package/src/presets/api-backend.ts +134 -0
- package/src/presets/data-pipeline.ts +204 -0
- package/src/presets/extend.test.ts +295 -0
- package/src/presets/extend.ts +297 -0
- package/src/presets/fullstack-app.ts +144 -0
- package/src/presets/index.ts +27 -0
- package/src/presets/jamstack.ts +135 -0
- package/src/presets/microservices.ts +167 -0
- package/src/presets/ml-api.ts +208 -0
- package/src/presets/nodejs-server.ts +104 -0
- package/src/presets/nodejs-serverless.ts +114 -0
- package/src/presets/realtime-app.ts +184 -0
- package/src/presets/static-site.ts +64 -0
- package/src/presets/traditional-web-app.ts +339 -0
- package/src/presets/wordpress.ts +138 -0
- package/src/preview/github.test.ts +249 -0
- package/src/preview/github.ts +297 -0
- package/src/preview/index.ts +37 -0
- package/src/preview/manager.test.ts +440 -0
- package/src/preview/manager.ts +326 -0
- package/src/preview/notifications.test.ts +582 -0
- package/src/preview/notifications.ts +341 -0
- package/src/queue/batch-processing.ts +402 -0
- package/src/queue/dlq-monitoring.ts +402 -0
- package/src/queue/fifo.ts +342 -0
- package/src/queue/index.ts +9 -0
- package/src/queue/management.ts +428 -0
- package/src/queue/queue.test.ts +429 -0
- package/src/resource-mgmt/index.ts +39 -0
- package/src/resource-naming.ts +62 -0
- package/src/s3/index.ts +523 -0
- package/src/schema/cloud-config.schema.json +554 -0
- package/src/schema/index.ts +68 -0
- package/src/security/certificate-manager.ts +492 -0
- package/src/security/index.ts +9 -0
- package/src/security/scanning.ts +545 -0
- package/src/security/secrets-manager.ts +476 -0
- package/src/security/secrets-rotation.ts +456 -0
- package/src/security/security.test.ts +738 -0
- package/src/sms/advanced/ab-testing.ts +389 -0
- package/src/sms/advanced/analytics.ts +336 -0
- package/src/sms/advanced/campaigns.ts +523 -0
- package/src/sms/advanced/chatbot.ts +224 -0
- package/src/sms/advanced/index.ts +10 -0
- package/src/sms/advanced/link-tracking.ts +248 -0
- package/src/sms/advanced/mms.ts +308 -0
- package/src/sms/handlers/__tests__/send.test.ts +40 -0
- package/src/sms/handlers/delivery-status.ts +133 -0
- package/src/sms/handlers/receive.ts +162 -0
- package/src/sms/handlers/send.ts +174 -0
- package/src/sms/index.ts +9 -0
- package/src/stack-diff.ts +389 -0
- package/src/static-site/index.ts +85 -0
- package/src/template-builder.ts +110 -0
- package/src/template-validator.ts +574 -0
- package/src/utils/cache.ts +291 -0
- package/src/utils/diff.ts +269 -0
- package/src/utils/hash.ts +227 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/parallel.ts +294 -0
- package/src/validators/credentials.test.ts +274 -0
- package/src/validators/credentials.ts +233 -0
- package/src/validators/quotas.test.ts +434 -0
- package/src/validators/quotas.ts +217 -0
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
import { describe, expect, it, beforeEach } from 'bun:test'
|
|
2
|
+
import {
|
|
3
|
+
ImageScanningManager,
|
|
4
|
+
imageScanningManager,
|
|
5
|
+
BuildOptimizationManager,
|
|
6
|
+
buildOptimizationManager,
|
|
7
|
+
ContainerRegistryManager,
|
|
8
|
+
containerRegistryManager,
|
|
9
|
+
ServiceMeshManager,
|
|
10
|
+
serviceMeshManager,
|
|
11
|
+
} from '.'
|
|
12
|
+
|
|
13
|
+
describe('Image Scanning Manager', () => {
|
|
14
|
+
let manager: ImageScanningManager
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
manager = new ImageScanningManager()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
describe('Scan Configuration', () => {
|
|
21
|
+
it('should configure Trivy scan', () => {
|
|
22
|
+
const config = manager.configureTrivyScan({
|
|
23
|
+
repository: 'my-app',
|
|
24
|
+
imageTag: 'v1.0.0',
|
|
25
|
+
scanOnPush: true,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
expect(config.id).toContain('scan-config')
|
|
29
|
+
expect(config.scanner).toBe('trivy')
|
|
30
|
+
expect(config.scanOnPush).toBe(true)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('should configure Snyk scan', () => {
|
|
34
|
+
const config = manager.configureSnykScan({
|
|
35
|
+
repository: 'my-app',
|
|
36
|
+
imageTag: 'latest',
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
expect(config.scanner).toBe('snyk')
|
|
40
|
+
expect(config.failOnSeverity).toBe('HIGH')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('should configure ECR scan', () => {
|
|
44
|
+
const config = manager.configureECRScan({
|
|
45
|
+
repository: 'my-repo',
|
|
46
|
+
scanOnPush: true,
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
expect(config.scanner).toBe('ecr')
|
|
50
|
+
expect(config.failOnSeverity).toBe('CRITICAL')
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
describe('Image Scanning', () => {
|
|
55
|
+
it('should scan image', async () => {
|
|
56
|
+
const config = manager.configureTrivyScan({
|
|
57
|
+
repository: 'test-app',
|
|
58
|
+
imageTag: 'v1.0.0',
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const result = await manager.scanImage(config.id)
|
|
62
|
+
|
|
63
|
+
expect(result.id).toContain('scan-result')
|
|
64
|
+
expect(result.scannerType).toBe('trivy')
|
|
65
|
+
expect(result.summary).toBeDefined()
|
|
66
|
+
expect(result.vulnerabilities).toBeDefined()
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('should evaluate scan result', async () => {
|
|
70
|
+
const config = manager.configureTrivyScan({
|
|
71
|
+
repository: 'test-app',
|
|
72
|
+
imageTag: 'v1.0.0',
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
config.failOnSeverity = 'CRITICAL'
|
|
76
|
+
|
|
77
|
+
const result = await manager.scanImage(config.id)
|
|
78
|
+
|
|
79
|
+
expect(typeof result.passed).toBe('boolean')
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
describe('Scan Policies', () => {
|
|
84
|
+
it('should create strict policy', () => {
|
|
85
|
+
const policy = manager.createStrictPolicy('production-policy')
|
|
86
|
+
|
|
87
|
+
expect(policy.id).toContain('policy')
|
|
88
|
+
expect(policy.maxCritical).toBe(0)
|
|
89
|
+
expect(policy.maxHigh).toBe(0)
|
|
90
|
+
expect(policy.blockOnFailure).toBe(true)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('should create permissive policy', () => {
|
|
94
|
+
const policy = manager.createPermissivePolicy('dev-policy')
|
|
95
|
+
|
|
96
|
+
expect(policy.maxCritical).toBe(5)
|
|
97
|
+
expect(policy.blockOnFailure).toBe(false)
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
describe('CloudFormation Generation', () => {
|
|
102
|
+
it('should generate ECR scan CloudFormation', () => {
|
|
103
|
+
const config = manager.configureECRScan({
|
|
104
|
+
repository: 'my-repo',
|
|
105
|
+
scanOnPush: true,
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
const cf = manager.generateECRScanCF(config)
|
|
109
|
+
|
|
110
|
+
expect(cf.Type).toBe('AWS::ECR::Repository')
|
|
111
|
+
expect(cf.Properties.ImageScanningConfiguration.ScanOnPush).toBe(true)
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('should use global instance', () => {
|
|
116
|
+
expect(imageScanningManager).toBeInstanceOf(ImageScanningManager)
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
describe('Build Optimization Manager', () => {
|
|
121
|
+
let manager: BuildOptimizationManager
|
|
122
|
+
|
|
123
|
+
beforeEach(() => {
|
|
124
|
+
manager = new BuildOptimizationManager()
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
describe('Build Configuration', () => {
|
|
128
|
+
it('should create optimized build config', () => {
|
|
129
|
+
const config = manager.createOptimizedBuildConfig({
|
|
130
|
+
name: 'my-app-build',
|
|
131
|
+
dockerfile: 'Dockerfile',
|
|
132
|
+
enableCache: true,
|
|
133
|
+
registry: 'my-registry.com',
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
expect(config.id).toContain('build-config')
|
|
137
|
+
expect(config.cacheStrategy.type).toBe('registry')
|
|
138
|
+
expect(config.cacheStrategy.cacheFrom).toBeDefined()
|
|
139
|
+
})
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
describe('Multi-Stage Builds', () => {
|
|
143
|
+
it('should create Node.js multi-stage build', () => {
|
|
144
|
+
const config = manager.createNodeMultiStageBuild({
|
|
145
|
+
name: 'nodejs-app',
|
|
146
|
+
nodeVersion: '18-alpine',
|
|
147
|
+
targetStage: 'production',
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
expect(config.id).toContain('multi-stage')
|
|
151
|
+
expect(config.stages).toHaveLength(3)
|
|
152
|
+
expect(config.stages[0].name).toBe('dependencies')
|
|
153
|
+
expect(config.stages[1].name).toBe('build')
|
|
154
|
+
expect(config.stages[2].name).toBe('production')
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
it('should generate Dockerfile from multi-stage config', () => {
|
|
158
|
+
const config = manager.createNodeMultiStageBuild({
|
|
159
|
+
name: 'test-app',
|
|
160
|
+
nodeVersion: '18-alpine',
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
const dockerfile = manager.generateDockerfile(config.id)
|
|
164
|
+
|
|
165
|
+
expect(dockerfile).toContain('FROM node:18-alpine AS dependencies')
|
|
166
|
+
expect(dockerfile).toContain('FROM node:18-alpine AS build')
|
|
167
|
+
expect(dockerfile).toContain('FROM node:18-alpine AS production')
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
describe('Layer Analysis', () => {
|
|
172
|
+
it('should analyze image layers', () => {
|
|
173
|
+
const analysis = manager.analyzeImage('my-image:latest', [
|
|
174
|
+
{
|
|
175
|
+
index: 0,
|
|
176
|
+
command: 'FROM node:18',
|
|
177
|
+
size: 50,
|
|
178
|
+
created: new Date(),
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
index: 1,
|
|
182
|
+
command: 'RUN apt-get update',
|
|
183
|
+
size: 100,
|
|
184
|
+
created: new Date(),
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
index: 2,
|
|
188
|
+
command: 'COPY . .',
|
|
189
|
+
size: 25,
|
|
190
|
+
created: new Date(),
|
|
191
|
+
},
|
|
192
|
+
])
|
|
193
|
+
|
|
194
|
+
expect(analysis.id).toContain('analysis')
|
|
195
|
+
expect(analysis.layers).toHaveLength(3)
|
|
196
|
+
expect(analysis.totalSize).toBe(175)
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
describe('Optimization Recommendations', () => {
|
|
201
|
+
it('should generate optimization recommendations', () => {
|
|
202
|
+
const analysis = manager.analyzeImage('test-image', [
|
|
203
|
+
{ index: 0, command: 'FROM ubuntu:20.04', size: 200, created: new Date() },
|
|
204
|
+
{ index: 1, command: 'RUN apt-get update', size: 50, created: new Date() },
|
|
205
|
+
{ index: 2, command: 'RUN apt-get install -y curl', size: 30, created: new Date() },
|
|
206
|
+
{ index: 3, command: 'RUN apt-get install -y git', size: 40, created: new Date() },
|
|
207
|
+
{ index: 4, command: 'COPY . .', size: 20, created: new Date() },
|
|
208
|
+
])
|
|
209
|
+
|
|
210
|
+
const optimization = manager.generateOptimizations(analysis.id)
|
|
211
|
+
|
|
212
|
+
expect(optimization.id).toContain('optimization')
|
|
213
|
+
expect(optimization.recommendations.length).toBeGreaterThan(0)
|
|
214
|
+
expect(optimization.estimatedSavings).toBeDefined()
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
it('should recommend layer reduction', () => {
|
|
218
|
+
const analysis = manager.analyzeImage('test-image', [
|
|
219
|
+
{ index: 0, command: 'FROM node:18', size: 100, created: new Date() },
|
|
220
|
+
{ index: 1, command: 'RUN npm install pkg1', size: 10, created: new Date() },
|
|
221
|
+
{ index: 2, command: 'RUN npm install pkg2', size: 10, created: new Date() },
|
|
222
|
+
{ index: 3, command: 'RUN npm install pkg3', size: 10, created: new Date() },
|
|
223
|
+
{ index: 4, command: 'RUN npm install pkg4', size: 10, created: new Date() },
|
|
224
|
+
{ index: 5, command: 'RUN npm install pkg5', size: 10, created: new Date() },
|
|
225
|
+
{ index: 6, command: 'RUN npm install pkg6', size: 10, created: new Date() },
|
|
226
|
+
])
|
|
227
|
+
|
|
228
|
+
const optimization = manager.generateOptimizations(analysis.id)
|
|
229
|
+
|
|
230
|
+
const layerReduction = optimization.recommendations.find(
|
|
231
|
+
r => r.type === 'layer_reduction'
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
expect(layerReduction).toBeDefined()
|
|
235
|
+
expect(layerReduction?.priority).toBe('high')
|
|
236
|
+
})
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
it('should use global instance', () => {
|
|
240
|
+
expect(buildOptimizationManager).toBeInstanceOf(BuildOptimizationManager)
|
|
241
|
+
})
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
describe('Container Registry Manager', () => {
|
|
245
|
+
let manager: ContainerRegistryManager
|
|
246
|
+
|
|
247
|
+
beforeEach(() => {
|
|
248
|
+
manager = new ContainerRegistryManager()
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
describe('Registry Creation', () => {
|
|
252
|
+
it('should create ECR repository', () => {
|
|
253
|
+
const registry = manager.createECRRepository({
|
|
254
|
+
name: 'my-app',
|
|
255
|
+
region: 'us-east-1',
|
|
256
|
+
scanOnPush: true,
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
expect(registry.id).toContain('registry')
|
|
260
|
+
expect(registry.registryType).toBe('ecr')
|
|
261
|
+
expect(registry.repositoryUri).toContain('my-app')
|
|
262
|
+
expect(registry.scanning?.scanOnPush).toBe(true)
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
it('should create repository with encryption', () => {
|
|
266
|
+
const registry = manager.createECRRepository({
|
|
267
|
+
name: 'secure-app',
|
|
268
|
+
encryption: 'KMS',
|
|
269
|
+
kmsKeyId: 'arn:aws:kms:us-east-1:123456789012:key/12345',
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
expect(registry.encryption?.encryptionType).toBe('KMS')
|
|
273
|
+
expect(registry.encryption?.kmsKeyId).toBeDefined()
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
it('should create managed repository with lifecycle', () => {
|
|
277
|
+
const registry = manager.createManagedRepository({
|
|
278
|
+
name: 'managed-app',
|
|
279
|
+
maxImageCount: 20,
|
|
280
|
+
maxImageAgeDays: 60,
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
expect(registry.lifecycle).toBeDefined()
|
|
284
|
+
expect(registry.lifecycle?.rules).toHaveLength(2)
|
|
285
|
+
expect(registry.lifecycle?.rules[0].selection.countNumber).toBe(20)
|
|
286
|
+
})
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
describe('Replication', () => {
|
|
290
|
+
it('should enable cross-region replication', () => {
|
|
291
|
+
const registry = manager.createECRRepository({
|
|
292
|
+
name: 'replicated-app',
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
manager.enableReplication(registry.id, [
|
|
296
|
+
{ region: 'us-west-2' },
|
|
297
|
+
{ region: 'eu-west-1' },
|
|
298
|
+
])
|
|
299
|
+
|
|
300
|
+
expect(registry.replication?.enabled).toBe(true)
|
|
301
|
+
expect(registry.replication?.destinations).toHaveLength(2)
|
|
302
|
+
})
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
describe('CloudFormation Generation', () => {
|
|
306
|
+
it('should generate ECR repository CloudFormation', () => {
|
|
307
|
+
const registry = manager.createECRRepository({
|
|
308
|
+
name: 'my-repo',
|
|
309
|
+
scanOnPush: true,
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
const cf = manager.generateECRRepositoryCF(registry)
|
|
313
|
+
|
|
314
|
+
expect(cf.Type).toBe('AWS::ECR::Repository')
|
|
315
|
+
expect(cf.Properties.RepositoryName).toBe('my-repo')
|
|
316
|
+
expect(cf.Properties.ImageScanningConfiguration.ScanOnPush).toBe(true)
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
it('should generate replication configuration', () => {
|
|
320
|
+
const replication = {
|
|
321
|
+
enabled: true,
|
|
322
|
+
destinations: [
|
|
323
|
+
{ region: 'us-west-2' },
|
|
324
|
+
{ region: 'eu-west-1' },
|
|
325
|
+
],
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const cf = manager.generateReplicationConfigCF(replication)
|
|
329
|
+
|
|
330
|
+
expect(cf.Type).toBe('AWS::ECR::ReplicationConfiguration')
|
|
331
|
+
expect(cf.Properties.ReplicationConfiguration.Rules).toHaveLength(2)
|
|
332
|
+
})
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
it('should use global instance', () => {
|
|
336
|
+
expect(containerRegistryManager).toBeInstanceOf(ContainerRegistryManager)
|
|
337
|
+
})
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
describe('Service Mesh Manager', () => {
|
|
341
|
+
let manager: ServiceMeshManager
|
|
342
|
+
|
|
343
|
+
beforeEach(() => {
|
|
344
|
+
manager = new ServiceMeshManager()
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
describe('Mesh Creation', () => {
|
|
348
|
+
it('should create App Mesh', () => {
|
|
349
|
+
const mesh = manager.createAppMesh({
|
|
350
|
+
name: 'my-mesh',
|
|
351
|
+
services: [
|
|
352
|
+
{
|
|
353
|
+
id: 'svc1',
|
|
354
|
+
name: 'frontend',
|
|
355
|
+
namespace: 'default',
|
|
356
|
+
port: 8080,
|
|
357
|
+
protocol: 'http',
|
|
358
|
+
},
|
|
359
|
+
],
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
expect(mesh.id).toContain('mesh')
|
|
363
|
+
expect(mesh.meshType).toBe('app_mesh')
|
|
364
|
+
expect(mesh.services).toHaveLength(1)
|
|
365
|
+
})
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
describe('Virtual Nodes', () => {
|
|
369
|
+
it('should create HTTP virtual node', () => {
|
|
370
|
+
const node = manager.createHTTPVirtualNode({
|
|
371
|
+
name: 'frontend-node',
|
|
372
|
+
serviceName: 'frontend',
|
|
373
|
+
port: 8080,
|
|
374
|
+
namespace: 'production',
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
expect(node.id).toContain('vnode')
|
|
378
|
+
expect(node.listeners).toHaveLength(1)
|
|
379
|
+
expect(node.listeners[0].protocol).toBe('http')
|
|
380
|
+
expect(node.listeners[0].healthCheck).toBeDefined()
|
|
381
|
+
})
|
|
382
|
+
|
|
383
|
+
it('should include health check', () => {
|
|
384
|
+
const node = manager.createHTTPVirtualNode({
|
|
385
|
+
name: 'api-node',
|
|
386
|
+
serviceName: 'api',
|
|
387
|
+
port: 3000,
|
|
388
|
+
namespace: 'production',
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
const healthCheck = node.listeners[0].healthCheck
|
|
392
|
+
|
|
393
|
+
expect(healthCheck).toBeDefined()
|
|
394
|
+
expect(healthCheck?.path).toBe('/health')
|
|
395
|
+
expect(healthCheck?.protocol).toBe('http')
|
|
396
|
+
})
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
describe('Virtual Routers', () => {
|
|
400
|
+
it('should create canary route', () => {
|
|
401
|
+
const router = manager.createCanaryRoute({
|
|
402
|
+
name: 'canary-router',
|
|
403
|
+
port: 8080,
|
|
404
|
+
protocol: 'http',
|
|
405
|
+
stableTarget: 'stable-node',
|
|
406
|
+
canaryTarget: 'canary-node',
|
|
407
|
+
canaryWeight: 20,
|
|
408
|
+
})
|
|
409
|
+
|
|
410
|
+
expect(router.id).toContain('vrouter')
|
|
411
|
+
expect(router.routes).toHaveLength(1)
|
|
412
|
+
expect(router.routes[0].action.weightedTargets).toHaveLength(2)
|
|
413
|
+
expect(router.routes[0].action.weightedTargets[0].weight).toBe(80)
|
|
414
|
+
expect(router.routes[0].action.weightedTargets[1].weight).toBe(20)
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
it('should include retry policy', () => {
|
|
418
|
+
const router = manager.createCanaryRoute({
|
|
419
|
+
name: 'retry-router',
|
|
420
|
+
port: 8080,
|
|
421
|
+
protocol: 'http',
|
|
422
|
+
stableTarget: 'stable',
|
|
423
|
+
canaryTarget: 'canary',
|
|
424
|
+
canaryWeight: 10,
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
const retryPolicy = router.routes[0].retryPolicy
|
|
428
|
+
|
|
429
|
+
expect(retryPolicy).toBeDefined()
|
|
430
|
+
expect(retryPolicy?.maxRetries).toBe(3)
|
|
431
|
+
expect(retryPolicy?.httpRetryEvents).toContain('server-error')
|
|
432
|
+
})
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
describe('Virtual Gateways', () => {
|
|
436
|
+
it('should create ingress gateway', () => {
|
|
437
|
+
const gateway = manager.createIngressGateway({
|
|
438
|
+
name: 'ingress-gateway',
|
|
439
|
+
port: 443,
|
|
440
|
+
enableTLS: true,
|
|
441
|
+
certificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/abc123',
|
|
442
|
+
})
|
|
443
|
+
|
|
444
|
+
expect(gateway.id).toContain('vgateway')
|
|
445
|
+
expect(gateway.listeners).toHaveLength(1)
|
|
446
|
+
expect(gateway.listeners[0].tls).toBeDefined()
|
|
447
|
+
expect(gateway.listeners[0].tls?.mode).toBe('STRICT')
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
it('should create gateway without TLS', () => {
|
|
451
|
+
const gateway = manager.createIngressGateway({
|
|
452
|
+
name: 'http-gateway',
|
|
453
|
+
port: 80,
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
expect(gateway.listeners[0].tls).toBeUndefined()
|
|
457
|
+
})
|
|
458
|
+
})
|
|
459
|
+
|
|
460
|
+
describe('CloudFormation Generation', () => {
|
|
461
|
+
it('should generate mesh CloudFormation', () => {
|
|
462
|
+
const mesh = manager.createAppMesh({
|
|
463
|
+
name: 'test-mesh',
|
|
464
|
+
services: [],
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
const cf = manager.generateMeshCF(mesh)
|
|
468
|
+
|
|
469
|
+
expect(cf.Type).toBe('AWS::AppMesh::Mesh')
|
|
470
|
+
expect(cf.Properties.MeshName).toBe('test-mesh')
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
it('should generate virtual node CloudFormation', () => {
|
|
474
|
+
const node = manager.createHTTPVirtualNode({
|
|
475
|
+
name: 'test-node',
|
|
476
|
+
serviceName: 'test-service',
|
|
477
|
+
port: 8080,
|
|
478
|
+
namespace: 'default',
|
|
479
|
+
})
|
|
480
|
+
|
|
481
|
+
const cf = manager.generateVirtualNodeCF(node, 'test-mesh')
|
|
482
|
+
|
|
483
|
+
expect(cf.Type).toBe('AWS::AppMesh::VirtualNode')
|
|
484
|
+
expect(cf.Properties.VirtualNodeName).toBe('test-node')
|
|
485
|
+
expect(cf.Properties.Spec.Listeners).toHaveLength(1)
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
it('should generate virtual router CloudFormation', () => {
|
|
489
|
+
const router = manager.createCanaryRoute({
|
|
490
|
+
name: 'test-router',
|
|
491
|
+
port: 8080,
|
|
492
|
+
protocol: 'http',
|
|
493
|
+
stableTarget: 'stable',
|
|
494
|
+
canaryTarget: 'canary',
|
|
495
|
+
canaryWeight: 10,
|
|
496
|
+
})
|
|
497
|
+
|
|
498
|
+
const cf = manager.generateVirtualRouterCF(router, 'test-mesh')
|
|
499
|
+
|
|
500
|
+
expect(cf.Type).toBe('AWS::AppMesh::VirtualRouter')
|
|
501
|
+
expect(cf.Properties.VirtualRouterName).toBe('test-router')
|
|
502
|
+
})
|
|
503
|
+
})
|
|
504
|
+
|
|
505
|
+
it('should use global instance', () => {
|
|
506
|
+
expect(serviceMeshManager).toBeInstanceOf(ServiceMeshManager)
|
|
507
|
+
})
|
|
508
|
+
})
|