@friggframework/devtools 2.0.0--canary.406.78e2685.0 → 2.0.0--canary.398.dd443c7.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.
Files changed (34) hide show
  1. package/frigg-cli/build-command/index.js +4 -2
  2. package/frigg-cli/deploy-command/index.js +5 -2
  3. package/frigg-cli/generate-iam-command.js +115 -0
  4. package/frigg-cli/index.js +11 -1
  5. package/infrastructure/AWS-DISCOVERY-TROUBLESHOOTING.md +245 -0
  6. package/infrastructure/AWS-IAM-CREDENTIAL-NEEDS.md +596 -0
  7. package/infrastructure/DEPLOYMENT-INSTRUCTIONS.md +268 -0
  8. package/infrastructure/GENERATE-IAM-DOCS.md +253 -0
  9. package/infrastructure/IAM-POLICY-TEMPLATES.md +176 -0
  10. package/infrastructure/README-TESTING.md +332 -0
  11. package/infrastructure/README.md +421 -0
  12. package/infrastructure/WEBSOCKET-CONFIGURATION.md +105 -0
  13. package/infrastructure/__tests__/fixtures/mock-aws-resources.js +391 -0
  14. package/infrastructure/__tests__/helpers/test-utils.js +277 -0
  15. package/infrastructure/aws-discovery.js +568 -0
  16. package/infrastructure/aws-discovery.test.js +373 -0
  17. package/infrastructure/build-time-discovery.js +206 -0
  18. package/infrastructure/build-time-discovery.test.js +375 -0
  19. package/infrastructure/create-frigg-infrastructure.js +2 -2
  20. package/infrastructure/frigg-deployment-iam-stack.yaml +379 -0
  21. package/infrastructure/iam-generator.js +687 -0
  22. package/infrastructure/iam-generator.test.js +169 -0
  23. package/infrastructure/iam-policy-basic.json +212 -0
  24. package/infrastructure/iam-policy-full.json +282 -0
  25. package/infrastructure/integration.test.js +383 -0
  26. package/infrastructure/run-discovery.js +110 -0
  27. package/infrastructure/serverless-template.js +514 -167
  28. package/infrastructure/serverless-template.test.js +541 -0
  29. package/management-ui/dist/assets/FriggLogo-B7Xx8ZW1.svg +1 -0
  30. package/management-ui/dist/assets/index-BA21WgFa.js +1221 -0
  31. package/management-ui/dist/assets/index-CbM64Oba.js +1221 -0
  32. package/management-ui/dist/assets/index-CkvseXTC.css +1 -0
  33. package/management-ui/dist/index.html +14 -0
  34. package/package.json +9 -5
