From 1db17bcb514cfebd8840a07174985a3259e0f2bc Mon Sep 17 00:00:00 2001 From: Simon Elder Date: Fri, 17 May 2019 13:42:04 +1000 Subject: [PATCH 1/6] Add authorization scopes with a cloudformation referenced authorizerid --- .../apiGateway/lib/method/authorization.js | 10 ++- .../apiGateway/lib/method/index.test.js | 73 ++++++++++++++++++- 2 files changed, 79 insertions(+), 4 deletions(-) diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/method/authorization.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/method/authorization.js index 03957b8e8..21ae109d0 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/method/authorization.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/method/authorization.js @@ -15,12 +15,18 @@ module.exports = { if (http.authorizer) { if (http.authorizer.type && http.authorizer.authorizerId) { - return { + const authReturn = { Properties: { AuthorizationType: http.authorizer.type, AuthorizerId: http.authorizer.authorizerId, }, }; + if (http.authorizer.type === 'COGNITO_USER_POOLS' + && http.authorizer.scopes + && http.authorizer.scopes.length) { + authReturn.Properties.AuthorizationScopes = http.authorizer.scopes; + } + return authReturn; } const authorizerLogicalId = this.provider.naming @@ -39,7 +45,7 @@ module.exports = { }, DependsOn: authorizerLogicalId, }; - if (http.authorizer.scopes) { + if (http.authorizer.scopes && http.authorizer.scopes.length) { cognitoReturn.Properties.AuthorizationScopes = http.authorizer.scopes; } return cognitoReturn; diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/method/index.test.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/method/index.test.js index 2ac2b2957..e6871ab9d 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/method/index.test.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/method/index.test.js @@ -489,7 +489,7 @@ describe('#compileMethods()', () => { }); }); - it('should set custom authorizer config with authorizeId', () => { + it('should set custom authorizer config with authorizerId', () => { awsCompileApigEvents.validated.events = [ { functionName: 'First', @@ -542,7 +542,7 @@ describe('#compileMethods()', () => { }); }); - it('should set authorizer config for a cognito user pool', () => { + it('should set authorizer config for a cognito user pool when given authorizer arn', () => { awsCompileApigEvents.validated.events = [ { functionName: 'First', @@ -583,6 +583,75 @@ describe('#compileMethods()', () => { }); }); + it('should set authorizer config for a cognito user pool when given authorizerId Ref', () => { + awsCompileApigEvents.validated.events = [ + { + functionName: 'First', + http: { + authorizer: { + name: 'authorizer', + type: 'COGNITO_USER_POOLS', + authorizerId: { Ref: 'CognitoAuthorizer' }, + scopes: ['myapp/read', 'myapp/write'], + }, + integration: 'AWS', + path: 'users/create', + method: 'post', + }, + }, + ]; + + return awsCompileApigEvents.compileMethods().then(() => { + expect( + awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate + .Resources.ApiGatewayMethodUsersCreatePost.Properties.AuthorizationType + ).to.equal('COGNITO_USER_POOLS'); + + expect( + awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate + .Resources.ApiGatewayMethodUsersCreatePost.Properties.AuthorizationScopes + ).to.contain('myapp/read'); + + expect( + awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate + .Resources.ApiGatewayMethodUsersCreatePost.Properties.AuthorizerId.Ref + ).to.equal('CognitoAuthorizer'); + + expect( + awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate + .Resources.ApiGatewayMethodUsersCreatePost.Properties + .Integration.RequestTemplates['application/json'] + ).to.not.match(/undefined/); + }); + }); + + it('should not scopes for a cognito user pool when given empty scopes array', () => { + awsCompileApigEvents.validated.events = [ + { + functionName: 'First', + http: { + authorizer: { + name: 'authorizer', + type: 'COGNITO_USER_POOLS', + authorizerId: { Ref: 'CognitoAuthorizer' }, + scopes: [], + }, + integration: 'AWS', + path: 'users/create', + method: 'post', + }, + }, + ]; + + return awsCompileApigEvents.compileMethods().then(() => { + expect( + awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate + .Resources.ApiGatewayMethodUsersCreatePost.Properties + ).to.not.have.property('AuthorizationScopes'); + }); + }); + + it('should set claims for a cognito user pool', () => { awsCompileApigEvents.validated.events = [ { From 834dc5a49a85ca468ddaff71c894971e32c9b08d Mon Sep 17 00:00:00 2001 From: Simon Elder Date: Fri, 17 May 2019 16:22:51 +1000 Subject: [PATCH 2/6] Update documentation example .... --- docs/providers/aws/events/apigateway.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/providers/aws/events/apigateway.md b/docs/providers/aws/events/apigateway.md index ad8ff969d..101c2c0ea 100644 --- a/docs/providers/aws/events/apigateway.md +++ b/docs/providers/aws/events/apigateway.md @@ -1355,6 +1355,8 @@ functions: type: COGNITO_USER_POOLS # TOKEN or REQUEST or COGNITO_USER_POOLS, same as AWS Cloudformation documentation authorizerId: Ref: ApiGatewayAuthorizer # or hard-code Authorizer ID + scopes: # Optional - List of Oauth2 scopes when type is COGNITO_USER_POOLS + - myapp/myscope deleteUser: ... From a04362017820829ac3c130e7526456b9393b095e Mon Sep 17 00:00:00 2001 From: Simon Elder Date: Fri, 17 May 2019 16:27:32 +1000 Subject: [PATCH 3/6] Fix typo .... --- docs/providers/aws/events/apigateway.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/providers/aws/events/apigateway.md b/docs/providers/aws/events/apigateway.md index 101c2c0ea..e37d30520 100644 --- a/docs/providers/aws/events/apigateway.md +++ b/docs/providers/aws/events/apigateway.md @@ -499,7 +499,7 @@ functions: - nickname ``` -### Using asyncronous integration +### Using asynchronous integration Use `async: true` when integrating a lambda function using [event invocation](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#SSS-Invoke-request-InvocationType). This lets API Gateway to return immediately with a 200 status code while the lambda continues running. If not othewise speficied integration type will be `AWS`. From 9bb787e1170a6caaf4fb197caa002a72e0dd2778 Mon Sep 17 00:00:00 2001 From: Simon Elder Date: Fri, 17 May 2019 16:30:55 +1000 Subject: [PATCH 4/6] Some more typos .... --- docs/providers/aws/events/apigateway.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/providers/aws/events/apigateway.md b/docs/providers/aws/events/apigateway.md index e37d30520..3e60adfe8 100644 --- a/docs/providers/aws/events/apigateway.md +++ b/docs/providers/aws/events/apigateway.md @@ -501,7 +501,7 @@ functions: ### Using asynchronous integration -Use `async: true` when integrating a lambda function using [event invocation](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#SSS-Invoke-request-InvocationType). This lets API Gateway to return immediately with a 200 status code while the lambda continues running. If not othewise speficied integration type will be `AWS`. +Use `async: true` when integrating a lambda function using [event invocation](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#SSS-Invoke-request-InvocationType). This lets API Gateway to return immediately with a 200 status code while the lambda continues running. If not otherwise specified integration type will be `AWS`. ```yml functions: @@ -868,7 +868,7 @@ If you want to spread a string into multiple lines, you can use the `>` or `|` s #### Pass Through Behavior API Gateway provides multiple ways to handle requests where the Content-Type header does not match any of the specified mapping templates. When this happens, the request payload will either be passed through the integration request *without transformation* or rejected with a `415 - Unsupported Media Type`, depending on the configuration. -You can define this behavior as follows (if not specified, a value of **NEVER** will be used): +You can define this behaviour as follows (if not specified, a value of **NEVER** will be used): ```yml functions: From 4edf46eaefe2d3689e5fbe79d4df1ee114ae375f Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Fri, 3 May 2019 13:32:06 +0200 Subject: [PATCH 5/6] Update required Node.js version / Add version check --- .travis.yml | 6 ------ VERSIONING.md | 4 ++++ bin/serverless | 15 +++++++++++++++ package.json | 2 +- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9982bc353..0e7d73b41 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,12 +8,6 @@ matrix: - secure: p9ka7mRzo/ecjnDh/dz19g0iVfQdvsGRAtg/4ONeiq75I2+oqHzu+VxUBA1Z2IQbpCEAMo21CarR3fg2I6MFUeazL0nEpqr1PoOAI8nPFeQlg/h+jLXsrPAkDcu2/b8ij7J5MXeLdZXUVqiPcGkr68x/tCMk/rwxftljQhvXPQfc7Lxm/m61ELnC7rLJulhxWZLNIq1hwQ9nh0GMKb4hm0KmPn8ksccVL+wyDikkgXCuvIujhTBjhNivAe4mG8mqnNsW1Ugh++SUe1ld27TtbH7wQj02SSG4Bxfwc3Gz0GFdAL1GyOkWI2WvrqP4a0KYTRUo+pUr9E+HZ1SNlxU5t6QWtmDiy5MKkxzgeTXmkKiJ98vMlF0ja5bpp46NjYarzDafqE8FozHzLtr+uAtqr6gRAgU1rWaG9BE3gKeW/f4B/2MfPI26b7SxuU1MwGVy0I76hb0Ujbgb3X8G4TYTGb6Nhoewc+RZExPwVhfrN8cJjo45masndv5tQAZMSRX/JUFjs4h/QMXNsn0A53GXgf6eIzUu15m+W8TJYFiKQeq9nMejzEE4sWMO3BFnkxueBGVCEurOc1GgdEnKxeqlp+psxHcJRlNCxC1HkUVOzfpkCr/Jy42vM8jQomAMv41Z9zWjOagVphWT25xNeSILfRt4yPku5wfW4CAxp+fl4KQ= include: # Linux tests - - os: linux - node_js: "4.4" - env: SLS_IGNORE_WARNING=* - - os: linux - node_js: "5.11" - env: SLS_IGNORE_WARNING=* - os: linux node_js: "6.2" env: SLS_IGNORE_WARNING=* diff --git a/VERSIONING.md b/VERSIONING.md index b0162bf8d..1b57039b2 100644 --- a/VERSIONING.md +++ b/VERSIONING.md @@ -49,6 +49,10 @@ Any non-backward compatible changes leads to a major version bump. This includes If we remove a helper function from the serverless object passed down to a plugin then this is a breaking change since some people might rely on it in custom made plugins. +### Node.js versions + +The Serverless Framework supports the major cloud providers Node.js runtime versions. Support for old Node.js versions will be removed once Cloud providers announce that such runtimes are not supported anymore. + ### FAQ 1. Is it okay to mark a feature as deprecated in version 1.4.0 and then remove it in 1.8.0 diff --git a/bin/serverless b/bin/serverless index b8cff829c..04e2eb50e 100755 --- a/bin/serverless +++ b/bin/serverless @@ -7,6 +7,20 @@ const BbPromise = require('bluebird'); const logError = require('../lib/classes/Error').logError; const uuid = require('uuid'); const initializeErrorReporter = require('../lib/utils/sentry').initializeErrorReporter; +const semver = require('semver'); +const packageJson = require('../package.json'); + +function checkNodeVersion(serverless) { + const requiredVersion = packageJson.engines.node; + const nodeVersion = process.version; + if (!semver.satisfies(nodeVersion, requiredVersion)) { + const msg = [ + `Serverless Framework requires Node.js version ${requiredVersion}. `, + `You're running version ${nodeVersion}.`, + ].join(''); + serverless.cli.log(msg); + } +} Error.stackTraceLimit = Infinity; @@ -40,6 +54,7 @@ const invocationId = uuid.v4(); serverless.invocationId = invocationId; return serverless.init() + .then(() => checkNodeVersion(serverless)) .then(() => serverless.run()) .then(() => process.exit(0)) .catch((err) => { diff --git a/package.json b/package.json index 9bd10a40f..fcb3a464e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "serverless", "version": "1.43.0", "engines": { - "node": ">=4.0" + "node": ">=6.0" }, "preferGlobal": true, "homepage": "https://github.com/serverless/serverless#readme", From 98e69f068f64f110b17996b0a1d8adac6aa512a5 Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Thu, 23 May 2019 12:16:50 +0200 Subject: [PATCH 6/6] Add engineStrict / remove version check in bin --- bin/serverless | 15 --------------- package.json | 1 + 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/bin/serverless b/bin/serverless index 04e2eb50e..b8cff829c 100755 --- a/bin/serverless +++ b/bin/serverless @@ -7,20 +7,6 @@ const BbPromise = require('bluebird'); const logError = require('../lib/classes/Error').logError; const uuid = require('uuid'); const initializeErrorReporter = require('../lib/utils/sentry').initializeErrorReporter; -const semver = require('semver'); -const packageJson = require('../package.json'); - -function checkNodeVersion(serverless) { - const requiredVersion = packageJson.engines.node; - const nodeVersion = process.version; - if (!semver.satisfies(nodeVersion, requiredVersion)) { - const msg = [ - `Serverless Framework requires Node.js version ${requiredVersion}. `, - `You're running version ${nodeVersion}.`, - ].join(''); - serverless.cli.log(msg); - } -} Error.stackTraceLimit = Infinity; @@ -54,7 +40,6 @@ const invocationId = uuid.v4(); serverless.invocationId = invocationId; return serverless.init() - .then(() => checkNodeVersion(serverless)) .then(() => serverless.run()) .then(() => process.exit(0)) .catch((err) => { diff --git a/package.json b/package.json index fcb3a464e..ad4f466d9 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "engines": { "node": ">=6.0" }, + "engineStrict": true, "preferGlobal": true, "homepage": "https://github.com/serverless/serverless#readme", "description": "Serverless Framework - Build web, mobile and IoT applications with serverless architectures using AWS Lambda, Azure Functions, Google CloudFunctions & more",