@friggframework/devtools 2.0.0--canary.461.ec909cf.0 → 2.0.0--canary.461.9483dbe.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/frigg-cli/__tests__/unit/commands/build.test.js +6 -6
- package/frigg-cli/build-command/index.js +1 -1
- package/frigg-cli/deploy-command/index.js +6 -6
- package/frigg-cli/generate-command/index.js +2 -2
- package/frigg-cli/generate-iam-command.js +10 -10
- package/frigg-cli/start-command/index.js +1 -1
- package/frigg-cli/start-command/start-command.test.js +3 -3
- package/frigg-cli/utils/database-validator.js +14 -21
- package/infrastructure/REFACTOR.md +532 -0
- package/infrastructure/TRANSFORMATION-VISUAL.md +239 -0
- package/infrastructure/__tests__/postgres-config.test.js +1 -1
- package/infrastructure/create-frigg-infrastructure.js +1 -1
- package/infrastructure/{DEPLOYMENT-INSTRUCTIONS.md → docs/deployment-instructions.md} +3 -3
- package/infrastructure/{IAM-POLICY-TEMPLATES.md → docs/iam-policy-templates.md} +9 -10
- package/infrastructure/domains/database/aurora-discovery.js +81 -0
- package/infrastructure/domains/database/aurora-discovery.test.js +188 -0
- package/infrastructure/domains/integration/integration-builder.js +178 -0
- package/infrastructure/domains/integration/integration-builder.test.js +362 -0
- package/infrastructure/domains/integration/websocket-builder.js +69 -0
- package/infrastructure/domains/integration/websocket-builder.test.js +195 -0
- package/infrastructure/domains/networking/vpc-discovery.test.js +257 -0
- package/infrastructure/domains/parameters/ssm-builder.js +79 -0
- package/infrastructure/domains/parameters/ssm-builder.test.js +188 -0
- package/infrastructure/domains/parameters/ssm-discovery.js +84 -0
- package/infrastructure/domains/parameters/ssm-discovery.test.js +210 -0
- package/infrastructure/{iam-generator.js → domains/security/iam-generator.js} +2 -2
- package/infrastructure/domains/security/kms-builder.js +169 -0
- package/infrastructure/domains/security/kms-builder.test.js +354 -0
- package/infrastructure/domains/security/kms-discovery.js +80 -0
- package/infrastructure/domains/security/kms-discovery.test.js +176 -0
- package/infrastructure/domains/shared/base-builder.js +112 -0
- package/infrastructure/domains/shared/builder-orchestrator.js +212 -0
- package/infrastructure/domains/shared/builder-orchestrator.test.js +213 -0
- package/infrastructure/domains/shared/environment-builder.js +118 -0
- package/infrastructure/domains/shared/environment-builder.test.js +246 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +366 -0
- package/infrastructure/domains/shared/providers/azure-provider-adapter.stub.js +93 -0
- package/infrastructure/domains/shared/providers/cloud-provider-adapter.js +136 -0
- package/infrastructure/domains/shared/providers/gcp-provider-adapter.stub.js +82 -0
- package/infrastructure/domains/shared/providers/provider-factory.js +108 -0
- package/infrastructure/domains/shared/providers/provider-factory.test.js +170 -0
- package/infrastructure/domains/shared/resource-discovery.js +132 -0
- package/infrastructure/domains/shared/resource-discovery.test.js +410 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.js +2 -3
- package/infrastructure/domains/shared/utilities/base-definition-factory.js.bak +338 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +248 -0
- package/infrastructure/domains/shared/utilities/handler-path-resolver.test.js +259 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.js +55 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +134 -0
- package/infrastructure/domains/shared/validation/env-validator.test.js +173 -0
- package/infrastructure/esbuild.config.js +53 -0
- package/infrastructure/infrastructure-composer.js +85 -0
- package/infrastructure/scripts/build-prisma-layer.js +60 -47
- package/infrastructure/{build-time-discovery.test.js → scripts/build-time-discovery.test.js} +5 -4
- package/layers/prisma/nodejs/package.json +8 -0
- package/management-ui/server/utils/environment/awsParameterStore.js +29 -18
- package/package.json +8 -8
- package/infrastructure/aws-discovery.js +0 -1704
- package/infrastructure/aws-discovery.test.js +0 -1666
- package/infrastructure/serverless-template.js +0 -2804
- package/infrastructure/serverless-template.test.js +0 -1897
- /package/infrastructure/{POSTGRES-CONFIGURATION.md → docs/POSTGRES-CONFIGURATION.md} +0 -0
- /package/infrastructure/{WEBSOCKET-CONFIGURATION.md → docs/WEBSOCKET-CONFIGURATION.md} +0 -0
- /package/infrastructure/{GENERATE-IAM-DOCS.md → docs/generate-iam-command.md} +0 -0
- /package/infrastructure/{iam-generator.test.js → domains/security/iam-generator.test.js} +0 -0
- /package/infrastructure/{frigg-deployment-iam-stack.yaml → domains/security/templates/frigg-deployment-iam-stack.yaml} +0 -0
- /package/infrastructure/{iam-policy-basic.json → domains/security/templates/iam-policy-basic.json} +0 -0
- /package/infrastructure/{iam-policy-full.json → domains/security/templates/iam-policy-full.json} +0 -0
- /package/infrastructure/{env-validator.js → domains/shared/validation/env-validator.js} +0 -0
- /package/infrastructure/{build-time-discovery.js → scripts/build-time-discovery.js} +0 -0
- /package/infrastructure/{run-discovery.js → scripts/run-discovery.js} +0 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource Discovery Service
|
|
3
|
+
*
|
|
4
|
+
* Domain Service - Hexagonal Architecture
|
|
5
|
+
*
|
|
6
|
+
* Orchestrates discovery of cloud resources (VPC, databases, encryption keys, etc.)
|
|
7
|
+
* using the cloud provider abstraction layer and domain-specific discovery services.
|
|
8
|
+
*
|
|
9
|
+
* This service is cloud-agnostic and delegates to provider-specific implementations.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { CloudProviderFactory } = require('./providers/provider-factory');
|
|
13
|
+
const { VpcDiscovery } = require('../networking/vpc-discovery');
|
|
14
|
+
const { KmsDiscovery } = require('../security/kms-discovery');
|
|
15
|
+
const { AuroraDiscovery } = require('../database/aurora-discovery');
|
|
16
|
+
const { SsmDiscovery } = require('../parameters/ssm-discovery');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Determine if AWS discovery should run
|
|
20
|
+
*
|
|
21
|
+
* @param {Object} appDefinition - Application definition
|
|
22
|
+
* @returns {boolean} True if discovery is needed
|
|
23
|
+
*/
|
|
24
|
+
function shouldRunDiscovery(appDefinition) {
|
|
25
|
+
console.log(
|
|
26
|
+
'⚙️ Checking FRIGG_SKIP_AWS_DISCOVERY:',
|
|
27
|
+
process.env.FRIGG_SKIP_AWS_DISCOVERY
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
if (process.env.FRIGG_SKIP_AWS_DISCOVERY === 'true') {
|
|
31
|
+
console.log(
|
|
32
|
+
'⚙️ Skipping AWS discovery because FRIGG_SKIP_AWS_DISCOVERY is set.'
|
|
33
|
+
);
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
appDefinition.vpc?.enable === true ||
|
|
39
|
+
appDefinition.encryption?.fieldLevelEncryptionMethod === 'kms' ||
|
|
40
|
+
appDefinition.ssm?.enable === true ||
|
|
41
|
+
appDefinition.database?.postgres?.enable === true
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Gather discovered cloud resources
|
|
47
|
+
*
|
|
48
|
+
* Uses cloud provider abstraction to discover resources in a provider-agnostic way.
|
|
49
|
+
*
|
|
50
|
+
* @param {Object} appDefinition - Application definition
|
|
51
|
+
* @returns {Promise<Object>} Discovered cloud resources
|
|
52
|
+
*/
|
|
53
|
+
async function gatherDiscoveredResources(appDefinition) {
|
|
54
|
+
if (!shouldRunDiscovery(appDefinition)) {
|
|
55
|
+
console.log('⚙️ Skipping cloud resource discovery (not required for this configuration)');
|
|
56
|
+
return {};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log('🔍 Running cloud resource discovery...');
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
// Get cloud provider (defaults to AWS, can be overridden via env var)
|
|
63
|
+
const providerName = process.env.CLOUD_PROVIDER || appDefinition.provider || 'aws';
|
|
64
|
+
const region = process.env.AWS_REGION || 'us-east-1';
|
|
65
|
+
|
|
66
|
+
console.log(` Provider: ${providerName}`);
|
|
67
|
+
console.log(` Region: ${region}`);
|
|
68
|
+
|
|
69
|
+
// Create provider adapter
|
|
70
|
+
const provider = CloudProviderFactory.create(providerName, region);
|
|
71
|
+
|
|
72
|
+
// Create domain discovery services with provider
|
|
73
|
+
const vpcDiscovery = new VpcDiscovery(provider);
|
|
74
|
+
const kmsDiscovery = new KmsDiscovery(provider);
|
|
75
|
+
const auroraDiscovery = new AuroraDiscovery(provider);
|
|
76
|
+
const ssmDiscovery = new SsmDiscovery(provider);
|
|
77
|
+
|
|
78
|
+
// Build discovery configuration
|
|
79
|
+
const stage = process.env.SLS_STAGE || 'dev';
|
|
80
|
+
const config = {
|
|
81
|
+
serviceName: appDefinition.name || 'create-frigg-app',
|
|
82
|
+
stage,
|
|
83
|
+
vpcId: appDefinition.vpc?.vpcId,
|
|
84
|
+
databaseId: appDefinition.database?.postgres?.clusterId ||
|
|
85
|
+
appDefinition.database?.postgres?.instanceId,
|
|
86
|
+
keyAlias: appDefinition.encryption?.keyAlias,
|
|
87
|
+
includeSecrets: true,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Run discoveries in parallel for better performance
|
|
91
|
+
const [vpcResources, kmsResources, dbResources, ssmResources] =
|
|
92
|
+
await Promise.all([
|
|
93
|
+
appDefinition.vpc?.enable ? vpcDiscovery.discover(config) : Promise.resolve({}),
|
|
94
|
+
appDefinition.encryption?.fieldLevelEncryptionMethod === 'kms'
|
|
95
|
+
? kmsDiscovery.discover(config)
|
|
96
|
+
: Promise.resolve({}),
|
|
97
|
+
appDefinition.database?.postgres?.enable
|
|
98
|
+
? auroraDiscovery.discover(config)
|
|
99
|
+
: Promise.resolve({}),
|
|
100
|
+
appDefinition.ssm?.enable
|
|
101
|
+
? ssmDiscovery.discover(config)
|
|
102
|
+
: Promise.resolve({}),
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
// Aggregate results
|
|
106
|
+
const discoveredResources = {
|
|
107
|
+
...vpcResources,
|
|
108
|
+
...kmsResources,
|
|
109
|
+
...dbResources,
|
|
110
|
+
...ssmResources,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
console.log('✅ Cloud resource discovery completed successfully!');
|
|
114
|
+
|
|
115
|
+
return discoveredResources;
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error('❌ Cloud resource discovery failed:', error.message);
|
|
118
|
+
console.error('Stack:', error.stack);
|
|
119
|
+
|
|
120
|
+
// Don't fail the build - return empty resources and let validation handle it
|
|
121
|
+
console.warn(
|
|
122
|
+
'⚠️ Continuing with empty discovered resources. This may cause deployment issues if resources are required.'
|
|
123
|
+
);
|
|
124
|
+
return {};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
module.exports = {
|
|
129
|
+
shouldRunDiscovery,
|
|
130
|
+
gatherDiscoveredResources,
|
|
131
|
+
};
|
|
132
|
+
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Resource Discovery Service
|
|
3
|
+
*
|
|
4
|
+
* Tests orchestration of cloud resource discovery
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { shouldRunDiscovery, gatherDiscoveredResources } = require('./resource-discovery');
|
|
8
|
+
|
|
9
|
+
// Mock the provider factory and discovery classes
|
|
10
|
+
jest.mock('./providers/provider-factory');
|
|
11
|
+
jest.mock('../networking/vpc-discovery');
|
|
12
|
+
jest.mock('../security/kms-discovery');
|
|
13
|
+
jest.mock('../database/aurora-discovery');
|
|
14
|
+
jest.mock('../parameters/ssm-discovery');
|
|
15
|
+
|
|
16
|
+
const { CloudProviderFactory } = require('./providers/provider-factory');
|
|
17
|
+
const { VpcDiscovery } = require('../networking/vpc-discovery');
|
|
18
|
+
const { KmsDiscovery } = require('../security/kms-discovery');
|
|
19
|
+
const { AuroraDiscovery } = require('../database/aurora-discovery');
|
|
20
|
+
const { SsmDiscovery } = require('../parameters/ssm-discovery');
|
|
21
|
+
|
|
22
|
+
describe('Resource Discovery', () => {
|
|
23
|
+
let mockProvider;
|
|
24
|
+
let mockVpcDiscovery;
|
|
25
|
+
let mockKmsDiscovery;
|
|
26
|
+
let mockAuroraDiscovery;
|
|
27
|
+
let mockSsmDiscovery;
|
|
28
|
+
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
// Reset environment
|
|
31
|
+
delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
|
|
32
|
+
delete process.env.CLOUD_PROVIDER;
|
|
33
|
+
delete process.env.AWS_REGION;
|
|
34
|
+
|
|
35
|
+
// Create mock provider
|
|
36
|
+
mockProvider = {
|
|
37
|
+
getName: jest.fn().mockReturnValue('aws'),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Create mock discoveries with default responses
|
|
41
|
+
mockVpcDiscovery = {
|
|
42
|
+
discover: jest.fn().mockResolvedValue({
|
|
43
|
+
defaultVpcId: 'vpc-123',
|
|
44
|
+
privateSubnetId1: 'subnet-1',
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
mockKmsDiscovery = {
|
|
49
|
+
discover: jest.fn().mockResolvedValue({
|
|
50
|
+
kmsKeyId: 'arn:aws:kms:us-east-1:123:key/abc',
|
|
51
|
+
}),
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
mockAuroraDiscovery = {
|
|
55
|
+
discover: jest.fn().mockResolvedValue({
|
|
56
|
+
auroraClusterEndpoint: 'db.example.com',
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
mockSsmDiscovery = {
|
|
61
|
+
discover: jest.fn().mockResolvedValue({
|
|
62
|
+
parameters: [],
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Mock factory and discovery constructors
|
|
67
|
+
CloudProviderFactory.create = jest.fn().mockReturnValue(mockProvider);
|
|
68
|
+
VpcDiscovery.mockImplementation(() => mockVpcDiscovery);
|
|
69
|
+
KmsDiscovery.mockImplementation(() => mockKmsDiscovery);
|
|
70
|
+
AuroraDiscovery.mockImplementation(() => mockAuroraDiscovery);
|
|
71
|
+
SsmDiscovery.mockImplementation(() => mockSsmDiscovery);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('shouldRunDiscovery()', () => {
|
|
75
|
+
it('should return false when FRIGG_SKIP_AWS_DISCOVERY is true', () => {
|
|
76
|
+
process.env.FRIGG_SKIP_AWS_DISCOVERY = 'true';
|
|
77
|
+
|
|
78
|
+
const result = shouldRunDiscovery({ vpc: { enable: true } });
|
|
79
|
+
|
|
80
|
+
expect(result).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should return true when VPC is enabled', () => {
|
|
84
|
+
const result = shouldRunDiscovery({ vpc: { enable: true } });
|
|
85
|
+
|
|
86
|
+
expect(result).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should return true when KMS encryption is enabled', () => {
|
|
90
|
+
const result = shouldRunDiscovery({
|
|
91
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
expect(result).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should return true when SSM is enabled', () => {
|
|
98
|
+
const result = shouldRunDiscovery({ ssm: { enable: true } });
|
|
99
|
+
|
|
100
|
+
expect(result).toBe(true);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should return true when Postgres database is enabled', () => {
|
|
104
|
+
const result = shouldRunDiscovery({
|
|
105
|
+
database: { postgres: { enable: true } },
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
expect(result).toBe(true);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should return false when no features require discovery', () => {
|
|
112
|
+
const result = shouldRunDiscovery({
|
|
113
|
+
vpc: { enable: false },
|
|
114
|
+
encryption: { fieldLevelEncryptionMethod: 'aes' },
|
|
115
|
+
ssm: { enable: false },
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(result).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should return false for empty app definition', () => {
|
|
122
|
+
const result = shouldRunDiscovery({});
|
|
123
|
+
|
|
124
|
+
expect(result).toBe(false);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe('gatherDiscoveredResources()', () => {
|
|
129
|
+
it('should skip discovery when not needed', async () => {
|
|
130
|
+
const appDefinition = {
|
|
131
|
+
vpc: { enable: false },
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const result = await gatherDiscoveredResources(appDefinition);
|
|
135
|
+
|
|
136
|
+
expect(result).toEqual({});
|
|
137
|
+
expect(CloudProviderFactory.create).not.toHaveBeenCalled();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should create AWS provider by default', async () => {
|
|
141
|
+
const appDefinition = {
|
|
142
|
+
vpc: { enable: true },
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
await gatherDiscoveredResources(appDefinition);
|
|
146
|
+
|
|
147
|
+
expect(CloudProviderFactory.create).toHaveBeenCalledWith('aws', 'us-east-1');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should respect CLOUD_PROVIDER environment variable', async () => {
|
|
151
|
+
process.env.CLOUD_PROVIDER = 'gcp';
|
|
152
|
+
process.env.AWS_REGION = 'us-central1';
|
|
153
|
+
|
|
154
|
+
const appDefinition = {
|
|
155
|
+
vpc: { enable: true },
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
await gatherDiscoveredResources(appDefinition);
|
|
159
|
+
|
|
160
|
+
expect(CloudProviderFactory.create).toHaveBeenCalledWith('gcp', 'us-central1');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should respect AWS_REGION environment variable', async () => {
|
|
164
|
+
process.env.AWS_REGION = 'eu-west-1';
|
|
165
|
+
|
|
166
|
+
const appDefinition = {
|
|
167
|
+
vpc: { enable: true },
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
await gatherDiscoveredResources(appDefinition);
|
|
171
|
+
|
|
172
|
+
expect(CloudProviderFactory.create).toHaveBeenCalledWith('aws', 'eu-west-1');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should create discovery services with provider', async () => {
|
|
176
|
+
const appDefinition = {
|
|
177
|
+
vpc: { enable: true },
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
await gatherDiscoveredResources(appDefinition);
|
|
181
|
+
|
|
182
|
+
expect(VpcDiscovery).toHaveBeenCalledWith(mockProvider);
|
|
183
|
+
expect(KmsDiscovery).toHaveBeenCalledWith(mockProvider);
|
|
184
|
+
expect(AuroraDiscovery).toHaveBeenCalledWith(mockProvider);
|
|
185
|
+
expect(SsmDiscovery).toHaveBeenCalledWith(mockProvider);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should run VPC discovery when enabled', async () => {
|
|
189
|
+
const appDefinition = {
|
|
190
|
+
name: 'test-app',
|
|
191
|
+
vpc: { enable: true },
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
await gatherDiscoveredResources(appDefinition);
|
|
195
|
+
|
|
196
|
+
expect(mockVpcDiscovery.discover).toHaveBeenCalledWith(
|
|
197
|
+
expect.objectContaining({
|
|
198
|
+
serviceName: 'test-app',
|
|
199
|
+
})
|
|
200
|
+
);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should skip VPC discovery when disabled', async () => {
|
|
204
|
+
const appDefinition = {
|
|
205
|
+
vpc: { enable: false },
|
|
206
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
await gatherDiscoveredResources(appDefinition);
|
|
210
|
+
|
|
211
|
+
expect(mockVpcDiscovery.discover).not.toHaveBeenCalled();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should run KMS discovery when encryption is kms', async () => {
|
|
215
|
+
const appDefinition = {
|
|
216
|
+
name: 'test-app',
|
|
217
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
await gatherDiscoveredResources(appDefinition);
|
|
221
|
+
|
|
222
|
+
expect(mockKmsDiscovery.discover).toHaveBeenCalled();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should skip KMS discovery when encryption is not kms', async () => {
|
|
226
|
+
const appDefinition = {
|
|
227
|
+
encryption: { fieldLevelEncryptionMethod: 'aes' },
|
|
228
|
+
vpc: { enable: true },
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
await gatherDiscoveredResources(appDefinition);
|
|
232
|
+
|
|
233
|
+
expect(mockKmsDiscovery.discover).not.toHaveBeenCalled();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('should run database discovery when postgres is enabled', async () => {
|
|
237
|
+
const appDefinition = {
|
|
238
|
+
database: { postgres: { enable: true } },
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
await gatherDiscoveredResources(appDefinition);
|
|
242
|
+
|
|
243
|
+
expect(mockAuroraDiscovery.discover).toHaveBeenCalled();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('should skip database discovery when postgres is disabled', async () => {
|
|
247
|
+
const appDefinition = {
|
|
248
|
+
database: { postgres: { enable: false } },
|
|
249
|
+
vpc: { enable: true },
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
await gatherDiscoveredResources(appDefinition);
|
|
253
|
+
|
|
254
|
+
expect(mockAuroraDiscovery.discover).not.toHaveBeenCalled();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should run SSM discovery when enabled', async () => {
|
|
258
|
+
const appDefinition = {
|
|
259
|
+
ssm: { enable: true },
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
await gatherDiscoveredResources(appDefinition);
|
|
263
|
+
|
|
264
|
+
expect(mockSsmDiscovery.discover).toHaveBeenCalled();
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should aggregate results from all discoveries', async () => {
|
|
268
|
+
mockVpcDiscovery.discover.mockResolvedValue({
|
|
269
|
+
defaultVpcId: 'vpc-123',
|
|
270
|
+
privateSubnetId1: 'subnet-1',
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
mockKmsDiscovery.discover.mockResolvedValue({
|
|
274
|
+
kmsKeyId: 'arn:aws:kms:key/abc',
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
mockAuroraDiscovery.discover.mockResolvedValue({
|
|
278
|
+
auroraClusterEndpoint: 'db.example.com',
|
|
279
|
+
auroraPort: 5432,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
mockSsmDiscovery.discover.mockResolvedValue({
|
|
283
|
+
parameters: ['param1'],
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
const appDefinition = {
|
|
287
|
+
vpc: { enable: true },
|
|
288
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
289
|
+
database: { postgres: { enable: true } },
|
|
290
|
+
ssm: { enable: true },
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const result = await gatherDiscoveredResources(appDefinition);
|
|
294
|
+
|
|
295
|
+
expect(result).toEqual({
|
|
296
|
+
defaultVpcId: 'vpc-123',
|
|
297
|
+
privateSubnetId1: 'subnet-1',
|
|
298
|
+
kmsKeyId: 'arn:aws:kms:key/abc',
|
|
299
|
+
auroraClusterEndpoint: 'db.example.com',
|
|
300
|
+
auroraPort: 5432,
|
|
301
|
+
parameters: ['param1'],
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('should run discoveries in parallel for performance', async () => {
|
|
306
|
+
const appDefinition = {
|
|
307
|
+
vpc: { enable: true },
|
|
308
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
309
|
+
database: { postgres: { enable: true } },
|
|
310
|
+
ssm: { enable: true },
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
await gatherDiscoveredResources(appDefinition);
|
|
314
|
+
|
|
315
|
+
// All should have been called (proving parallel execution)
|
|
316
|
+
expect(mockVpcDiscovery.discover).toHaveBeenCalled();
|
|
317
|
+
expect(mockKmsDiscovery.discover).toHaveBeenCalled();
|
|
318
|
+
expect(mockAuroraDiscovery.discover).toHaveBeenCalled();
|
|
319
|
+
expect(mockSsmDiscovery.discover).toHaveBeenCalled();
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('should handle discovery errors gracefully', async () => {
|
|
323
|
+
mockVpcDiscovery.discover.mockRejectedValue(new Error('VPC API Error'));
|
|
324
|
+
|
|
325
|
+
const appDefinition = {
|
|
326
|
+
vpc: { enable: true },
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
const result = await gatherDiscoveredResources(appDefinition);
|
|
330
|
+
|
|
331
|
+
// Should return empty object instead of throwing
|
|
332
|
+
expect(result).toEqual({});
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('should pass configuration to discoveries', async () => {
|
|
336
|
+
const appDefinition = {
|
|
337
|
+
name: 'my-service',
|
|
338
|
+
vpc: {
|
|
339
|
+
enable: true,
|
|
340
|
+
vpcId: 'vpc-custom',
|
|
341
|
+
},
|
|
342
|
+
database: {
|
|
343
|
+
postgres: {
|
|
344
|
+
enable: true,
|
|
345
|
+
clusterId: 'my-cluster',
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
encryption: {
|
|
349
|
+
fieldLevelEncryptionMethod: 'kms',
|
|
350
|
+
keyAlias: 'alias/my-key',
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
process.env.SLS_STAGE = 'production';
|
|
355
|
+
|
|
356
|
+
await gatherDiscoveredResources(appDefinition);
|
|
357
|
+
|
|
358
|
+
expect(mockVpcDiscovery.discover).toHaveBeenCalledWith(
|
|
359
|
+
expect.objectContaining({
|
|
360
|
+
serviceName: 'my-service',
|
|
361
|
+
stage: 'production',
|
|
362
|
+
vpcId: 'vpc-custom',
|
|
363
|
+
})
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
expect(mockAuroraDiscovery.discover).toHaveBeenCalledWith(
|
|
367
|
+
expect.objectContaining({
|
|
368
|
+
databaseId: 'my-cluster',
|
|
369
|
+
})
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
expect(mockKmsDiscovery.discover).toHaveBeenCalledWith(
|
|
373
|
+
expect.objectContaining({
|
|
374
|
+
keyAlias: 'alias/my-key',
|
|
375
|
+
})
|
|
376
|
+
);
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it('should default stage to dev', async () => {
|
|
380
|
+
delete process.env.SLS_STAGE;
|
|
381
|
+
|
|
382
|
+
const appDefinition = {
|
|
383
|
+
vpc: { enable: true },
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
await gatherDiscoveredResources(appDefinition);
|
|
387
|
+
|
|
388
|
+
expect(mockVpcDiscovery.discover).toHaveBeenCalledWith(
|
|
389
|
+
expect.objectContaining({
|
|
390
|
+
stage: 'dev',
|
|
391
|
+
})
|
|
392
|
+
);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it('should include secrets in SSM discovery by default', async () => {
|
|
396
|
+
const appDefinition = {
|
|
397
|
+
ssm: { enable: true },
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
await gatherDiscoveredResources(appDefinition);
|
|
401
|
+
|
|
402
|
+
expect(mockSsmDiscovery.discover).toHaveBeenCalledWith(
|
|
403
|
+
expect.objectContaining({
|
|
404
|
+
includeSecrets: true,
|
|
405
|
+
})
|
|
406
|
+
);
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
|
|
@@ -32,7 +32,7 @@ function createBaseDefinition(
|
|
|
32
32
|
const region = process.env.AWS_REGION || 'us-east-1';
|
|
33
33
|
|
|
34
34
|
// Package config for handlers that skip esbuild (need node_modules dependencies)
|
|
35
|
-
//
|
|
35
|
+
// Include backend src/ and index.js since handlers load the app definition
|
|
36
36
|
const skipEsbuildPackageConfig = {
|
|
37
37
|
exclude: [
|
|
38
38
|
// Exclude Prisma (provided via Lambda Layer)
|
|
@@ -53,8 +53,7 @@ function createBaseDefinition(
|
|
|
53
53
|
'node_modules/prettier/**',
|
|
54
54
|
'node_modules/eslint/**',
|
|
55
55
|
|
|
56
|
-
// Exclude
|
|
57
|
-
'src/**',
|
|
56
|
+
// Exclude test files and layers (but keep src/ - needed for app definition)
|
|
58
57
|
'test/**',
|
|
59
58
|
'layers/**',
|
|
60
59
|
'coverage/**',
|