@@ -0,0 +1,391 @@
1
+ /**
2
+ * Mock AWS resources for consistent testing across all VPC/KMS/SSM tests
3
+ */
4
+
5
+ const mockVpc = {
6
+ VpcId: 'vpc-12345678',
7
+ IsDefault: true,
8
+ State: 'available',
9
+ CidrBlock: '10.0.0.0/16',
10
+ DhcpOptionsId: 'dopt-12345678',
11
+ InstanceTenancy: 'default'
12
+ };
13
+
14
+ const mockSubnets = [
15
+ {
16
+ SubnetId: 'subnet-private-1',
17
+ VpcId: 'vpc-12345678',
18
+ CidrBlock: '10.0.1.0/24',
19
+ AvailabilityZone: 'us-east-1a',
20
+ State: 'available',
21
+ MapPublicIpOnLaunch: false
22
+ },
23
+ {
24
+ SubnetId: 'subnet-private-2',
25
+ VpcId: 'vpc-12345678',
26
+ CidrBlock: '10.0.2.0/24',
27
+ AvailabilityZone: 'us-east-1b',
28
+ State: 'available',
29
+ MapPublicIpOnLaunch: false
30
+ },
31
+ {
32
+ SubnetId: 'subnet-public-1',
33
+ VpcId: 'vpc-12345678',
34
+ CidrBlock: '10.0.3.0/24',
35
+ AvailabilityZone: 'us-east-1a',
36
+ State: 'available',
37
+ MapPublicIpOnLaunch: true
38
+ }
39
+ ];
40
+
41
+ const mockSecurityGroups = [
42
+ {
43
+ GroupId: 'sg-frigg-12345678',
44
+ GroupName: 'frigg-lambda-sg',
45
+ Description: 'Security group for Frigg Lambda functions',
46
+ VpcId: 'vpc-12345678'
47
+ },
48
+ {
49
+ GroupId: 'sg-default-12345678',
50
+ GroupName: 'default',
51
+ Description: 'Default security group',
52
+ VpcId: 'vpc-12345678'
53
+ }
54
+ ];
55
+
56
+ const mockRouteTables = [
57
+ {
58
+ RouteTableId: 'rtb-private-12345678',
59
+ VpcId: 'vpc-12345678',
60
+ Routes: [
61
+ {
62
+ DestinationCidrBlock: '10.0.0.0/16',
63
+ GatewayId: 'local',
64
+ State: 'active'
65
+ },
66
+ {
67
+ DestinationCidrBlock: '0.0.0.0/0',
68
+ NatGatewayId: 'nat-12345678',
69
+ State: 'active'
70
+ }
71
+ ],
72
+ Associations: [
73
+ {
74
+ RouteTableAssociationId: 'rtbassoc-12345678',
75
+ RouteTableId: 'rtb-private-12345678',
76
+ SubnetId: 'subnet-private-1'
77
+ }
78
+ ]
79
+ },
80
+ {
81
+ RouteTableId: 'rtb-public-12345678',
82
+ VpcId: 'vpc-12345678',
83
+ Routes: [
84
+ {
85
+ DestinationCidrBlock: '10.0.0.0/16',
86
+ GatewayId: 'local',
87
+ State: 'active'
88
+ },
89
+ {
90
+ DestinationCidrBlock: '0.0.0.0/0',
91
+ GatewayId: 'igw-12345678',
92
+ State: 'active'
93
+ }
94
+ ],
95
+ Associations: [
96
+ {
97
+ RouteTableAssociationId: 'rtbassoc-87654321',
98
+ RouteTableId: 'rtb-public-12345678',
99
+ SubnetId: 'subnet-public-1'
100
+ }
101
+ ]
102
+ }
103
+ ];
104
+
105
+ const mockKmsKeys = [
106
+ {
107
+ KeyId: '12345678-1234-1234-1234-123456789012',
108
+ Arn: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012'
109
+ },
110
+ {
111
+ KeyId: '87654321-8765-4321-8765-876543218765',
112
+ Arn: 'arn:aws:kms:us-east-1:123456789012:key/87654321-8765-4321-8765-876543218765'
113
+ }
114
+ ];
115
+
116
+ const mockKmsKeyMetadata = {
117
+ KeyId: '12345678-1234-1234-1234-123456789012',
118
+ Arn: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012',
119
+ CreationDate: new Date('2023-01-01'),
120
+ Enabled: true,
121
+ Description: 'Default KMS key for Frigg encryption',
122
+ KeyUsage: 'ENCRYPT_DECRYPT',
123
+ KeyState: 'Enabled',
124
+ Origin: 'AWS_KMS',
125
+ KeyManager: 'CUSTOMER',
126
+ CustomerMasterKeySpec: 'SYMMETRIC_DEFAULT'
127
+ };
128
+
129
+ const mockStsCallerIdentity = {
130
+ UserId: 'AIDACKCEVSQ6C2EXAMPLE',
131
+ Account: '123456789012',
132
+ Arn: 'arn:aws:iam::123456789012:user/test-user'
133
+ };
134
+
135
+ const mockDiscoveredResources = {
136
+ defaultVpcId: mockVpc.VpcId,
137
+ defaultSecurityGroupId: mockSecurityGroups[0].GroupId,
138
+ privateSubnetId1: mockSubnets[0].SubnetId,
139
+ privateSubnetId2: mockSubnets[1].SubnetId,
140
+ privateRouteTableId: mockRouteTables[0].RouteTableId,
141
+ defaultKmsKeyId: mockKmsKeyMetadata.Arn
142
+ };
143
+
144
+ // App definitions for testing different scenarios
145
+ const mockAppDefinitions = {
146
+ vpcOnly: {
147
+ name: 'vpc-test-app',
148
+ vpc: { enable: true },
149
+ integrations: []
150
+ },
151
+
152
+ kmsOnly: {
153
+ name: 'kms-test-app',
154
+ encryption: { useDefaultKMSForFieldLevelEncryption: true },
155
+ integrations: []
156
+ },
157
+
158
+ ssmOnly: {
159
+ name: 'ssm-test-app',
160
+ ssm: { enable: true },
161
+ integrations: []
162
+ },
163
+
164
+ allFeatures: {
165
+ name: 'full-feature-app',
166
+ vpc: { enable: true },
167
+ encryption: { useDefaultKMSForFieldLevelEncryption: true },
168
+ ssm: { enable: true },
169
+ integrations: [{
170
+ Definition: {
171
+ name: 'testIntegration'
172
+ }
173
+ }]
174
+ },
175
+
176
+ noFeatures: {
177
+ name: 'minimal-app',
178
+ integrations: []
179
+ },
180
+
181
+ multipleIntegrations: {
182
+ name: 'multi-integration-app',
183
+ vpc: { enable: true },
184
+ integrations: [
185
+ {
186
+ Definition: {
187
+ name: 'hubspot'
188
+ }
189
+ },
190
+ {
191
+ Definition: {
192
+ name: 'salesforce'
193
+ }
194
+ }
195
+ ]
196
+ }
197
+ };
198
+
199
+ // Mock serverless service configurations
200
+ const mockServerlessServices = {
201
+ withVpc: {
202
+ provider: {
203
+ name: 'aws',
204
+ region: 'us-east-1',
205
+ vpc: '${self:custom.vpc.${self:provider.stage}}'
206
+ },
207
+ plugins: [],
208
+ custom: {
209
+ vpc: {
210
+ '${self:provider.stage}': {
211
+ securityGroupIds: ['${env:AWS_DISCOVERY_SECURITY_GROUP_ID}'],
212
+ subnetIds: [
213
+ '${env:AWS_DISCOVERY_SUBNET_ID_1}',
214
+ '${env:AWS_DISCOVERY_SUBNET_ID_2}'
215
+ ]
216
+ }
217
+ }
218
+ },
219
+ functions: {}
220
+ },
221
+
222
+ withKms: {
223
+ provider: {
224
+ name: 'aws',
225
+ region: 'us-east-1'
226
+ },
227
+ plugins: ['serverless-kms-grants'],
228
+ custom: {
229
+ kmsGrants: {
230
+ kmsKeyId: '${env:AWS_DISCOVERY_KMS_KEY_ID}'
231
+ }
232
+ },
233
+ functions: {}
234
+ },
235
+
236
+ withSsm: {
237
+ provider: {
238
+ name: 'aws',
239
+ region: 'us-east-1',
240
+ layers: [
241
+ 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11'
242
+ ]
243
+ },
244
+ plugins: [],
245
+ custom: {},
246
+ functions: {}
247
+ },
248
+
249
+ withAll: {
250
+ provider: {
251
+ name: 'aws',
252
+ region: 'us-east-1',
253
+ vpc: '${self:custom.vpc.${self:provider.stage}}',
254
+ layers: [
255
+ 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11'
256
+ ]
257
+ },
258
+ plugins: ['serverless-kms-grants'],
259
+ custom: {
260
+ vpc: {
261
+ '${self:provider.stage}': {
262
+ securityGroupIds: ['${env:AWS_DISCOVERY_SECURITY_GROUP_ID}'],
263
+ subnetIds: [
264
+ '${env:AWS_DISCOVERY_SUBNET_ID_1}',
265
+ '${env:AWS_DISCOVERY_SUBNET_ID_2}'
266
+ ]
267
+ }
268
+ },
269
+ kmsGrants: {
270
+ kmsKeyId: '${env:AWS_DISCOVERY_KMS_KEY_ID}'
271
+ }
272
+ },
273
+ functions: {}
274
+ }
275
+ };
276
+
277
+ // Environment variables for testing
278
+ const mockEnvironmentVariables = {
279
+ AWS_DISCOVERY_VPC_ID: mockVpc.VpcId,
280
+ AWS_DISCOVERY_SECURITY_GROUP_ID: mockSecurityGroups[0].GroupId,
281
+ AWS_DISCOVERY_SUBNET_ID_1: mockSubnets[0].SubnetId,
282
+ AWS_DISCOVERY_SUBNET_ID_2: mockSubnets[1].SubnetId,
283
+ AWS_DISCOVERY_ROUTE_TABLE_ID: mockRouteTables[0].RouteTableId,
284
+ AWS_DISCOVERY_KMS_KEY_ID: mockKmsKeyMetadata.Arn
285
+ };
286
+
287
+ // Fallback environment variables for error scenarios
288
+ const mockFallbackEnvironmentVariables = {
289
+ AWS_DISCOVERY_VPC_ID: 'vpc-fallback',
290
+ AWS_DISCOVERY_SECURITY_GROUP_ID: 'sg-fallback',
291
+ AWS_DISCOVERY_SUBNET_ID_1: 'subnet-fallback-1',
292
+ AWS_DISCOVERY_SUBNET_ID_2: 'subnet-fallback-2',
293
+ AWS_DISCOVERY_ROUTE_TABLE_ID: 'rtb-fallback',
294
+ AWS_DISCOVERY_KMS_KEY_ID: 'arn:aws:kms:*:*:key/*'
295
+ };
296
+
297
+ // Mock AWS SDK responses
298
+ const mockAwsSdkResponses = {
299
+ ec2: {
300
+ describeVpcs: {
301
+ default: {
302
+ Vpcs: [mockVpc]
303
+ },
304
+ empty: {
305
+ Vpcs: []
306
+ },
307
+ multiple: {
308
+ Vpcs: [mockVpc, { ...mockVpc, VpcId: 'vpc-87654321', IsDefault: false }]
309
+ }
310
+ },
311
+
312
+ describeSubnets: {
313
+ private: {
314
+ Subnets: mockSubnets.slice(0, 2) // Only private subnets
315
+ },
316
+ mixed: {
317
+ Subnets: mockSubnets // All subnets
318
+ },
319
+ empty: {
320
+ Subnets: []
321
+ }
322
+ },
323
+
324
+ describeSecurityGroups: {
325
+ frigg: {
326
+ SecurityGroups: [mockSecurityGroups[0]]
327
+ },
328
+ default: {
329
+ SecurityGroups: [mockSecurityGroups[1]]
330
+ },
331
+ empty: {
332
+ SecurityGroups: []
333
+ }
334
+ },
335
+
336
+ describeRouteTables: {
337
+ private: {
338
+ RouteTables: [mockRouteTables[0]]
339
+ },
340
+ public: {
341
+ RouteTables: [mockRouteTables[1]]
342
+ },
343
+ mixed: {
344
+ RouteTables: mockRouteTables
345
+ }
346
+ }
347
+ },
348
+
349
+ kms: {
350
+ listKeys: {
351
+ withKeys: {
352
+ Keys: mockKmsKeys
353
+ },
354
+ empty: {
355
+ Keys: []
356
+ }
357
+ },
358
+
359
+ describeKey: {
360
+ customer: {
361
+ KeyMetadata: mockKmsKeyMetadata
362
+ },
363
+ aws: {
364
+ KeyMetadata: {
365
+ ...mockKmsKeyMetadata,
366
+ KeyManager: 'AWS'
367
+ }
368
+ }
369
+ }
370
+ },
371
+
372
+ sts: {
373
+ getCallerIdentity: mockStsCallerIdentity
374
+ }
375
+ };
376
+
377
+ module.exports = {
378
+ mockVpc,
379
+ mockSubnets,
380
+ mockSecurityGroups,
381
+ mockRouteTables,
382
+ mockKmsKeys,
383
+ mockKmsKeyMetadata,
384
+ mockStsCallerIdentity,
385
+ mockDiscoveredResources,
386
+ mockAppDefinitions,
387
+ mockServerlessServices,
388
+ mockEnvironmentVariables,
389
+ mockFallbackEnvironmentVariables,
390
+ mockAwsSdkResponses
391
+ };
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Test utilities for VPC/KMS/SSM testing
3
+ */
4
+
5
+ const { mockEnvironmentVariables, mockFallbackEnvironmentVariables } = require('../fixtures/mock-aws-resources');
6
+
7
+ /**
8
+ * Set up environment variables for testing
9
+ * @param {Object} envVars - Environment variables to set
10
+ */
11
+ function setTestEnvironmentVariables(envVars = mockEnvironmentVariables) {
12
+ Object.keys(envVars).forEach(key => {
13
+ process.env[key] = envVars[key];
14
+ });
15
+ }
16
+
17
+ /**
18
+ * Clean up environment variables after testing
19
+ * @param {Object} envVars - Environment variables to clean up
20
+ */
21
+ function cleanupTestEnvironmentVariables(envVars = mockEnvironmentVariables) {
22
+ Object.keys(envVars).forEach(key => {
23
+ delete process.env[key];
24
+ });
25
+ }
26
+
27
+ /**
28
+ * Set up fallback environment variables for error testing
29
+ */
30
+ function setFallbackEnvironmentVariables() {
31
+ setTestEnvironmentVariables(mockFallbackEnvironmentVariables);
32
+ }
33
+
34
+ /**
35
+ * Create a mock AWS SDK client send function
36
+ * @param {Array} responses - Array of responses to return in order
37
+ * @returns {Function} Mock send function
38
+ */
39
+ function createMockSendFunction(responses) {
40
+ let callCount = 0;
41
+ return jest.fn().mockImplementation(() => {
42
+ const response = responses[callCount] || responses[responses.length - 1];
43
+ callCount++;
44
+ return Promise.resolve(response);
45
+ });
46
+ }
47
+
48
+ /**
49
+ * Create a mock serverless object for plugin testing
50
+ * @param {Object} serviceConfig - Serverless service configuration
51
+ * @param {Array} commands - Commands in processedInput
52
+ * @returns {Object} Mock serverless object
53
+ */
54
+ function createMockServerless(serviceConfig = {}, commands = []) {
55
+ return {
56
+ cli: {
57
+ log: jest.fn()
58
+ },
59
+ service: {
60
+ provider: {
61
+ name: 'aws',
62
+ region: 'us-east-1',
63
+ ...serviceConfig.provider
64
+ },
65
+ plugins: serviceConfig.plugins || [],
66
+ custom: serviceConfig.custom || {},
67
+ functions: serviceConfig.functions || {},
68
+ ...serviceConfig
69
+ },
70
+ processedInput: {
71
+ commands: commands
72
+ },
73
+ getProvider: jest.fn(() => ({})),
74
+ extendConfiguration: jest.fn()
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Verify that environment variables are set correctly
80
+ * @param {Object} expectedVars - Expected environment variables
81
+ */
82
+ function verifyEnvironmentVariables(expectedVars) {
83
+ Object.keys(expectedVars).forEach(key => {
84
+ expect(process.env[key]).toBe(expectedVars[key]);
85
+ });
86
+ }
87
+
88
+ /**
89
+ * Create a mock integration definition
90
+ * @param {string} name - Integration name
91
+ * @returns {Object} Mock integration
92
+ */
93
+ function createMockIntegration(name = 'testIntegration') {
94
+ return {
95
+ Definition: {
96
+ name: name
97
+ }
98
+ };
99
+ }
100
+
101
+ /**
102
+ * Create a mock app definition with specified features
103
+ * @param {Object} features - Features to enable (vpc, kms, ssm)
104
+ * @param {Array} integrations - Integration definitions
105
+ * @returns {Object} Mock app definition
106
+ */
107
+ function createMockAppDefinition(features = {}, integrations = []) {
108
+ const appDefinition = {
109
+ name: 'test-app',
110
+ integrations: integrations
111
+ };
112
+
113
+ if (features.vpc) {
114
+ appDefinition.vpc = { enable: true };
115
+ }
116
+
117
+ if (features.kms) {
118
+ appDefinition.encryption = { useDefaultKMSForFieldLevelEncryption: true };
119
+ }
120
+
121
+ if (features.ssm) {
122
+ appDefinition.ssm = { enable: true };
123
+ }
124
+
125
+ return appDefinition;
126
+ }
127
+
128
+ /**
129
+ * Verify serverless configuration contains expected VPC settings
130
+ * @param {Object} config - Serverless configuration
131
+ */
132
+ function verifyVpcConfiguration(config) {
133
+ expect(config.provider.vpc).toBe('${self:custom.vpc.${self:provider.stage}}');
134
+ expect(config.custom.vpc).toEqual({
135
+ '${self:provider.stage}': {
136
+ securityGroupIds: ['${env:AWS_DISCOVERY_SECURITY_GROUP_ID}'],
137
+ subnetIds: [
138
+ '${env:AWS_DISCOVERY_SUBNET_ID_1}',
139
+ '${env:AWS_DISCOVERY_SUBNET_ID_2}'
140
+ ]
141
+ }
142
+ });
143
+ expect(config.resources.Resources.VPCEndpointS3).toBeDefined();
144
+ }
145
+
146
+ /**
147
+ * Verify serverless configuration contains expected KMS settings
148
+ * @param {Object} config - Serverless configuration
149
+ */
150
+ function verifyKmsConfiguration(config) {
151
+ expect(config.plugins).toContain('serverless-kms-grants');
152
+ expect(config.provider.environment.KMS_KEY_ARN).toBe('${self:custom.kmsGrants.kmsKeyId}');
153
+ expect(config.custom.kmsGrants).toEqual({
154
+ kmsKeyId: '${env:AWS_DISCOVERY_KMS_KEY_ID}'
155
+ });
156
+
157
+ // Verify KMS IAM permissions
158
+ const kmsPermission = config.provider.iamRoleStatements.find(
159
+ statement => statement.Action.includes('kms:GenerateDataKey')
160
+ );
161
+ expect(kmsPermission).toBeDefined();
162
+ }
163
+
164
+ /**
165
+ * Verify serverless configuration contains expected SSM settings
166
+ * @param {Object} config - Serverless configuration
167
+ */
168
+ function verifySsmConfiguration(config) {
169
+ expect(config.provider.layers).toEqual([
170
+ 'arn:aws:lambda:${self:provider.region}:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11'
171
+ ]);
172
+ expect(config.provider.environment.SSM_PARAMETER_PREFIX).toBe('/${self:service}/${self:provider.stage}');
173
+
174
+ // Verify SSM IAM permissions
175
+ const ssmPermission = config.provider.iamRoleStatements.find(
176
+ statement => statement.Action.includes('ssm:GetParameter')
177
+ );
178
+ expect(ssmPermission).toBeDefined();
179
+ }
180
+
181
+ /**
182
+ * Verify integration-specific resources are created
183
+ * @param {Object} config - Serverless configuration
184
+ * @param {string} integrationName - Name of the integration
185
+ */
186
+ function verifyIntegrationConfiguration(config, integrationName) {
187
+ const capitalizedName = integrationName.charAt(0).toUpperCase() + integrationName.slice(1);
188
+
189
+ // Verify integration function
190
+ expect(config.functions[integrationName]).toBeDefined();
191
+
192
+ // Verify queue worker function
193
+ expect(config.functions[`${integrationName}QueueWorker`]).toBeDefined();
194
+
195
+ // Verify SQS queue resource
196
+ expect(config.resources.Resources[`${capitalizedName}Queue`]).toBeDefined();
197
+
198
+ // Verify environment variable
199
+ expect(config.provider.environment[`${integrationName.toUpperCase()}_QUEUE_URL`]).toBeDefined();
200
+ }
201
+
202
+ /**
203
+ * Wait for async operations to complete
204
+ * @param {number} ms - Milliseconds to wait
205
+ */
206
+ function wait(ms = 0) {
207
+ return new Promise(resolve => setTimeout(resolve, ms));
208
+ }
209
+
210
+ /**
211
+ * Capture console output for testing
212
+ */
213
+ function captureConsoleOutput() {
214
+ const originalLog = console.log;
215
+ const originalError = console.error;
216
+ const originalWarn = console.warn;
217
+
218
+ const logs = [];
219
+ const errors = [];
220
+ const warnings = [];
221
+
222
+ console.log = (...args) => {
223
+ logs.push(args.join(' '));
224
+ };
225
+
226
+ console.error = (...args) => {
227
+ errors.push(args.join(' '));
228
+ };
229
+
230
+ console.warn = (...args) => {
231
+ warnings.push(args.join(' '));
232
+ };
233
+
234
+ return {
235
+ logs,
236
+ errors,
237
+ warnings,
238
+ restore: () => {
239
+ console.log = originalLog;
240
+ console.error = originalError;
241
+ console.warn = originalWarn;
242
+ }
243
+ };
244
+ }
245
+
246
+ /**
247
+ * Mock process.argv for testing
248
+ * @param {Array} argv - Arguments to set
249
+ */
250
+ function mockProcessArgv(argv = ['node', 'test']) {
251
+ const originalArgv = process.argv;
252
+ jest.spyOn(process, 'argv', 'get').mockReturnValue(argv);
253
+
254
+ return {
255
+ restore: () => {
256
+ process.argv = originalArgv;
257
+ }
258
+ };
259
+ }
260
+
261
+ module.exports = {
262
+ setTestEnvironmentVariables,
263
+ cleanupTestEnvironmentVariables,
264
+ setFallbackEnvironmentVariables,
265
+ createMockSendFunction,
266
+ createMockServerless,
267
+ verifyEnvironmentVariables,
268
+ createMockIntegration,
269
+ createMockAppDefinition,
270
+ verifyVpcConfiguration,
271
+ verifyKmsConfiguration,
272
+ verifySsmConfiguration,
273
+ verifyIntegrationConfiguration,
274
+ wait,
275
+ captureConsoleOutput,
276
+ mockProcessArgv
277
+ };