From 0becdacdeaf5216b3a36150085652779ac6d4b29 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Wed, 10 May 2023 14:37:35 -0400 Subject: [PATCH] fix(NODE-5262): AWS Lambda metadata detection logic is too permissive (#3683) --- src/cmap/handshake/client_metadata.ts | 3 +- .../mongodb-handshake.prose.test.ts | 5 ++ .../cmap/handshake/client_metadata.test.ts | 65 ++++++++++++++----- 3 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/cmap/handshake/client_metadata.ts b/src/cmap/handshake/client_metadata.ts index ab66328ca5a..fb1ba40b14e 100644 --- a/src/cmap/handshake/client_metadata.ts +++ b/src/cmap/handshake/client_metadata.ts @@ -176,7 +176,8 @@ export function getFAASEnv(): Map | null { VERCEL_REGION = '' } = process.env; - const isAWSFaaS = AWS_EXECUTION_ENV.length > 0 || AWS_LAMBDA_RUNTIME_API.length > 0; + const isAWSFaaS = + AWS_EXECUTION_ENV.startsWith('AWS_Lambda_') || AWS_LAMBDA_RUNTIME_API.length > 0; const isAzureFaaS = FUNCTIONS_WORKER_RUNTIME.length > 0; const isGCPFaaS = K_SERVICE.length > 0 || FUNCTION_NAME.length > 0; const isVercelFaaS = VERCEL.length > 0; diff --git a/test/integration/mongodb-handshake/mongodb-handshake.prose.test.ts b/test/integration/mongodb-handshake/mongodb-handshake.prose.test.ts index cb20e9ac097..fefb10b86aa 100644 --- a/test/integration/mongodb-handshake/mongodb-handshake.prose.test.ts +++ b/test/integration/mongodb-handshake/mongodb-handshake.prose.test.ts @@ -71,6 +71,11 @@ describe('Handshake Prose Tests', function () { ['AWS_EXECUTION_ENV', 'AWS_Lambda_java8'], ['AWS_LAMBDA_FUNCTION_MEMORY_SIZE', 'big'] ] + }, + { + expectedProvider: undefined, + context: '8. Invalid - AWS_EXECUTION_ENV does not start with "AWS_Lambda_"', + env: [['AWS_EXECUTION_ENV', 'EC2']] } ]; diff --git a/test/unit/cmap/handshake/client_metadata.test.ts b/test/unit/cmap/handshake/client_metadata.test.ts index 98eef138e60..590a27a7d10 100644 --- a/test/unit/cmap/handshake/client_metadata.test.ts +++ b/test/unit/cmap/handshake/client_metadata.test.ts @@ -37,8 +37,7 @@ describe('client metadata module', () => { }); describe('getFAASEnv()', function () { - const tests: Array<[string, string]> = [ - ['AWS_EXECUTION_ENV', 'aws.lambda'], + const tests: Array<[envVariable: string, provider: string]> = [ ['AWS_LAMBDA_RUNTIME_API', 'aws.lambda'], ['FUNCTIONS_WORKER_RUNTIME', 'azure.func'], ['K_SERVICE', 'gcp.func'], @@ -46,9 +45,9 @@ describe('client metadata module', () => { ['VERCEL', 'vercel'] ]; for (const [envVariable, provider] of tests) { - context(`when ${envVariable} is in the environment`, () => { + context(`when ${envVariable} is set to a non-empty string`, () => { before(() => { - process.env[envVariable] = 'non empty string'; + process.env[envVariable] = 'non_empty_string'; }); after(() => { delete process.env[envVariable]; @@ -56,9 +55,45 @@ describe('client metadata module', () => { it('determines the correct provider', () => { expect(getFAASEnv()?.get('name')).to.equal(provider); }); + + context(`when ${envVariable} is set to an empty string`, () => { + before(() => { + process.env[envVariable] = ''; + }); + after(() => { + delete process.env[envVariable]; + }); + it('returns null', () => { + expect(getFAASEnv()).to.be.null; + }); + }); }); } + context('when AWS_EXECUTION_ENV starts with "AWS_Lambda_"', () => { + before(() => { + process.env.AWS_EXECUTION_ENV = 'AWS_Lambda_correctStartString'; + }); + after(() => { + delete process.env.AWS_EXECUTION_ENV; + }); + it('indicates the runtime is aws lambda', () => { + expect(getFAASEnv()?.get('name')).to.equal('aws.lambda'); + }); + }); + + context('when AWS_EXECUTION_ENV does not start with "AWS_Lambda_"', () => { + before(() => { + process.env.AWS_EXECUTION_ENV = 'AWS_LambdaIncorrectStartString'; + }); + after(() => { + delete process.env.AWS_EXECUTION_ENV; + }); + it('returns null', () => { + expect(getFAASEnv()).to.be.null; + }); + }); + context('when there is no FAAS provider data in the env', () => { it('returns null', () => { expect(getFAASEnv()).to.be.null; @@ -69,9 +104,9 @@ describe('client metadata module', () => { context('unrelated environments', () => { before(() => { // aws - process.env.AWS_EXECUTION_ENV = 'non-empty-string'; + process.env.AWS_EXECUTION_ENV = 'AWS_Lambda_non_empty_string'; // azure - process.env.FUNCTIONS_WORKER_RUNTIME = 'non-empty-string'; + process.env.FUNCTIONS_WORKER_RUNTIME = 'non_empty_string'; }); after(() => { delete process.env.AWS_EXECUTION_ENV; @@ -85,10 +120,10 @@ describe('client metadata module', () => { context('vercel and aws which share env variables', () => { before(() => { // vercel - process.env.VERCEL = 'non-empty-string'; + process.env.VERCEL = 'non_empty_string'; // aws - process.env.AWS_EXECUTION_ENV = 'non-empty-string'; - process.env.AWS_LAMBDA_RUNTIME_API = 'non-empty-string'; + process.env.AWS_EXECUTION_ENV = 'non_empty_string'; + process.env.AWS_LAMBDA_RUNTIME_API = 'non_empty_string'; }); after(() => { delete process.env.VERCEL; @@ -383,7 +418,7 @@ describe('client metadata module', () => { aws: [ { context: 'no additional metadata', - env: [['AWS_EXECUTION_ENV', 'non-empty string']], + env: [['AWS_EXECUTION_ENV', 'AWS_Lambda_non_empty_string']], outcome: { name: 'aws.lambda' } @@ -391,7 +426,7 @@ describe('client metadata module', () => { { context: 'AWS_REGION provided', env: [ - ['AWS_EXECUTION_ENV', 'non-empty string'], + ['AWS_EXECUTION_ENV', 'AWS_Lambda_non_empty_string'], ['AWS_REGION', 'non-null'] ], outcome: { @@ -402,7 +437,7 @@ describe('client metadata module', () => { { context: 'AWS_LAMBDA_FUNCTION_MEMORY_SIZE provided', env: [ - ['AWS_EXECUTION_ENV', 'non-empty string'], + ['AWS_EXECUTION_ENV', 'AWS_Lambda_non_empty_string'], ['AWS_LAMBDA_FUNCTION_MEMORY_SIZE', '3'] ], outcome: { @@ -506,7 +541,7 @@ describe('client metadata module', () => { context('when a numeric FAAS env variable is not numerically parsable', () => { before(() => { - process.env.AWS_EXECUTION_ENV = 'non-empty-string'; + process.env.AWS_EXECUTION_ENV = 'AWS_Lambda_non_empty_string'; process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '123not numeric'; }); @@ -525,7 +560,7 @@ describe('client metadata module', () => { context('when faas region is too large', () => { beforeEach('1. Omit fields from `env` except `env.name`.', () => { sinon.stub(process, 'env').get(() => ({ - AWS_EXECUTION_ENV: 'iLoveJavaScript', + AWS_EXECUTION_ENV: 'AWS_Lambda_iLoveJavaScript', AWS_REGION: 'a'.repeat(512) })); }); @@ -542,7 +577,7 @@ describe('client metadata module', () => { context('release too large', () => { beforeEach('2. Omit fields from `os` except `os.type`.', () => { sinon.stub(process, 'env').get(() => ({ - AWS_EXECUTION_ENV: 'iLoveJavaScript', + AWS_EXECUTION_ENV: 'AWS_Lambda_iLoveJavaScript', AWS_REGION: 'abc' })); sinon.stub(os, 'release').returns('a'.repeat(512));