@friggframework/devtools 2.0.0-next.35 → 2.0.0-next.36
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/deploy-command/index.js +150 -12
- package/infrastructure/env-validator.js +77 -0
- package/infrastructure/iam-generator.js +110 -2
- package/infrastructure/iam-policy-basic.json +5 -1
- package/infrastructure/iam-policy-full.json +5 -1
- package/infrastructure/serverless-template.js +66 -23
- package/package.json +6 -6
|
@@ -1,26 +1,155 @@
|
|
|
1
|
-
const { spawn
|
|
1
|
+
const { spawn } = require('child_process');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
// Configuration constants
|
|
6
|
+
const PATHS = {
|
|
7
|
+
APP_DEFINITION: 'index.js',
|
|
8
|
+
INFRASTRUCTURE: 'infrastructure.js'
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const COMMANDS = {
|
|
12
|
+
SERVERLESS: 'serverless'
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Constructs filtered environment variables for serverless deployment
|
|
17
|
+
* @param {string[]} appDefinedVariables - Array of environment variable names from app definition
|
|
18
|
+
* @returns {Object} Filtered environment variables object
|
|
19
|
+
*/
|
|
20
|
+
function buildFilteredEnvironment(appDefinedVariables) {
|
|
21
|
+
return {
|
|
22
|
+
// Essential system variables needed to run serverless
|
|
23
|
+
PATH: process.env.PATH,
|
|
24
|
+
HOME: process.env.HOME,
|
|
25
|
+
USER: process.env.USER,
|
|
26
|
+
|
|
27
|
+
// AWS credentials and configuration (all AWS_ prefixed variables)
|
|
28
|
+
...Object.fromEntries(
|
|
29
|
+
Object.entries(process.env).filter(([key]) =>
|
|
30
|
+
key.startsWith('AWS_')
|
|
31
|
+
)
|
|
32
|
+
),
|
|
33
|
+
|
|
34
|
+
// App-defined environment variables
|
|
35
|
+
...Object.fromEntries(
|
|
36
|
+
appDefinedVariables
|
|
37
|
+
.map((key) => [key, process.env[key]])
|
|
38
|
+
.filter(([_, value]) => value !== undefined)
|
|
39
|
+
),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Loads and parses the app definition from index.js
|
|
45
|
+
* @returns {Object|null} App definition object or null if not found
|
|
46
|
+
*/
|
|
47
|
+
function loadAppDefinition() {
|
|
48
|
+
const appDefPath = path.join(process.cwd(), PATHS.APP_DEFINITION);
|
|
49
|
+
|
|
50
|
+
if (!fs.existsSync(appDefPath)) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const { Definition } = require(appDefPath);
|
|
56
|
+
return Definition;
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.warn('Could not load appDefinition environment config:', error.message);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Extracts environment variable names from app definition
|
|
65
|
+
* @param {Object} appDefinition - App definition object
|
|
66
|
+
* @returns {string[]} Array of environment variable names
|
|
67
|
+
*/
|
|
68
|
+
function extractEnvironmentVariables(appDefinition) {
|
|
69
|
+
if (!appDefinition?.environment) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log('🔧 Loading environment configuration from appDefinition...');
|
|
74
|
+
|
|
75
|
+
const appDefinedVariables = Object.keys(appDefinition.environment).filter(
|
|
76
|
+
(key) => appDefinition.environment[key] === true
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
console.log(` Found ${appDefinedVariables.length} environment variables: ${appDefinedVariables.join(', ')}`);
|
|
80
|
+
return appDefinedVariables;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Handles environment validation warnings
|
|
85
|
+
* @param {Object} validation - Validation result object
|
|
86
|
+
* @param {Object} options - Deploy command options
|
|
87
|
+
*/
|
|
88
|
+
function handleValidationWarnings(validation, options) {
|
|
89
|
+
if (validation.missing.length === 0 || options.skipEnvValidation) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
6
92
|
|
|
7
|
-
|
|
8
|
-
console.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
93
|
+
console.warn(`⚠️ Warning: Missing ${validation.missing.length} environment variables: ${validation.missing.join(', ')}`);
|
|
94
|
+
console.warn(' These variables are optional and deployment will continue');
|
|
95
|
+
console.warn(' Run with --skip-env-validation to bypass this check');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Validates environment variables and builds filtered environment
|
|
100
|
+
* @param {Object} appDefinition - App definition object
|
|
101
|
+
* @param {Object} options - Deploy command options
|
|
102
|
+
* @returns {Object} Filtered environment variables
|
|
103
|
+
*/
|
|
104
|
+
function validateAndBuildEnvironment(appDefinition, options) {
|
|
105
|
+
if (!appDefinition) {
|
|
106
|
+
return buildFilteredEnvironment([]);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const appDefinedVariables = extractEnvironmentVariables(appDefinition);
|
|
110
|
+
|
|
111
|
+
// Try to use the env-validator if available
|
|
112
|
+
try {
|
|
113
|
+
const { validateEnvironmentVariables } = require('@friggframework/devtools/infrastructure/env-validator');
|
|
114
|
+
const validation = validateEnvironmentVariables(appDefinition);
|
|
115
|
+
|
|
116
|
+
handleValidationWarnings(validation, options);
|
|
117
|
+
return buildFilteredEnvironment(appDefinedVariables);
|
|
118
|
+
|
|
119
|
+
} catch (validatorError) {
|
|
120
|
+
// Validator not available, do basic validation
|
|
121
|
+
const missingVariables = appDefinedVariables.filter((variable) => !process.env[variable]);
|
|
122
|
+
|
|
123
|
+
if (missingVariables.length > 0) {
|
|
124
|
+
console.warn(`⚠️ Warning: Missing ${missingVariables.length} environment variables: ${missingVariables.join(', ')}`);
|
|
125
|
+
console.warn(' These variables are optional and deployment will continue');
|
|
126
|
+
console.warn(' Set them in your CI/CD environment or .env file if needed');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return buildFilteredEnvironment(appDefinedVariables);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Executes the serverless deployment command
|
|
135
|
+
* @param {Object} environment - Environment variables to pass to serverless
|
|
136
|
+
* @param {Object} options - Deploy command options
|
|
137
|
+
*/
|
|
138
|
+
function executeServerlessDeployment(environment, options) {
|
|
139
|
+
console.log('🚀 Deploying serverless application...');
|
|
140
|
+
|
|
12
141
|
const serverlessArgs = [
|
|
13
142
|
'deploy',
|
|
14
143
|
'--config',
|
|
15
|
-
|
|
144
|
+
PATHS.INFRASTRUCTURE,
|
|
16
145
|
'--stage',
|
|
17
146
|
options.stage,
|
|
18
147
|
];
|
|
19
148
|
|
|
20
|
-
const childProcess = spawn(
|
|
21
|
-
cwd:
|
|
149
|
+
const childProcess = spawn(COMMANDS.SERVERLESS, serverlessArgs, {
|
|
150
|
+
cwd: path.resolve(process.cwd()),
|
|
22
151
|
stdio: 'inherit',
|
|
23
|
-
env:
|
|
152
|
+
env: environment,
|
|
24
153
|
});
|
|
25
154
|
|
|
26
155
|
childProcess.on('error', (error) => {
|
|
@@ -34,4 +163,13 @@ async function deployCommand(options) {
|
|
|
34
163
|
});
|
|
35
164
|
}
|
|
36
165
|
|
|
166
|
+
async function deployCommand(options) {
|
|
167
|
+
console.log('Deploying the serverless application...');
|
|
168
|
+
|
|
169
|
+
const appDefinition = loadAppDefinition();
|
|
170
|
+
const environment = validateAndBuildEnvironment(appDefinition, options);
|
|
171
|
+
|
|
172
|
+
executeServerlessDeployment(environment, options);
|
|
173
|
+
}
|
|
174
|
+
|
|
37
175
|
module.exports = { deployCommand };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment variable validator for Frigg applications
|
|
3
|
+
* Validates that required environment variables are present based on appDefinition
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Validate environment variables against appDefinition
|
|
8
|
+
* @param {Object} AppDefinition - Application definition with environment config
|
|
9
|
+
* @returns {Object} Validation results with valid, missing, and warnings arrays
|
|
10
|
+
*/
|
|
11
|
+
const validateEnvironmentVariables = (AppDefinition) => {
|
|
12
|
+
const results = {
|
|
13
|
+
valid: [],
|
|
14
|
+
missing: [],
|
|
15
|
+
warnings: [],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
if (!AppDefinition.environment) {
|
|
19
|
+
return results;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.log('🔍 Validating environment variables...');
|
|
23
|
+
|
|
24
|
+
for (const [key, value] of Object.entries(AppDefinition.environment)) {
|
|
25
|
+
if (value === true) {
|
|
26
|
+
if (process.env[key]) {
|
|
27
|
+
results.valid.push(key);
|
|
28
|
+
} else {
|
|
29
|
+
results.missing.push(key);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Special handling for certain variables
|
|
35
|
+
if (results.missing.includes('NODE_ENV')) {
|
|
36
|
+
results.warnings.push('NODE_ENV not set, defaulting to "production"');
|
|
37
|
+
// Remove from missing since it has a default
|
|
38
|
+
results.missing = results.missing.filter((v) => v !== 'NODE_ENV');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Report results
|
|
42
|
+
if (results.valid.length > 0) {
|
|
43
|
+
console.log(
|
|
44
|
+
` ✅ Valid: ${results.valid.length} environment variables found`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (results.missing.length > 0) {
|
|
49
|
+
console.log(` ⚠️ Missing: ${results.missing.join(', ')}`);
|
|
50
|
+
results.warnings.push(
|
|
51
|
+
`Missing ${results.missing.length} environment variables. These should be set in your CI/CD environment or .env file`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (results.warnings.length > 0) {
|
|
56
|
+
results.warnings.forEach((warning) => {
|
|
57
|
+
console.log(` ⚠️ ${warning}`);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return results;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Check if all required environment variables are present
|
|
66
|
+
* @param {Object} AppDefinition - Application definition
|
|
67
|
+
* @returns {boolean} True if all required variables are present
|
|
68
|
+
*/
|
|
69
|
+
const hasAllRequiredEnvVars = (AppDefinition) => {
|
|
70
|
+
const results = validateEnvironmentVariables(AppDefinition);
|
|
71
|
+
return results.missing.length === 0;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
module.exports = {
|
|
75
|
+
validateEnvironmentVariables,
|
|
76
|
+
hasAllRequiredEnvVars,
|
|
77
|
+
};
|
|
@@ -180,6 +180,114 @@ function generateIAMCloudFormation(appDefinition, options = {}) {
|
|
|
180
180
|
};
|
|
181
181
|
|
|
182
182
|
// Add Core Deployment Policy (always needed)
|
|
183
|
+
const coreActions = [
|
|
184
|
+
// CloudFormation permissions
|
|
185
|
+
'cloudformation:CreateStack',
|
|
186
|
+
'cloudformation:UpdateStack',
|
|
187
|
+
'cloudformation:DeleteStack',
|
|
188
|
+
'cloudformation:DescribeStacks',
|
|
189
|
+
'cloudformation:DescribeStackEvents',
|
|
190
|
+
'cloudformation:DescribeStackResources',
|
|
191
|
+
'cloudformation:DescribeStackResource',
|
|
192
|
+
'cloudformation:ListStackResources',
|
|
193
|
+
'cloudformation:GetTemplate',
|
|
194
|
+
'cloudformation:DescribeChangeSet',
|
|
195
|
+
'cloudformation:CreateChangeSet',
|
|
196
|
+
'cloudformation:DeleteChangeSet',
|
|
197
|
+
'cloudformation:ExecuteChangeSet',
|
|
198
|
+
'cloudformation:ValidateTemplate',
|
|
199
|
+
|
|
200
|
+
// Lambda permissions
|
|
201
|
+
'lambda:CreateFunction',
|
|
202
|
+
'lambda:UpdateFunctionCode',
|
|
203
|
+
'lambda:UpdateFunctionConfiguration',
|
|
204
|
+
'lambda:DeleteFunction',
|
|
205
|
+
'lambda:GetFunction',
|
|
206
|
+
'lambda:ListFunctions',
|
|
207
|
+
'lambda:PublishVersion',
|
|
208
|
+
'lambda:CreateAlias',
|
|
209
|
+
'lambda:UpdateAlias',
|
|
210
|
+
'lambda:DeleteAlias',
|
|
211
|
+
'lambda:GetAlias',
|
|
212
|
+
'lambda:AddPermission',
|
|
213
|
+
'lambda:RemovePermission',
|
|
214
|
+
'lambda:GetPolicy',
|
|
215
|
+
'lambda:PutProvisionedConcurrencyConfig',
|
|
216
|
+
'lambda:DeleteProvisionedConcurrencyConfig',
|
|
217
|
+
'lambda:PutConcurrency',
|
|
218
|
+
'lambda:DeleteConcurrency',
|
|
219
|
+
'lambda:TagResource',
|
|
220
|
+
'lambda:UntagResource',
|
|
221
|
+
'lambda:ListVersionsByFunction',
|
|
222
|
+
|
|
223
|
+
// IAM permissions
|
|
224
|
+
'iam:CreateRole',
|
|
225
|
+
'iam:DeleteRole',
|
|
226
|
+
'iam:GetRole',
|
|
227
|
+
'iam:PassRole',
|
|
228
|
+
'iam:PutRolePolicy',
|
|
229
|
+
'iam:DeleteRolePolicy',
|
|
230
|
+
'iam:GetRolePolicy',
|
|
231
|
+
'iam:AttachRolePolicy',
|
|
232
|
+
'iam:DetachRolePolicy',
|
|
233
|
+
'iam:TagRole',
|
|
234
|
+
'iam:UntagRole',
|
|
235
|
+
'iam:ListPolicyVersions',
|
|
236
|
+
|
|
237
|
+
// S3 permissions
|
|
238
|
+
's3:CreateBucket',
|
|
239
|
+
's3:PutObject',
|
|
240
|
+
's3:GetObject',
|
|
241
|
+
's3:DeleteObject',
|
|
242
|
+
's3:PutBucketPolicy',
|
|
243
|
+
's3:PutBucketVersioning',
|
|
244
|
+
's3:PutBucketPublicAccessBlock',
|
|
245
|
+
's3:GetBucketLocation',
|
|
246
|
+
's3:ListBucket',
|
|
247
|
+
|
|
248
|
+
// SQS permissions
|
|
249
|
+
'sqs:CreateQueue',
|
|
250
|
+
'sqs:DeleteQueue',
|
|
251
|
+
'sqs:GetQueueAttributes',
|
|
252
|
+
'sqs:SetQueueAttributes',
|
|
253
|
+
'sqs:GetQueueUrl',
|
|
254
|
+
'sqs:TagQueue',
|
|
255
|
+
'sqs:UntagQueue',
|
|
256
|
+
|
|
257
|
+
// SNS permissions
|
|
258
|
+
'sns:CreateTopic',
|
|
259
|
+
'sns:DeleteTopic',
|
|
260
|
+
'sns:GetTopicAttributes',
|
|
261
|
+
'sns:SetTopicAttributes',
|
|
262
|
+
'sns:Subscribe',
|
|
263
|
+
'sns:Unsubscribe',
|
|
264
|
+
'sns:ListSubscriptionsByTopic',
|
|
265
|
+
'sns:TagResource',
|
|
266
|
+
'sns:UntagResource',
|
|
267
|
+
|
|
268
|
+
// CloudWatch and Logs permissions
|
|
269
|
+
'cloudwatch:PutMetricAlarm',
|
|
270
|
+
'cloudwatch:DeleteAlarms',
|
|
271
|
+
'cloudwatch:DescribeAlarms',
|
|
272
|
+
'logs:CreateLogGroup',
|
|
273
|
+
'logs:CreateLogStream',
|
|
274
|
+
'logs:DeleteLogGroup',
|
|
275
|
+
'logs:DescribeLogGroups',
|
|
276
|
+
'logs:DescribeLogStreams',
|
|
277
|
+
'logs:FilterLogEvents',
|
|
278
|
+
'logs:PutLogEvents',
|
|
279
|
+
'logs:PutRetentionPolicy',
|
|
280
|
+
|
|
281
|
+
// API Gateway permissions
|
|
282
|
+
'apigateway:POST',
|
|
283
|
+
'apigateway:PUT',
|
|
284
|
+
'apigateway:DELETE',
|
|
285
|
+
'apigateway:GET',
|
|
286
|
+
'apigateway:PATCH',
|
|
287
|
+
'apigateway:TagResource',
|
|
288
|
+
'apigateway:UntagResource',
|
|
289
|
+
];
|
|
290
|
+
|
|
183
291
|
const coreStatements = [
|
|
184
292
|
{
|
|
185
293
|
Sid: 'CloudFormationFriggStacks',
|
|
@@ -374,6 +482,8 @@ function generateIAMCloudFormation(appDefinition, options = {}) {
|
|
|
374
482
|
'apigateway:DELETE',
|
|
375
483
|
'apigateway:GET',
|
|
376
484
|
'apigateway:PATCH',
|
|
485
|
+
'apigateway:TagResource',
|
|
486
|
+
'apigateway:UntagResource',
|
|
377
487
|
],
|
|
378
488
|
Resource: [
|
|
379
489
|
'arn:aws:apigateway:*::/restapis',
|
|
@@ -397,8 +507,6 @@ function generateIAMCloudFormation(appDefinition, options = {}) {
|
|
|
397
507
|
'arn:aws:apigateway:*::/apis/*',
|
|
398
508
|
'arn:aws:apigateway:*::/apis/*/stages',
|
|
399
509
|
'arn:aws:apigateway:*::/apis/*/stages/*',
|
|
400
|
-
'arn:aws:apigateway:*::/apis/*/mappings',
|
|
401
|
-
'arn:aws:apigateway:*::/apis/*/mappings/*',
|
|
402
510
|
'arn:aws:apigateway:*::/domainnames',
|
|
403
511
|
'arn:aws:apigateway:*::/domainnames/*',
|
|
404
512
|
'arn:aws:apigateway:*::/domainnames/*/apimappings',
|
|
@@ -199,13 +199,17 @@
|
|
|
199
199
|
"apigateway:PUT",
|
|
200
200
|
"apigateway:DELETE",
|
|
201
201
|
"apigateway:GET",
|
|
202
|
-
"apigateway:PATCH"
|
|
202
|
+
"apigateway:PATCH",
|
|
203
|
+
"apigateway:TagResource",
|
|
204
|
+
"apigateway:UntagResource"
|
|
203
205
|
],
|
|
204
206
|
"Resource": [
|
|
205
207
|
"arn:aws:apigateway:*::/restapis",
|
|
206
208
|
"arn:aws:apigateway:*::/restapis/*",
|
|
207
209
|
"arn:aws:apigateway:*::/apis",
|
|
208
210
|
"arn:aws:apigateway:*::/apis/*",
|
|
211
|
+
"arn:aws:apigateway:*::/apis/*/stages",
|
|
212
|
+
"arn:aws:apigateway:*::/apis/*/stages/*",
|
|
209
213
|
"arn:aws:apigateway:*::/domainnames",
|
|
210
214
|
"arn:aws:apigateway:*::/domainnames/*"
|
|
211
215
|
]
|
|
@@ -199,13 +199,17 @@
|
|
|
199
199
|
"apigateway:PUT",
|
|
200
200
|
"apigateway:DELETE",
|
|
201
201
|
"apigateway:GET",
|
|
202
|
-
"apigateway:PATCH"
|
|
202
|
+
"apigateway:PATCH",
|
|
203
|
+
"apigateway:TagResource",
|
|
204
|
+
"apigateway:UntagResource"
|
|
203
205
|
],
|
|
204
206
|
"Resource": [
|
|
205
207
|
"arn:aws:apigateway:*::/restapis",
|
|
206
208
|
"arn:aws:apigateway:*::/restapis/*",
|
|
207
209
|
"arn:aws:apigateway:*::/apis",
|
|
208
210
|
"arn:aws:apigateway:*::/apis/*",
|
|
211
|
+
"arn:aws:apigateway:*::/apis/*/stages",
|
|
212
|
+
"arn:aws:apigateway:*::/apis/*/stages/*",
|
|
209
213
|
"arn:aws:apigateway:*::/domainnames",
|
|
210
214
|
"arn:aws:apigateway:*::/domainnames/*"
|
|
211
215
|
]
|
|
@@ -16,6 +16,68 @@ const shouldRunDiscovery = (AppDefinition) => {
|
|
|
16
16
|
);
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Extract environment variables from AppDefinition
|
|
21
|
+
* @param {Object} AppDefinition - Application definition
|
|
22
|
+
* @returns {Object} Environment variables to set in serverless
|
|
23
|
+
*/
|
|
24
|
+
const getAppEnvironmentVars = (AppDefinition) => {
|
|
25
|
+
const envVars = {};
|
|
26
|
+
|
|
27
|
+
// AWS Lambda reserved environment variables that cannot be set (from official AWS docs)
|
|
28
|
+
const reservedVars = new Set([
|
|
29
|
+
'_HANDLER',
|
|
30
|
+
'_X_AMZN_TRACE_ID',
|
|
31
|
+
'AWS_DEFAULT_REGION',
|
|
32
|
+
'AWS_EXECUTION_ENV',
|
|
33
|
+
'AWS_REGION',
|
|
34
|
+
'AWS_LAMBDA_FUNCTION_NAME',
|
|
35
|
+
'AWS_LAMBDA_FUNCTION_MEMORY_SIZE',
|
|
36
|
+
'AWS_LAMBDA_FUNCTION_VERSION',
|
|
37
|
+
'AWS_LAMBDA_INITIALIZATION_TYPE',
|
|
38
|
+
'AWS_LAMBDA_LOG_GROUP_NAME',
|
|
39
|
+
'AWS_LAMBDA_LOG_STREAM_NAME',
|
|
40
|
+
'AWS_ACCESS_KEY',
|
|
41
|
+
'AWS_ACCESS_KEY_ID',
|
|
42
|
+
'AWS_SECRET_ACCESS_KEY',
|
|
43
|
+
'AWS_SESSION_TOKEN',
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
if (AppDefinition.environment) {
|
|
47
|
+
console.log('📋 Loading environment variables from appDefinition...');
|
|
48
|
+
const envKeys = [];
|
|
49
|
+
const skippedKeys = [];
|
|
50
|
+
|
|
51
|
+
for (const [key, value] of Object.entries(AppDefinition.environment)) {
|
|
52
|
+
if (value === true) {
|
|
53
|
+
if (reservedVars.has(key)) {
|
|
54
|
+
skippedKeys.push(key);
|
|
55
|
+
} else {
|
|
56
|
+
envVars[key] = `\${env:${key}, ''}`;
|
|
57
|
+
envKeys.push(key);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (envKeys.length > 0) {
|
|
63
|
+
console.log(
|
|
64
|
+
` Found ${
|
|
65
|
+
envKeys.length
|
|
66
|
+
} environment variables: ${envKeys.join(', ')}`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if (skippedKeys.length > 0) {
|
|
70
|
+
console.log(
|
|
71
|
+
` ⚠️ Skipped ${
|
|
72
|
+
skippedKeys.length
|
|
73
|
+
} reserved AWS Lambda variables: ${skippedKeys.join(', ')}`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return envVars;
|
|
79
|
+
};
|
|
80
|
+
|
|
19
81
|
/**
|
|
20
82
|
* Find the actual path to node_modules directory
|
|
21
83
|
* Tries multiple methods to locate node_modules:
|
|
@@ -555,17 +617,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
555
617
|
}
|
|
556
618
|
}
|
|
557
619
|
|
|
558
|
-
//
|
|
559
|
-
|
|
560
|
-
const envKeys = Object.keys(process.env || {}).sort();
|
|
561
|
-
console.log(
|
|
562
|
-
'Frigg deploy env keys (sample):',
|
|
563
|
-
envKeys.slice(0, 30),
|
|
564
|
-
`... total=${envKeys.length}`
|
|
565
|
-
);
|
|
566
|
-
} catch (e) {
|
|
567
|
-
console.log('Frigg deploy env keys: <unavailable>', e?.message);
|
|
568
|
-
}
|
|
620
|
+
// Get environment variables from appDefinition
|
|
621
|
+
const appEnvironmentVars = getAppEnvironmentVars(AppDefinition);
|
|
569
622
|
|
|
570
623
|
const definition = {
|
|
571
624
|
frameworkVersion: '>=3.17.0',
|
|
@@ -588,18 +641,8 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
588
641
|
environment: {
|
|
589
642
|
STAGE: '${opt:stage, "dev"}',
|
|
590
643
|
AWS_NODEJS_CONNECTION_REUSE_ENABLED: 1,
|
|
591
|
-
//
|
|
592
|
-
|
|
593
|
-
...Object.fromEntries(
|
|
594
|
-
Object.entries(process.env)
|
|
595
|
-
.filter(([key]) => key.startsWith('FRIGG__'))
|
|
596
|
-
.map(([key, value]) => [
|
|
597
|
-
key.replace('FRIGG__', ''),
|
|
598
|
-
value,
|
|
599
|
-
])
|
|
600
|
-
),
|
|
601
|
-
// Also include essential non-prefixed variables
|
|
602
|
-
...(process.env.NODE_ENV && { NODE_ENV: process.env.NODE_ENV }),
|
|
644
|
+
// Add environment variables from appDefinition
|
|
645
|
+
...appEnvironmentVars,
|
|
603
646
|
// Add discovered resources to environment if available
|
|
604
647
|
...(discoveredResources.defaultVpcId && {
|
|
605
648
|
AWS_DISCOVERY_VPC_ID: discoveredResources.defaultVpcId,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/devtools",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0-next.
|
|
4
|
+
"version": "2.0.0-next.36",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-ec2": "^3.835.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.835.0",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"@babel/eslint-parser": "^7.18.9",
|
|
10
10
|
"@babel/parser": "^7.25.3",
|
|
11
11
|
"@babel/traverse": "^7.25.3",
|
|
12
|
-
"@friggframework/schemas": "2.0.0-next.
|
|
13
|
-
"@friggframework/test": "2.0.0-next.
|
|
12
|
+
"@friggframework/schemas": "2.0.0-next.36",
|
|
13
|
+
"@friggframework/test": "2.0.0-next.36",
|
|
14
14
|
"@hapi/boom": "^10.0.1",
|
|
15
15
|
"@inquirer/prompts": "^5.3.8",
|
|
16
16
|
"axios": "^1.7.2",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"serverless-http": "^2.7.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@friggframework/eslint-config": "2.0.0-next.
|
|
36
|
-
"@friggframework/prettier-config": "2.0.0-next.
|
|
35
|
+
"@friggframework/eslint-config": "2.0.0-next.36",
|
|
36
|
+
"@friggframework/prettier-config": "2.0.0-next.36",
|
|
37
37
|
"prettier": "^2.7.1",
|
|
38
38
|
"serverless": "3.39.0",
|
|
39
39
|
"serverless-dotenv-plugin": "^6.0.0",
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"publishConfig": {
|
|
66
66
|
"access": "public"
|
|
67
67
|
},
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "6cca53cb3091d6bd11ae37f6c459679f1b5b19a6"
|
|
69
69
|
}
|