Repository: serverless/serverless (JavaScript) — Bug Fix

Issue:
Can't attach event to an existing bucket with an !ImportValue name
<!--
1. If you have a question and not a bug report please ask first at http://forum.serverless.com
2. Please check if an issue already exists. This bug may have already been documented
3. Check out and follow our Guidelines: https://github.com/serverless/serverless/blob/master/CONTRIBUTING.md
4. Fill out the whole template so we have a good overview on the issue
5. Do not remove any section of the template. If something is not applicable leave it empty but leave it in the Issue
6. Please follow the template, otherwise we'll have to ask you to update it
-->

# This is a Bug Report

## Description

Create a serverless template like this:

```
service: test

provider:
  name: aws
  runtime: nodejs10.x

functions:
  hello:
    handler: handler.hello
    events:
      - s3:
          bucket: !ImportValue test
          events:
            - s3:ObjectCreated:*
          existing: true
```

and run it:

```
# npx sls prepare
```

- What went wrong?

The CloudFormation template generated is invalid.

```
# cat .serverless/cloudformation-template-update-stack.json | jq ".Resources.IamRoleCustomResourcesLambdaExecution.Properties.Policies[0].PolicyDocument.Statement[0].Resource"

"arn:aws:s3:::[object Object]"
```
- What did you expect should have happened?

I expected the S3 Bucket ARN in the policy to be a valid ARN (generated using `Fn::Join` from the imported bucket name)

- What was the config you used?

```
service: test

provider:
  name: aws
  runtime: nodejs10.x

functions:
  hello:
    handler: handler.hello
    events:
      - s3:
          bucket: !ImportValue test
          events:
            - s3:ObjectCreated:*
          existing: true
```

- What stacktrace or error message from your provider did you see?

Similar or dependent issues:

## Additional Data

- **_Serverless Framework Version you're using_**:

```
1.48.2 (Enterprise Plugin: 1.3.1, Platform SDK: 2.0.3)
```

- **_Operating System_**:

```
Linux 4.14.128-112.105.amzn2.x86_64 #1 SMP Wed Jun 19 16:53:40 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
```

- **_Stack Trace_**:
- **_Provider Error messages_**:



Discussion:

Resolving patch:
diff --git a/lib/plugins/aws/package/compile/events/s3/index.js b/lib/plugins/aws/package/compile/events/s3/index.js
index 04af67ff703..fa3aaa00f3a 100644
--- a/lib/plugins/aws/package/compile/events/s3/index.js
+++ b/lib/plugins/aws/package/compile/events/s3/index.js
@@ -284,7 +284,7 @@ class AwsCompileS3Events {
               iamRoleStatements.push({
                 Effect: 'Allow',
                 Resource: {
-                  'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, `:s3:::${bucket}`]],
+                  'Fn::Join': [':', ['arn', { Ref: 'AWS::Partition' }, 's3', '', '', bucket]],
                 },
                 Action: ['s3:PutBucketNotification', 's3:GetBucketNotification'],
               });


Test patch:
diff --git a/lib/plugins/aws/package/compile/events/s3/index.test.js b/lib/plugins/aws/package/compile/events/s3/index.test.js
index dce6a20dd59..980346d20e6 100644
--- a/lib/plugins/aws/package/compile/events/s3/index.test.js
+++ b/lib/plugins/aws/package/compile/events/s3/index.test.js
@@ -277,13 +277,16 @@ describe('AwsCompileS3Events', () => {
             Effect: 'Allow',
             Resource: {
               'Fn::Join': [
-                '',
+                ':',
                 [
-                  'arn:',
+                  'arn',
                   {
                     Ref: 'AWS::Partition',
                   },
-                  ':s3:::existing-s3-bucket',
+                  's3',
+                  '',
+                  '',
+                  'existing-s3-bucket',
                 ],
               ],
             },
@@ -359,13 +362,16 @@ describe('AwsCompileS3Events', () => {
             Effect: 'Allow',
             Resource: {
               'Fn::Join': [
-                '',
+                ':',
                 [
-                  'arn:',
+                  'arn',
                   {
                     Ref: 'AWS::Partition',
                   },
-                  ':s3:::existing-s3-bucket',
+                  's3',
+                  '',
+                  '',
+                  'existing-s3-bucket',
                 ],
               ],
             },
@@ -462,13 +468,16 @@ describe('AwsCompileS3Events', () => {
             Effect: 'Allow',
             Resource: {
               'Fn::Join': [
-                '',
+                ':',
                 [
-                  'arn:',
+                  'arn',
                   {
                     Ref: 'AWS::Partition',
                   },
-                  ':s3:::existing-s3-bucket',
+                  's3',
+                  '',
+                  '',
+                  'existing-s3-bucket',
                 ],
               ],
             },
@@ -529,6 +538,42 @@ describe('AwsCompileS3Events', () => {
       });
     });
 
+    it('should create a valid policy for an S3 bucket using !ImportValue', () => {
+      awsCompileS3Events.serverless.service.functions = {
+        first: {
+          name: 'first',
+          events: [
+            {
+              s3: {
+                bucket: { 'Fn::ImportValue': 'existing-s3-bucket' },
+
+                existing: true,
+              },
+            },
+          ],
+        },
+      };
+
+      return expect(awsCompileS3Events.existingS3Buckets()).to.be.fulfilled.then(() => {
+        expect(addCustomResourceToServiceStub).to.have.been.calledOnce;
+        expect(addCustomResourceToServiceStub.args[0][2][0].Resource).to.deep.equal({
+          'Fn::Join': [
+            ':',
+            [
+              'arn',
+              {
+                Ref: 'AWS::Partition',
+              },
+              's3',
+              '',
+              '',
+              { 'Fn::ImportValue': 'existing-s3-bucket' },
+            ],
+          ],
+        });
+      });
+    });
+
     it('should create DependsOn clauses when one bucket is used in more than 1 custom resources', () => {
       awsCompileS3Events.serverless.service.functions = {
         first: {
@@ -604,13 +649,16 @@ describe('AwsCompileS3Events', () => {
             Effect: 'Allow',
             Resource: {
               'Fn::Join': [
-                '',
+                ':',
                 [
-                  'arn:',
+                  'arn',
                   {
                     Ref: 'AWS::Partition',
                   },
-                  ':s3:::existing-s3-bucket',
+                  's3',
+                  '',
+                  '',
+                  'existing-s3-bucket',
                 ],
               ],
             },
@@ -644,13 +692,16 @@ describe('AwsCompileS3Events', () => {
             Effect: 'Allow',
             Resource: {
               'Fn::Join': [
-                '',
+                ':',
                 [
-                  'arn:',
+                  'arn',
                   {
                     Ref: 'AWS::Partition',
                   },
-                  ':s3:::existing-s3-bucket',
+                  's3',
+                  '',
+                  '',
+                  'existing-s3-bucket',
                 ],
               ],
             },