@adobe/helix-deploy 13.3.3 → 13.4.1

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 CHANGED
@@ -1,3 +1,18 @@
1
+ ## [13.4.1](https://github.com/adobe/helix-deploy/compare/v13.4.0...v13.4.1) (2026-03-10)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **deps:** update external fixes ([#899](https://github.com/adobe/helix-deploy/issues/899)) ([62964cb](https://github.com/adobe/helix-deploy/commit/62964cb20690f7e970304d9aa1c2f0a4b39ebacf))
7
+
8
+ # [13.4.0](https://github.com/adobe/helix-deploy/compare/v13.3.3...v13.4.0) (2026-03-09)
9
+
10
+
11
+ ### Features
12
+
13
+ * 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))
14
+ * 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))
15
+
1
16
  ## [13.3.3](https://github.com/adobe/helix-deploy/compare/v13.3.2...v13.3.3) (2026-03-05)
2
17
 
3
18
 
package/README.md CHANGED
@@ -146,6 +146,8 @@ AWS Deployment Options
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
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]
149
151
 
150
152
  Google Deployment Options
151
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/helix-deploy",
3
- "version": "13.3.3",
3
+ "version": "13.4.1",
4
4
  "description": "Library and Commandline Tools to build and deploy OpenWhisk Actions",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/adobe/helix-deploy#readme",
@@ -39,12 +39,12 @@
39
39
  "dependencies": {
40
40
  "@adobe/fetch": "4.2.3",
41
41
  "@adobe/helix-shared-process-queue": "3.1.5",
42
- "@aws-sdk/client-apigatewayv2": "3.991.0",
43
- "@aws-sdk/client-lambda": "3.991.0",
44
- "@aws-sdk/client-s3": "3.991.0",
45
- "@aws-sdk/client-secrets-manager": "3.991.0",
46
- "@aws-sdk/client-ssm": "3.991.0",
47
- "@aws-sdk/client-sts": "3.991.0",
42
+ "@aws-sdk/client-apigatewayv2": "3.996.0",
43
+ "@aws-sdk/client-lambda": "3.996.0",
44
+ "@aws-sdk/client-s3": "3.996.0",
45
+ "@aws-sdk/client-secrets-manager": "3.996.0",
46
+ "@aws-sdk/client-ssm": "3.996.0",
47
+ "@aws-sdk/client-sts": "3.996.0",
48
48
  "@google-cloud/functions": "4.2.1",
49
49
  "@google-cloud/secret-manager": "6.1.1",
50
50
  "@google-cloud/storage": "7.19.0",
@@ -54,7 +54,7 @@
54
54
  "esbuild": "0.27.3",
55
55
  "escalade": "3.2.0",
56
56
  "fs-extra": "11.3.3",
57
- "isomorphic-git": "1.37.1",
57
+ "isomorphic-git": "1.37.2",
58
58
  "openwhisk": "3.21.8",
59
59
  "semver": "7.7.4",
60
60
  "yargs": "18.0.0"
@@ -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 {