@adobe/helix-deploy 13.3.2 → 13.4.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/CHANGELOG.md +15 -0
- package/README.md +3 -0
- package/package.json +1 -1
- package/src/deploy/AWSConfig.js +55 -2
- package/src/deploy/AWSDeployer.js +19 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
# [13.4.0](https://github.com/adobe/helix-deploy/compare/v13.3.3...v13.4.0) (2026-03-09)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* add VPC subnet and security group properties to AWSConfig ([#897](https://github.com/adobe/helix-deploy/issues/897)) ([15cd4fe](https://github.com/adobe/helix-deploy/commit/15cd4feb74b1a9b9e238c6a821d342bf2a1db8d4))
|
|
7
|
+
* add VpcConfig to functionConfig and cross-field validation ([#897](https://github.com/adobe/helix-deploy/issues/897)) ([54599c7](https://github.com/adobe/helix-deploy/commit/54599c7b88a2ddf5898a33227c4cd9ee43a528fc))
|
|
8
|
+
|
|
9
|
+
## [13.3.3](https://github.com/adobe/helix-deploy/compare/v13.3.2...v13.3.3) (2026-03-05)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* README update for aws-ephemeral-storage option ([#894](https://github.com/adobe/helix-deploy/issues/894)) ([8b11fa9](https://github.com/adobe/helix-deploy/commit/8b11fa94c16aeae9b9be1ce62fd0b2bbba91063d))
|
|
15
|
+
|
|
1
16
|
## [13.3.2](https://github.com/adobe/helix-deploy/compare/v13.3.1...v13.3.2) (2026-03-03)
|
|
2
17
|
|
|
3
18
|
|
package/README.md
CHANGED
|
@@ -145,6 +145,9 @@ AWS Deployment Options
|
|
|
145
145
|
--aws-extra-permissions A list of additional invoke permissions to add to the lambda function in the form <SourceARN>@<Principal>. Optionally, you can use <SourceARN>@<Principal>:<Alias> if you want to scope the permission to a specific alias. [array]
|
|
146
146
|
--aws-tags A list of additional tags to attach to the lambda function in the form key=value. To remove a tag, use key= (i.e. without a value). [array]
|
|
147
147
|
--aws-handler Set custom lambda Handler. For example, set if an AWS layer provides another function entry point. [string]
|
|
148
|
+
--aws-ephemeral-storage Size of the Lambda /tmp ephemeral storage in MB (512-10240). [number] [default: 512]
|
|
149
|
+
--aws-vpc-subnet-ids List of VPC subnet IDs to attach the Lambda function to. [array]
|
|
150
|
+
--aws-vpc-security-group-ids List of VPC security group IDs to attach the Lambda function to. [array]
|
|
148
151
|
|
|
149
152
|
Google Deployment Options
|
|
150
153
|
--google-project-id the Google Cloud project to deploy to. Optional when the key file is a JSON file [string] [default: ""]
|
package/package.json
CHANGED
package/src/deploy/AWSConfig.js
CHANGED
|
@@ -13,6 +13,29 @@
|
|
|
13
13
|
// eslint-disable-next-line no-template-curly-in-string
|
|
14
14
|
const DEFAULT_LAMBDA_FORMAT = '${packageName}--${baseName}';
|
|
15
15
|
|
|
16
|
+
// VPC IDs are validated more strictly than other array options (e.g. --aws-layers)
|
|
17
|
+
// because VPC misconfiguration silently breaks Lambda networking with no obvious
|
|
18
|
+
// symptoms, and ${env.VAR} substitution failures are a common CI footgun.
|
|
19
|
+
function validateVpcIds(value, flagName, prefix) {
|
|
20
|
+
if (!Array.isArray(value)) {
|
|
21
|
+
throw new Error(`${flagName} must be an array`);
|
|
22
|
+
}
|
|
23
|
+
for (const id of value) {
|
|
24
|
+
if (typeof id !== 'string') {
|
|
25
|
+
throw new Error(`${flagName} contains a non-string element: ${JSON.stringify(id)}`);
|
|
26
|
+
}
|
|
27
|
+
if (id === '') {
|
|
28
|
+
throw new Error(`${flagName} contains an empty string - check that the corresponding environment variable is set`);
|
|
29
|
+
}
|
|
30
|
+
if (/\$\{env\./.test(id)) {
|
|
31
|
+
throw new Error(`${flagName} contains an unresolved \${env.} reference: "${id}"`);
|
|
32
|
+
}
|
|
33
|
+
if (!id.startsWith(prefix)) {
|
|
34
|
+
throw new Error(`invalid ${flagName} entry "${id}" - must start with "${prefix}"`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
16
39
|
export default class AWSConfig {
|
|
17
40
|
constructor() {
|
|
18
41
|
Object.assign(this, {
|
|
@@ -38,6 +61,8 @@ export default class AWSConfig {
|
|
|
38
61
|
tags: undefined,
|
|
39
62
|
handler: undefined,
|
|
40
63
|
ephemeralStorage: undefined,
|
|
64
|
+
vpcSubnetIds: undefined,
|
|
65
|
+
vpcSecurityGroupIds: undefined,
|
|
41
66
|
});
|
|
42
67
|
}
|
|
43
68
|
|
|
@@ -64,7 +89,9 @@ export default class AWSConfig {
|
|
|
64
89
|
.withAWSExtraPermissions(argv.awsExtraPermissions)
|
|
65
90
|
.withAWSTags(argv.awsTags)
|
|
66
91
|
.withAWSHandler(argv.awsHandler)
|
|
67
|
-
.withAWSEphemeralStorage(argv.awsEphemeralStorage)
|
|
92
|
+
.withAWSEphemeralStorage(argv.awsEphemeralStorage)
|
|
93
|
+
.withAWSVpcSubnetIds(argv.awsVpcSubnetIds)
|
|
94
|
+
.withAWSVpcSecurityGroupIds(argv.awsVpcSecurityGroupIds);
|
|
68
95
|
}
|
|
69
96
|
|
|
70
97
|
withAWSRegion(value) {
|
|
@@ -189,6 +216,22 @@ export default class AWSConfig {
|
|
|
189
216
|
return this;
|
|
190
217
|
}
|
|
191
218
|
|
|
219
|
+
withAWSVpcSubnetIds(value) {
|
|
220
|
+
if (value !== undefined) {
|
|
221
|
+
validateVpcIds(value, 'aws-vpc-subnet-ids', 'subnet-');
|
|
222
|
+
this.vpcSubnetIds = value;
|
|
223
|
+
}
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
withAWSVpcSecurityGroupIds(value) {
|
|
228
|
+
if (value !== undefined) {
|
|
229
|
+
validateVpcIds(value, 'aws-vpc-security-group-ids', 'sg-');
|
|
230
|
+
this.vpcSecurityGroupIds = value;
|
|
231
|
+
}
|
|
232
|
+
return this;
|
|
233
|
+
}
|
|
234
|
+
|
|
192
235
|
static yarg(yargs) {
|
|
193
236
|
return yargs
|
|
194
237
|
.group(['aws-region', 'aws-api', 'aws-role', 'aws-cleanup-buckets', 'aws-cleanup-integrations',
|
|
@@ -196,7 +239,7 @@ export default class AWSConfig {
|
|
|
196
239
|
'aws-lambda-format', 'aws-parameter-manager', 'aws-deploy-template', 'aws-arch', 'aws-update-secrets',
|
|
197
240
|
'aws-deploy-bucket', 'aws-identity-source', 'aws-log-format', 'aws-layers',
|
|
198
241
|
'aws-tracing-mode', 'aws-extra-permissions', 'aws-tags', 'aws-handler',
|
|
199
|
-
'aws-ephemeral-storage'], 'AWS Deployment Options')
|
|
242
|
+
'aws-ephemeral-storage', 'aws-vpc-subnet-ids', 'aws-vpc-security-group-ids'], 'AWS Deployment Options')
|
|
200
243
|
.option('aws-region', {
|
|
201
244
|
description: 'the AWS region to deploy lambda functions to',
|
|
202
245
|
type: 'string',
|
|
@@ -304,6 +347,16 @@ export default class AWSConfig {
|
|
|
304
347
|
.option('aws-ephemeral-storage', {
|
|
305
348
|
description: 'Size of the Lambda /tmp ephemeral storage in MB (512-10240). Default is 512 MB.',
|
|
306
349
|
type: 'number',
|
|
350
|
+
})
|
|
351
|
+
.option('aws-vpc-subnet-ids', {
|
|
352
|
+
description: 'List of VPC subnet IDs to attach the Lambda function to.',
|
|
353
|
+
type: 'string',
|
|
354
|
+
array: true,
|
|
355
|
+
})
|
|
356
|
+
.option('aws-vpc-security-group-ids', {
|
|
357
|
+
description: 'List of VPC security group IDs to attach the Lambda function to.',
|
|
358
|
+
type: 'string',
|
|
359
|
+
array: true,
|
|
307
360
|
});
|
|
308
361
|
}
|
|
309
362
|
}
|
|
@@ -150,6 +150,12 @@ export default class AWSDeployer extends BaseDeployer {
|
|
|
150
150
|
if (req.length) {
|
|
151
151
|
throw Error(`AWS target needs ${req.join(' and ')}`);
|
|
152
152
|
}
|
|
153
|
+
if (this._cfg.vpcSubnetIds !== undefined && this._cfg.vpcSecurityGroupIds === undefined) {
|
|
154
|
+
throw Error('--aws-vpc-security-group-ids is required when --aws-vpc-subnet-ids is set');
|
|
155
|
+
}
|
|
156
|
+
if (this._cfg.vpcSecurityGroupIds !== undefined && this._cfg.vpcSubnetIds === undefined) {
|
|
157
|
+
throw Error('--aws-vpc-subnet-ids is required when --aws-vpc-security-group-ids is set');
|
|
158
|
+
}
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
async init() {
|
|
@@ -255,6 +261,13 @@ export default class AWSDeployer extends BaseDeployer {
|
|
|
255
261
|
TracingConfig: this._cfg.tracingMode ? { Mode: this._cfg.tracingMode } : undefined,
|
|
256
262
|
EphemeralStorage: this._cfg.ephemeralStorage
|
|
257
263
|
? { Size: this._cfg.ephemeralStorage } : undefined,
|
|
264
|
+
// uses strict !== undefined (not falsy check) because [] is a valid value (VPC detach)
|
|
265
|
+
VpcConfig: this._cfg.vpcSubnetIds !== undefined && this._cfg.vpcSecurityGroupIds !== undefined
|
|
266
|
+
? {
|
|
267
|
+
SubnetIds: this._cfg.vpcSubnetIds,
|
|
268
|
+
SecurityGroupIds: this._cfg.vpcSecurityGroupIds,
|
|
269
|
+
}
|
|
270
|
+
: undefined,
|
|
258
271
|
};
|
|
259
272
|
|
|
260
273
|
// add additional tags which are not empty
|
|
@@ -275,6 +288,12 @@ export default class AWSDeployer extends BaseDeployer {
|
|
|
275
288
|
|
|
276
289
|
this.log.info(`--: using lambda role "${this._cfg.role}"`);
|
|
277
290
|
|
|
291
|
+
if (Array.isArray(this._cfg.vpcSubnetIds) && this._cfg.vpcSubnetIds.length === 0) {
|
|
292
|
+
this.log.warn(chalk`{yellow warn:} VPC detach requested - Lambda will lose VPC network access`);
|
|
293
|
+
} else if (this._cfg.vpcSubnetIds?.length) {
|
|
294
|
+
this.log.info(chalk`--: VPC config set - ensure Lambda role has {yellow ec2:CreateNetworkInterface}, {yellow ec2:DescribeNetworkInterfaces}, {yellow ec2:DeleteNetworkInterface} permissions`);
|
|
295
|
+
}
|
|
296
|
+
|
|
278
297
|
// check if function already exists
|
|
279
298
|
let baseARN;
|
|
280
299
|
try {
|