@friggframework/devtools 2.0.0--canary.474.edb48ba.0 → 2.0.0--canary.482.c063a2a.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/infrastructure/docs/PRE-DEPLOYMENT-HEALTH-CHECK-SPEC.md +1317 -0
- package/infrastructure/domains/database/migration-builder.js +64 -2
- package/infrastructure/domains/shared/resource-discovery.enhanced.test.js +306 -0
- package/infrastructure/domains/shared/resource-discovery.js +31 -2
- package/infrastructure/domains/shared/validation/plugin-validator.js +187 -0
- package/infrastructure/domains/shared/validation/plugin-validator.test.js +323 -0
- package/infrastructure/infrastructure-composer.js +22 -0
- package/package.json +6 -6
|
@@ -237,10 +237,21 @@ class MigrationBuilder extends InfrastructureBuilder {
|
|
|
237
237
|
console.log(' 🔍 DEBUG: result.functions is:', typeof result.functions, result.functions);
|
|
238
238
|
// Migration WORKER package config (needs Prisma CLI WASM files)
|
|
239
239
|
const migrationWorkerPackageConfig = {
|
|
240
|
+
individually: true,
|
|
240
241
|
exclude: [
|
|
242
|
+
// Exclude Prisma runtime client - it's in the Lambda Layer
|
|
243
|
+
'node_modules/@prisma/client/**',
|
|
244
|
+
'node_modules/.prisma/**',
|
|
245
|
+
'node_modules/@friggframework/core/generated/**',
|
|
246
|
+
// But KEEP node_modules/prisma/** (the CLI with WASM)
|
|
247
|
+
|
|
248
|
+
// Exclude ALL nested node_modules
|
|
249
|
+
'node_modules/**/node_modules/**',
|
|
250
|
+
|
|
241
251
|
// Exclude AWS SDK (provided by Lambda runtime)
|
|
242
252
|
'node_modules/aws-sdk/**',
|
|
243
253
|
'node_modules/@aws-sdk/**',
|
|
254
|
+
|
|
244
255
|
// Exclude build tools
|
|
245
256
|
'node_modules/esbuild/**',
|
|
246
257
|
'node_modules/@esbuild/**',
|
|
@@ -253,6 +264,8 @@ class MigrationBuilder extends InfrastructureBuilder {
|
|
|
253
264
|
'node_modules/serverless-offline-sqs/**',
|
|
254
265
|
'node_modules/serverless-dotenv-plugin/**',
|
|
255
266
|
'node_modules/serverless-kms-grants/**',
|
|
267
|
+
|
|
268
|
+
// Exclude dev dependencies
|
|
256
269
|
'node_modules/@friggframework/test/**',
|
|
257
270
|
'node_modules/@friggframework/eslint-config/**',
|
|
258
271
|
'node_modules/@friggframework/prettier-config/**',
|
|
@@ -261,23 +274,39 @@ class MigrationBuilder extends InfrastructureBuilder {
|
|
|
261
274
|
'node_modules/jest/**',
|
|
262
275
|
'node_modules/prettier/**',
|
|
263
276
|
'node_modules/eslint/**',
|
|
277
|
+
|
|
278
|
+
// Exclude non-essential Frigg core modules
|
|
264
279
|
'node_modules/@friggframework/core/generated/prisma-mongodb/**',
|
|
265
280
|
'node_modules/@friggframework/core/integrations/**',
|
|
266
281
|
'node_modules/@friggframework/core/user/**',
|
|
282
|
+
|
|
283
|
+
// Exclude other handlers we don't need (keep db-migration worker)
|
|
284
|
+
'node_modules/@friggframework/core/handlers/routers/auth.js',
|
|
285
|
+
'node_modules/@friggframework/core/handlers/routers/health.js',
|
|
286
|
+
'node_modules/@friggframework/core/handlers/routers/user.js',
|
|
287
|
+
'node_modules/@friggframework/core/handlers/routers/websocket.js',
|
|
288
|
+
'node_modules/@friggframework/core/handlers/routers/integration-*.js',
|
|
289
|
+
'node_modules/@friggframework/core/handlers/workers/integration-*.js',
|
|
290
|
+
|
|
291
|
+
// Exclude wrong OS binaries
|
|
267
292
|
'**/query-engine-darwin*',
|
|
268
293
|
'**/schema-engine-darwin*',
|
|
269
294
|
'**/libquery_engine-darwin*',
|
|
270
295
|
'**/*-darwin-arm64*',
|
|
271
296
|
'**/*-darwin*',
|
|
297
|
+
|
|
272
298
|
// Migration worker DOES need Prisma CLI WASM files (for migrate deploy)
|
|
273
299
|
// Only exclude runtime engine WASM (query engine internals)
|
|
274
300
|
'**/runtime/*.wasm',
|
|
301
|
+
|
|
275
302
|
// Additional size optimizations
|
|
276
303
|
'**/*.map',
|
|
277
304
|
'**/*.md',
|
|
305
|
+
'**/LICENSE*',
|
|
306
|
+
'**/*.d.ts',
|
|
307
|
+
'**/*.d.mts',
|
|
278
308
|
'**/examples/**',
|
|
279
309
|
'**/docs/**',
|
|
280
|
-
'**/*.d.ts',
|
|
281
310
|
'src/**',
|
|
282
311
|
'test/**',
|
|
283
312
|
'layers/**',
|
|
@@ -297,21 +326,37 @@ class MigrationBuilder extends InfrastructureBuilder {
|
|
|
297
326
|
|
|
298
327
|
// Migration ROUTER package config (lighter, no Prisma CLI needed)
|
|
299
328
|
const migrationRouterPackageConfig = {
|
|
329
|
+
individually: true,
|
|
300
330
|
exclude: [
|
|
331
|
+
// Exclude Prisma runtime client - it's in the Lambda Layer
|
|
332
|
+
'node_modules/@prisma/client/**',
|
|
333
|
+
'node_modules/.prisma/**',
|
|
334
|
+
'node_modules/@friggframework/core/generated/**',
|
|
335
|
+
|
|
336
|
+
// Router doesn't need Prisma CLI at all
|
|
337
|
+
'node_modules/prisma/**',
|
|
338
|
+
|
|
339
|
+
// Exclude ALL nested node_modules
|
|
340
|
+
'node_modules/**/node_modules/**',
|
|
341
|
+
|
|
301
342
|
// Exclude AWS SDK (provided by Lambda runtime)
|
|
302
343
|
'node_modules/aws-sdk/**',
|
|
303
344
|
'node_modules/@aws-sdk/**',
|
|
345
|
+
|
|
304
346
|
// Exclude build tools
|
|
305
347
|
'node_modules/esbuild/**',
|
|
306
348
|
'node_modules/@esbuild/**',
|
|
307
349
|
'node_modules/typescript/**',
|
|
308
350
|
'node_modules/webpack/**',
|
|
351
|
+
'node_modules/osls/**',
|
|
309
352
|
'node_modules/serverless-esbuild/**',
|
|
310
353
|
'node_modules/serverless-jetpack/**',
|
|
311
354
|
'node_modules/serverless-offline/**',
|
|
312
355
|
'node_modules/serverless-offline-sqs/**',
|
|
313
356
|
'node_modules/serverless-dotenv-plugin/**',
|
|
314
357
|
'node_modules/serverless-kms-grants/**',
|
|
358
|
+
|
|
359
|
+
// Exclude dev dependencies
|
|
315
360
|
'node_modules/@friggframework/test/**',
|
|
316
361
|
'node_modules/@friggframework/eslint-config/**',
|
|
317
362
|
'node_modules/@friggframework/prettier-config/**',
|
|
@@ -320,25 +365,42 @@ class MigrationBuilder extends InfrastructureBuilder {
|
|
|
320
365
|
'node_modules/jest/**',
|
|
321
366
|
'node_modules/prettier/**',
|
|
322
367
|
'node_modules/eslint/**',
|
|
368
|
+
|
|
369
|
+
// Exclude non-essential Frigg core modules
|
|
323
370
|
'node_modules/@friggframework/core/generated/prisma-mongodb/**',
|
|
371
|
+
'node_modules/@friggframework/core/integrations/**',
|
|
324
372
|
'node_modules/@friggframework/core/user/**',
|
|
373
|
+
|
|
374
|
+
// Exclude other handlers we don't need (keep db-migration router)
|
|
375
|
+
'node_modules/@friggframework/core/handlers/routers/auth.js',
|
|
376
|
+
'node_modules/@friggframework/core/handlers/routers/health.js',
|
|
377
|
+
'node_modules/@friggframework/core/handlers/routers/user.js',
|
|
378
|
+
'node_modules/@friggframework/core/handlers/routers/websocket.js',
|
|
379
|
+
'node_modules/@friggframework/core/handlers/routers/integration-*.js',
|
|
380
|
+
'node_modules/@friggframework/core/handlers/workers/**',
|
|
381
|
+
|
|
382
|
+
// Exclude wrong OS binaries
|
|
325
383
|
'**/query-engine-darwin*',
|
|
326
384
|
'**/schema-engine-darwin*',
|
|
327
385
|
'**/libquery_engine-darwin*',
|
|
328
386
|
'**/*-darwin-arm64*',
|
|
329
387
|
'**/*-darwin*',
|
|
388
|
+
|
|
330
389
|
// Router doesn't run migrations - exclude ALL WASM files
|
|
331
390
|
'**/runtime/*.wasm',
|
|
332
391
|
'**/*.wasm*',
|
|
392
|
+
|
|
333
393
|
// Additional size optimizations
|
|
334
394
|
'**/*.map',
|
|
335
395
|
'**/*.md',
|
|
396
|
+
'**/LICENSE*',
|
|
397
|
+
'**/*.d.ts',
|
|
398
|
+
'**/*.d.mts',
|
|
336
399
|
'**/test/**',
|
|
337
400
|
'**/tests/**',
|
|
338
401
|
'**/__tests__/**',
|
|
339
402
|
'**/examples/**',
|
|
340
403
|
'**/docs/**',
|
|
341
|
-
'**/*.d.ts',
|
|
342
404
|
'src/**',
|
|
343
405
|
'test/**',
|
|
344
406
|
'layers/**',
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Discovery Configuration Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for AppDefinition-level discovery control options
|
|
5
|
+
* addressing GitHub Issue #481 - Issue 5
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { shouldRunDiscovery, gatherDiscoveredResources } = require('./resource-discovery');
|
|
9
|
+
|
|
10
|
+
// Mock dependencies
|
|
11
|
+
jest.mock('./providers/provider-factory');
|
|
12
|
+
jest.mock('./cloudformation-discovery');
|
|
13
|
+
jest.mock('../networking/vpc-discovery');
|
|
14
|
+
jest.mock('../security/kms-discovery');
|
|
15
|
+
jest.mock('../database/aurora-discovery');
|
|
16
|
+
jest.mock('../parameters/ssm-discovery');
|
|
17
|
+
|
|
18
|
+
describe('AWS Discovery Configuration (Issue #481 - Issue 5)', () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
|
|
21
|
+
jest.clearAllMocks();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('shouldRunDiscovery - Priority Order', () => {
|
|
25
|
+
it('should use AppDefinition.aws.discovery.enabled when explicitly set to true', () => {
|
|
26
|
+
const appDefinition = {
|
|
27
|
+
aws: { discovery: { enabled: true } },
|
|
28
|
+
vpc: { enable: false }, // Would normally skip
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const result = shouldRunDiscovery(appDefinition);
|
|
32
|
+
|
|
33
|
+
expect(result).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should use AppDefinition.aws.discovery.enabled when explicitly set to false', () => {
|
|
37
|
+
const appDefinition = {
|
|
38
|
+
aws: { discovery: { enabled: false } },
|
|
39
|
+
vpc: { enable: true }, // Would normally run
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const result = shouldRunDiscovery(appDefinition);
|
|
43
|
+
|
|
44
|
+
expect(result).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should fall back to env var when AppDefinition not set', () => {
|
|
48
|
+
process.env.FRIGG_SKIP_AWS_DISCOVERY = 'true';
|
|
49
|
+
|
|
50
|
+
const appDefinition = {
|
|
51
|
+
vpc: { enable: true }, // Would normally run
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const result = shouldRunDiscovery(appDefinition);
|
|
55
|
+
|
|
56
|
+
expect(result).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should auto-detect when neither AppDefinition nor env var is set', () => {
|
|
60
|
+
const appDefinition = {
|
|
61
|
+
vpc: { enable: true },
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const result = shouldRunDiscovery(appDefinition);
|
|
65
|
+
|
|
66
|
+
expect(result).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should prioritize AppDefinition over env var', () => {
|
|
70
|
+
process.env.FRIGG_SKIP_AWS_DISCOVERY = 'true';
|
|
71
|
+
|
|
72
|
+
const appDefinition = {
|
|
73
|
+
aws: { discovery: { enabled: true } }, // Explicit override
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const result = shouldRunDiscovery(appDefinition);
|
|
77
|
+
|
|
78
|
+
expect(result).toBe(true); // AppDefinition wins
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('AppDefinition.aws.discovery.enabled', () => {
|
|
83
|
+
it('should log when using AppDefinition configuration', () => {
|
|
84
|
+
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
85
|
+
|
|
86
|
+
const appDefinition = {
|
|
87
|
+
aws: { discovery: { enabled: true } },
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
shouldRunDiscovery(appDefinition);
|
|
91
|
+
|
|
92
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
93
|
+
expect.stringContaining('AppDefinition.aws.discovery.enabled: true')
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
consoleSpy.mockRestore();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should handle explicit false value', () => {
|
|
100
|
+
const appDefinition = {
|
|
101
|
+
aws: { discovery: { enabled: false } },
|
|
102
|
+
vpc: { enable: true },
|
|
103
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const result = shouldRunDiscovery(appDefinition);
|
|
107
|
+
|
|
108
|
+
expect(result).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should handle undefined correctly (fall through to next priority)', () => {
|
|
112
|
+
const appDefinition = {
|
|
113
|
+
aws: { discovery: { enabled: undefined } },
|
|
114
|
+
vpc: { enable: true },
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const result = shouldRunDiscovery(appDefinition);
|
|
118
|
+
|
|
119
|
+
// Should skip when undefined (fall through to env var check)
|
|
120
|
+
expect(result).toBe(true); // Auto-detect kicks in
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe('Auto-detection based on features', () => {
|
|
125
|
+
it('should run discovery when VPC is enabled', () => {
|
|
126
|
+
const appDefinition = {
|
|
127
|
+
vpc: { enable: true },
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
expect(shouldRunDiscovery(appDefinition)).toBe(true);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should run discovery when KMS encryption is enabled', () => {
|
|
134
|
+
const appDefinition = {
|
|
135
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
expect(shouldRunDiscovery(appDefinition)).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should run discovery when SSM is enabled', () => {
|
|
142
|
+
const appDefinition = {
|
|
143
|
+
ssm: { enable: true },
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
expect(shouldRunDiscovery(appDefinition)).toBe(true);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should run discovery when PostgreSQL is enabled', () => {
|
|
150
|
+
const appDefinition = {
|
|
151
|
+
database: { postgres: { enable: true } },
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
expect(shouldRunDiscovery(appDefinition)).toBe(true);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should not run discovery when no features are enabled', () => {
|
|
158
|
+
const appDefinition = {
|
|
159
|
+
vpc: { enable: false },
|
|
160
|
+
encryption: { fieldLevelEncryptionMethod: 'aes' },
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
expect(shouldRunDiscovery(appDefinition)).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('gatherDiscoveredResources - failOnError behavior', () => {
|
|
168
|
+
const { CloudProviderFactory } = require('./providers/provider-factory');
|
|
169
|
+
const { CloudFormationDiscovery } = require('./cloudformation-discovery');
|
|
170
|
+
|
|
171
|
+
beforeEach(() => {
|
|
172
|
+
const mockProvider = {
|
|
173
|
+
getVpcs: jest.fn(),
|
|
174
|
+
getKmsKeys: jest.fn(),
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
CloudProviderFactory.create = jest.fn().mockReturnValue(mockProvider);
|
|
178
|
+
|
|
179
|
+
// Mock CloudFormation discovery to throw error
|
|
180
|
+
CloudFormationDiscovery.mockImplementation(() => ({
|
|
181
|
+
discoverFromStack: jest.fn().mockRejectedValue(
|
|
182
|
+
new Error('User is not authorized to perform: ec2:DescribeVpcs')
|
|
183
|
+
),
|
|
184
|
+
}));
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should throw error when failOnError is true', async () => {
|
|
188
|
+
const appDefinition = {
|
|
189
|
+
name: 'test-app',
|
|
190
|
+
vpc: { enable: true },
|
|
191
|
+
aws: {
|
|
192
|
+
discovery: {
|
|
193
|
+
enabled: true,
|
|
194
|
+
failOnError: true,
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
await expect(gatherDiscoveredResources(appDefinition)).rejects.toThrow(
|
|
200
|
+
'User is not authorized'
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should return empty object when failOnError is false', async () => {
|
|
205
|
+
const appDefinition = {
|
|
206
|
+
name: 'test-app',
|
|
207
|
+
vpc: { enable: true },
|
|
208
|
+
aws: {
|
|
209
|
+
discovery: {
|
|
210
|
+
enabled: true,
|
|
211
|
+
failOnError: false,
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const result = await gatherDiscoveredResources(appDefinition);
|
|
217
|
+
|
|
218
|
+
expect(result).toEqual({});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('should default to false when failOnError is not set', async () => {
|
|
222
|
+
const appDefinition = {
|
|
223
|
+
name: 'test-app',
|
|
224
|
+
vpc: { enable: true },
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const result = await gatherDiscoveredResources(appDefinition);
|
|
228
|
+
|
|
229
|
+
expect(result).toEqual({});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('should log helpful message when failing gracefully', async () => {
|
|
233
|
+
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation();
|
|
234
|
+
|
|
235
|
+
const appDefinition = {
|
|
236
|
+
name: 'test-app',
|
|
237
|
+
vpc: { enable: true },
|
|
238
|
+
aws: { discovery: { failOnError: false } },
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
await gatherDiscoveredResources(appDefinition);
|
|
242
|
+
|
|
243
|
+
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
244
|
+
expect.stringContaining('Set aws.discovery.failOnError = true')
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
consoleWarnSpy.mockRestore();
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe('Real-world scenarios', () => {
|
|
252
|
+
it('should handle restrictive IAM with explicit disable', () => {
|
|
253
|
+
const appDefinition = {
|
|
254
|
+
vpc: { enable: true },
|
|
255
|
+
aws: {
|
|
256
|
+
discovery: {
|
|
257
|
+
enabled: false, // Explicit disable for restrictive IAM
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const result = shouldRunDiscovery(appDefinition);
|
|
263
|
+
|
|
264
|
+
expect(result).toBe(false);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should allow strict mode for production deployments', async () => {
|
|
268
|
+
const { CloudProviderFactory } = require('./providers/provider-factory');
|
|
269
|
+
const { CloudFormationDiscovery } = require('./cloudformation-discovery');
|
|
270
|
+
|
|
271
|
+
CloudFormationDiscovery.mockImplementation(() => ({
|
|
272
|
+
discoverFromStack: jest.fn().mockRejectedValue(new Error('IAM error')),
|
|
273
|
+
}));
|
|
274
|
+
|
|
275
|
+
const appDefinition = {
|
|
276
|
+
name: 'prod-app',
|
|
277
|
+
vpc: { enable: true },
|
|
278
|
+
aws: {
|
|
279
|
+
discovery: {
|
|
280
|
+
enabled: true,
|
|
281
|
+
failOnError: true, // Strict mode for production
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
await expect(gatherDiscoveredResources(appDefinition)).rejects.toThrow();
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('should allow graceful degradation for dev environments', async () => {
|
|
290
|
+
const appDefinition = {
|
|
291
|
+
name: 'dev-app',
|
|
292
|
+
vpc: { enable: true },
|
|
293
|
+
aws: {
|
|
294
|
+
discovery: {
|
|
295
|
+
enabled: true,
|
|
296
|
+
failOnError: false, // Graceful for dev
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const result = await gatherDiscoveredResources(appDefinition);
|
|
302
|
+
|
|
303
|
+
expect(result).toEqual({});
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
});
|
|
@@ -18,11 +18,26 @@ const { SsmDiscovery } = require('../parameters/ssm-discovery');
|
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Determine if AWS discovery should run
|
|
21
|
-
*
|
|
21
|
+
*
|
|
22
|
+
* Checks in priority order:
|
|
23
|
+
* 1. AppDefinition.aws.discovery.enabled (explicit opt-in/out)
|
|
24
|
+
* 2. FRIGG_SKIP_AWS_DISCOVERY environment variable
|
|
25
|
+
* 3. Auto-detection based on features enabled (VPC, KMS, SSM, PostgreSQL)
|
|
26
|
+
*
|
|
22
27
|
* @param {Object} appDefinition - Application definition
|
|
23
28
|
* @returns {boolean} True if discovery is needed
|
|
24
29
|
*/
|
|
25
30
|
function shouldRunDiscovery(appDefinition) {
|
|
31
|
+
// Priority 1: Check AppDefinition-level configuration
|
|
32
|
+
if (appDefinition.aws?.discovery?.enabled !== undefined) {
|
|
33
|
+
const enabled = appDefinition.aws.discovery.enabled;
|
|
34
|
+
console.log(
|
|
35
|
+
`⚙️ Using AppDefinition.aws.discovery.enabled: ${enabled}`
|
|
36
|
+
);
|
|
37
|
+
return enabled;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Priority 2: Check environment variable
|
|
26
41
|
console.log(
|
|
27
42
|
'⚙️ Checking FRIGG_SKIP_AWS_DISCOVERY:',
|
|
28
43
|
process.env.FRIGG_SKIP_AWS_DISCOVERY
|
|
@@ -35,6 +50,7 @@ function shouldRunDiscovery(appDefinition) {
|
|
|
35
50
|
return false;
|
|
36
51
|
}
|
|
37
52
|
|
|
53
|
+
// Priority 3: Auto-detect based on enabled features
|
|
38
54
|
return (
|
|
39
55
|
appDefinition.vpc?.enable === true ||
|
|
40
56
|
appDefinition.encryption?.fieldLevelEncryptionMethod === 'kms' ||
|
|
@@ -177,10 +193,23 @@ async function gatherDiscoveredResources(appDefinition) {
|
|
|
177
193
|
console.error('❌ Cloud resource discovery failed:', error.message);
|
|
178
194
|
console.error('Stack:', error.stack);
|
|
179
195
|
|
|
180
|
-
//
|
|
196
|
+
// Check if discovery failures should fail the deployment
|
|
197
|
+
const failOnError = appDefinition.aws?.discovery?.failOnError ?? false;
|
|
198
|
+
|
|
199
|
+
if (failOnError) {
|
|
200
|
+
console.error(
|
|
201
|
+
'❌ Discovery failure blocking deployment (aws.discovery.failOnError = true)'
|
|
202
|
+
);
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Graceful degradation - return empty resources and let validation handle it
|
|
181
207
|
console.warn(
|
|
182
208
|
'⚠️ Continuing with empty discovered resources. This may cause deployment issues if resources are required.'
|
|
183
209
|
);
|
|
210
|
+
console.warn(
|
|
211
|
+
'💡 Set aws.discovery.failOnError = true in AppDefinition to fail on discovery errors.'
|
|
212
|
+
);
|
|
184
213
|
return {};
|
|
185
214
|
}
|
|
186
215
|
}
|