diff --git a/src/template/aws-package-params.js b/src/template/aws-package-params.js new file mode 100644 index 00000000..7357d801 --- /dev/null +++ b/src/template/aws-package-params.js @@ -0,0 +1,55 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +const { promisify } = require('util'); + +async function getAWSSecrets(functionName) { + // delay the import so that other runtimes do not have to care + // eslint-disable-next-line import/no-unresolved, global-require,import/no-extraneous-dependencies + const AWS = require('aws-sdk'); + + AWS.config.update({ + region: process.env.AWS_REGION, + logger: console, + }); + + const ssm = new AWS.SSM(); + ssm.getParametersByPath = promisify(ssm.getParametersByPath.bind(ssm)); + + let params = []; + let nextToken; + try { + do { + const opts = { + Path: `/helix-deploy/${functionName.replace(/--.*/, '')}/`, + WithDecryption: true, + }; + if (nextToken) { + opts.NextToken = nextToken; + } + // eslint-disable-next-line no-await-in-loop + const res = await ssm.getParametersByPath(opts); + nextToken = res.NextToken; + params = params.concat(res.Parameters); + } while (nextToken); + } catch (e) { + // eslint-disable-next-line no-console + console.error('unable to get parameters', e); + } + + return params.reduce((p, param) => { + // eslint-disable-next-line no-param-reassign + p[param.Name.replace(/.*\//, '')] = param.Value; + return p; + }, {}); +} + +module.exports = getAWSSecrets; diff --git a/src/template/index.js b/src/template/index.js index 104594f5..5d9ce883 100644 --- a/src/template/index.js +++ b/src/template/index.js @@ -11,10 +11,10 @@ */ /* eslint-disable no-param-reassign, no-underscore-dangle, import/no-extraneous-dependencies */ const querystring = require('querystring'); -const { promisify } = require('util'); const { Request } = require('@adobe/helix-fetch'); const { epsagon } = require('@adobe/helix-epsagon'); const { isBinary, ensureUTF8Charset } = require('./utils.js'); +const getAWSSecrets = require('./aws-package-params.js'); const { AWSResolver, OpenwhiskResolver, @@ -52,45 +52,6 @@ async function getGoogleSecrets(functionName, projectID) { } } -async function getAWSSecrets(functionName) { - // delay the import so that other runtimes do not have to care - // eslint-disable-next-line import/no-unresolved, global-require - const AWS = require('aws-sdk'); - - AWS.config.update({ - region: process.env.AWS_REGION, - }); - - const ssm = new AWS.SSM(); - ssm.getParametersByPath = promisify(ssm.getParametersByPath.bind(ssm)); - - let params = []; - let nextToken; - try { - do { - const opts = { - Path: `/helix-deploy/${functionName.replace(/--.*/, '')}/`, - WithDecryption: true, - }; - if (nextToken) { - opts.NextToken = nextToken; - } - // eslint-disable-next-line no-await-in-loop - const res = await ssm.getParametersByPath(opts); - nextToken = res.NextToken; - params = params.concat(res.Parameters); - } while (nextToken); - } catch (e) { - // eslint-disable-next-line no-console - console.error('unable to get parameters', e); - } - - return params.reduce((p, param) => { - p[param.Name.replace(/.*\//, '')] = param.Value; - return p; - }, {}); -} - // Azure async function azure(context, req) { context.log('JavaScript HTTP trigger function processed a request.'); @@ -310,6 +271,17 @@ async function lambda(event, context) { headers: event.headers, body: event.isBase64Encoded ? Buffer.from(event.body, 'base64') : event.body, }); + + // parse ARN + // arn:partition:service:region:account-id:resource-type:resource-id + // eg: arn:aws:lambda:us-east-1:118435662149:function:dump:4_2_1 + const [/* 'arn' */, /* 'aws' */, /* 'lambda' */, + region, + accountId, /* 'function' */, + functionName, + functionAlias, + ] = context.invokedFunctionArn.split(':'); + const con = { resolver: new AWSResolver(event), pathInfo: { @@ -317,11 +289,12 @@ async function lambda(event, context) { }, runtime: { name: 'aws-lambda', - region: process.env.AWS_REGION, + region, + accountId, }, func: { - name: context.functionName, - version: context.functionVersion, + name: functionName, + version: (functionAlias || '').replace(/_/g, '.'), app: event.requestContext.apiId, }, invocation: { diff --git a/test/wrapper.test.js b/test/wrapper.test.js index 04f273d3..d26b3e25 100644 --- a/test/wrapper.test.js +++ b/test/wrapper.test.js @@ -31,6 +31,7 @@ describe('Wrapper tests for Azure', () => { }); const context = { + // eslint-disable-next-line no-console log: console.log, executionContext: { functionName: 'simple-package--simple-name_1_45_0', @@ -45,3 +46,72 @@ describe('Wrapper tests for Azure', () => { assert.equal(context.res.status, 200, context.res.body); }); }); + +describe('Wrapper tests for AWS', () => { + it('context.func', async () => { + const { lambda } = proxyquire('../src/template/index.js', { + './main.js': { + main: (request, context) => { + assert.deepEqual(context.func, { + name: 'dump', + version: '4.3.1', + app: 'kvvyh7ikcb', + }); + return new Response('ok'); + }, + }, + './aws-package-params.js': () => ({}), + }); + + const event = { + version: '2.0', + routeKey: 'ANY /dump', + rawPath: '/dump', + rawQueryString: '', + headers: { + accept: '*/*', + 'content-length': '0', + host: 'kvvyh7ikcb.execute-api.us-east-1.amazonaws.com', + 'user-agent': 'curl/7.64.1', + 'x-amzn-trace-id': 'Root=1-603df0bb-05e846307a6221f72030fe68', + 'x-forwarded-for': '210.153.232.90', + 'x-forwarded-port': '443', + 'x-forwarded-proto': 'https', + }, + requestContext: { + accountId: '118435662149', + apiId: 'kvvyh7ikcb', + domainName: 'kvvyh7ikcb.execute-api.us-east-1.amazonaws.com', + domainPrefix: 'kvvyh7ikcb', + http: { + method: 'GET', + path: '/dump', + protocol: 'HTTP/1.1', + sourceIp: '210.153.232.90', + userAgent: 'curl/7.64.1', + }, + requestId: 'bjKNYhHcoAMEJIw=', + routeKey: 'ANY /dump', + stage: '$default', + time: '02/Mar/2021:08:00:59 +0000', + timeEpoch: 1614672059918, + }, + isBase64Encoded: false, + }; + + const context = { + getRemainingTimeInMillis: () => 30000, + callbackWaitsForEmptyEventLoop: true, + functionVersion: '$LATEST', + functionName: 'dump', + memoryLimitInMB: '128', + logGroupName: '/aws/lambda/dump', + logStreamName: '2021/03/02/[$LATEST]89b58159f93949f787eb8de043937bbb', + invokedFunctionArn: 'arn:aws:lambda:us-east-1:118435662149:function:dump:4_3_1', + awsRequestId: '535f0399-9c90-4042-880e-620cfec6af55', + }; + + const res = await lambda(event, context); + assert.equal(res.statusCode, 200); + }); +});