Repository: cloud-custodian/cloud-custodian

Issue:
S3 Add Filter for Bucket Replication filter
### Describe the feature

Per two different compliance frameworks (so far) I need the ability to check if an s3 bucket has cross region replication enabled.

### Extra information or context

This can be achieved by running the get_bucket_replication api and then running the get_bucket_location on the destination bucket.

Sample of what policy could look like: 

```
policies:
  - name: aws-s3-bucket-cross-region-replication
    resource: aws.s3
    conditions:
    - region: us-east-1
    filters:
    - type: bucket-replication
      cross-region: True
```


Discussion:
I will work on this issue.

Resolving patch:
diff --git a/c7n/resources/s3.py b/c7n/resources/s3.py
--- a/c7n/resources/s3.py
+++ b/c7n/resources/s3.py
@@ -64,6 +64,7 @@
 from c7n.utils import (
     chunks, local_session, set_annotation, type_schema, filter_empty,
     dumps, format_string_values, get_account_alias_from_sts)
+from c7n.resources.aws import inspect_bucket_region
 
 
 log = logging.getLogger('custodian.s3')
@@ -3707,3 +3708,66 @@ def process_bucket(self, b):
                 raise
             controls = {}
         b[self.annotation_key] = controls.get('OwnershipControls')
+
+
+@filters.register('bucket-replication')
+class BucketReplication(ListItemFilter):
+    """Filter for S3 buckets to look at bucket replication configurations
+
+    The schema to supply to the attrs follows the schema here:
+     https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3/client/get_bucket_replication.html
+
+    :example:
+
+    .. code-block:: yaml
+
+            policies:
+              - name: s3-bucket-replication
+                resource: s3
+                filters:
+                  - type: bucket-replication
+                    attrs:
+                      - Status: Enabled
+                      - Filter:
+                          And:
+                            Prefix: test
+                            Tags:
+                              - Key: Owner
+                                Value: c7n
+                      - ExistingObjectReplication: Enabled
+
+    """
+    schema = type_schema(
+        'bucket-replication',
+        attrs={'$ref': '#/definitions/filters_common/list_item_attrs'},
+        count={'type': 'number'},
+        count_op={'$ref': '#/definitions/filters_common/comparison_operators'}
+    )
+
+    permissions = ("s3:GetReplicationConfiguration",)
+    annotation_key = 'Replication'
+    annotate_items = True
+
+    def __init__(self, data, manager=None):
+        super().__init__(data, manager)
+        self.data['key'] = self.annotation_key
+
+    def get_item_values(self, b):
+        client = bucket_client(local_session(self.manager.session_factory), b)
+        # replication configuration is called in S3_AUGMENT_TABLE:
+        bucket_replication = b[self.annotation_key]
+
+        rules = []
+        if bucket_replication is not None:
+            rules = bucket_replication.get('ReplicationConfiguration', {}).get('Rules', [])
+            for replication in rules:
+                self.augment_bucket_replication(b, replication, client)
+
+        return rules
+
+    def augment_bucket_replication(self, b, replication, client):
+        destination_bucket = replication.get('Destination').get('Bucket').split(':')[5]
+        destination_region = inspect_bucket_region(destination_bucket, client.meta.endpoint_url)
+        source_region = get_region(b)
+        replication['DestinationRegion'] = destination_region
+        replication['CrossRegion'] = destination_region != source_region


Test patch:
diff --git a/tests/data/placebo/test_s3_bucket_no_replication_rule/s3.GetBucketReplication_1.json b/tests/data/placebo/test_s3_bucket_no_replication_rule/s3.GetBucketReplication_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_s3_bucket_no_replication_rule/s3.GetBucketReplication_1.json
@@ -0,0 +1,33 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {},
+        "ReplicationConfiguration": {
+            "Role": "arn:aws:iam::644160558196:role/service-role/s3crr_role_for_custodian-repl-test-1",
+            "Rules": [
+                {
+                    "ID": "replication-1",
+                    "Priority": 0,
+                    "Filter": {
+                        "And": {
+                            "Prefix": "abc",
+                            "Tags": [
+                                {
+                                    "Key": "Owner",
+                                    "Value": "c7n"
+                                }
+                            ]
+                        }
+                    },
+                    "Status": "Enabled",
+                    "Destination": {
+                        "Bucket": "arn:aws:s3:::custodian-replication-west"
+                    },
+                    "DeleteMarkerReplication": {
+                        "Status": "Disabled"
+                    }
+                }
+            ]
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_s3_bucket_no_replication_rule/s3.GetBucketReplication_2.json b/tests/data/placebo/test_s3_bucket_no_replication_rule/s3.GetBucketReplication_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_s3_bucket_no_replication_rule/s3.GetBucketReplication_2.json
@@ -0,0 +1,11 @@
+{
+    "status_code": 404,
+    "data": {
+        "Error": {
+            "Code": "ReplicationConfigurationNotFoundError",
+            "Message": "The replication configuration was not found",
+            "BucketName": "custodian-replication-west"
+        },
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_s3_bucket_no_replication_rule/s3.ListBuckets_1.json b/tests/data/placebo/test_s3_bucket_no_replication_rule/s3.ListBuckets_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_s3_bucket_no_replication_rule/s3.ListBuckets_1.json
@@ -0,0 +1,38 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {},
+        "Buckets": [
+            {
+                "Name": "custodian-replication-test-1",
+                "CreationDate": {
+                    "__class__": "datetime",
+                    "year": 2023,
+                    "month": 7,
+                    "day": 31,
+                    "hour": 21,
+                    "minute": 29,
+                    "second": 35,
+                    "microsecond": 0
+                }
+            },
+            {
+                "Name": "custodian-replication-west",
+                "CreationDate": {
+                    "__class__": "datetime",
+                    "year": 2023,
+                    "month": 7,
+                    "day": 31,
+                    "hour": 21,
+                    "minute": 30,
+                    "second": 9,
+                    "microsecond": 0
+                }
+            }
+        ],
+        "Owner": {
+            "DisplayName": "jerryhxu",
+            "ID": "3f7350bf5d3dab59930bea77eec4aeb7790ca043fbc1891bbabb70df0c63ff01"
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_s3_bucket_replication_filter/s3.GetBucketReplication_1.json b/tests/data/placebo/test_s3_bucket_replication_filter/s3.GetBucketReplication_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_s3_bucket_replication_filter/s3.GetBucketReplication_1.json
@@ -0,0 +1,33 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {},
+        "ReplicationConfiguration": {
+            "Role": "arn:aws:iam::644160558196:role/service-role/s3crr_role_for_custodian-repl-test-1",
+            "Rules": [
+                {
+                    "ID": "replication-1",
+                    "Priority": 0,
+                    "Filter": {
+                        "And": {
+                            "Prefix": "abc",
+                            "Tags": [
+                                {
+                                    "Key": "Owner",
+                                    "Value": "c7n"
+                                }
+                            ]
+                        }
+                    },
+                    "Status": "Enabled",
+                    "Destination": {
+                        "Bucket": "arn:aws:s3:::custodian-replication-west"
+                    },
+                    "DeleteMarkerReplication": {
+                        "Status": "Disabled"
+                    }
+                }
+            ]
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_s3_bucket_replication_filter/s3.GetBucketReplication_2.json b/tests/data/placebo/test_s3_bucket_replication_filter/s3.GetBucketReplication_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_s3_bucket_replication_filter/s3.GetBucketReplication_2.json
@@ -0,0 +1,11 @@
+{
+    "status_code": 404,
+    "data": {
+        "Error": {
+            "Code": "ReplicationConfigurationNotFoundError",
+            "Message": "The replication configuration was not found",
+            "BucketName": "custodian-replication-west"
+        },
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_s3_bucket_replication_filter/s3.ListBuckets_1.json b/tests/data/placebo/test_s3_bucket_replication_filter/s3.ListBuckets_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_s3_bucket_replication_filter/s3.ListBuckets_1.json
@@ -0,0 +1,38 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {},
+        "Buckets": [
+            {
+                "Name": "custodian-replication-test-1",
+                "CreationDate": {
+                    "__class__": "datetime",
+                    "year": 2023,
+                    "month": 7,
+                    "day": 31,
+                    "hour": 21,
+                    "minute": 29,
+                    "second": 35,
+                    "microsecond": 0
+                }
+            },
+            {
+                "Name": "custodian-replication-west",
+                "CreationDate": {
+                    "__class__": "datetime",
+                    "year": 2023,
+                    "month": 7,
+                    "day": 31,
+                    "hour": 21,
+                    "minute": 30,
+                    "second": 9,
+                    "microsecond": 0
+                }
+            }
+        ],
+        "Owner": {
+            "DisplayName": "jerryhxu",
+            "ID": "3f7350bf5d3dab59930bea77eec4aeb7790ca043fbc1891bbabb70df0c63ff01"
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_s3_bucket_replication_filter_count/s3.GetBucketReplication_1.json b/tests/data/placebo/test_s3_bucket_replication_filter_count/s3.GetBucketReplication_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_s3_bucket_replication_filter_count/s3.GetBucketReplication_1.json
@@ -0,0 +1,33 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {},
+        "ReplicationConfiguration": {
+            "Role": "arn:aws:iam::644160558196:role/service-role/s3crr_role_for_custodian-repl-test-1",
+            "Rules": [
+                {
+                    "ID": "replication-1",
+                    "Priority": 0,
+                    "Filter": {
+                        "And": {
+                            "Prefix": "abc",
+                            "Tags": [
+                                {
+                                    "Key": "Owner",
+                                    "Value": "c7n"
+                                }
+                            ]
+                        }
+                    },
+                    "Status": "Enabled",
+                    "Destination": {
+                        "Bucket": "arn:aws:s3:::custodian-replication-west"
+                    },
+                    "DeleteMarkerReplication": {
+                        "Status": "Disabled"
+                    }
+                }
+            ]
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_s3_bucket_replication_filter_count/s3.GetBucketReplication_2.json b/tests/data/placebo/test_s3_bucket_replication_filter_count/s3.GetBucketReplication_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_s3_bucket_replication_filter_count/s3.GetBucketReplication_2.json
@@ -0,0 +1,11 @@
+{
+    "status_code": 404,
+    "data": {
+        "Error": {
+            "Code": "ReplicationConfigurationNotFoundError",
+            "Message": "The replication configuration was not found",
+            "BucketName": "custodian-replication-west"
+        },
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_s3_bucket_replication_filter_count/s3.ListBuckets_1.json b/tests/data/placebo/test_s3_bucket_replication_filter_count/s3.ListBuckets_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_s3_bucket_replication_filter_count/s3.ListBuckets_1.json
@@ -0,0 +1,38 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {},
+        "Buckets": [
+            {
+                "Name": "custodian-replication-test-1",
+                "CreationDate": {
+                    "__class__": "datetime",
+                    "year": 2023,
+                    "month": 7,
+                    "day": 31,
+                    "hour": 21,
+                    "minute": 29,
+                    "second": 35,
+                    "microsecond": 0
+                }
+            },
+            {
+                "Name": "custodian-replication-west",
+                "CreationDate": {
+                    "__class__": "datetime",
+                    "year": 2023,
+                    "month": 7,
+                    "day": 31,
+                    "hour": 21,
+                    "minute": 30,
+                    "second": 9,
+                    "microsecond": 0
+                }
+            }
+        ],
+        "Owner": {
+            "DisplayName": "jerryhxu",
+            "ID": "3f7350bf5d3dab59930bea77eec4aeb7790ca043fbc1891bbabb70df0c63ff01"
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/vcr_cassettes/test_s3/no_replication_rule.yaml b/tests/data/vcr_cassettes/test_s3/no_replication_rule.yaml
new file mode 100644
--- /dev/null
+++ b/tests/data/vcr_cassettes/test_s3/no_replication_rule.yaml
@@ -0,0 +1,66 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Connection:
+      - close
+      Host:
+      - s3.amazonaws.com
+      User-Agent:
+      - Python-urllib/3.11
+    method: HEAD
+    uri: https://s3.amazonaws.com/custodian-replication-west
+  response:
+    body:
+      string: ''
+    headers:
+      Connection:
+      - close
+      Content-Type:
+      - application/xml
+      Date:
+      - Tue, 01 Aug 2023 14:23:50 GMT
+      Server:
+      - AmazonS3
+      x-amz-bucket-region:
+      - us-west-2
+      x-amz-id-2:
+      - OvnbsSTEcnispyAPkVfE5hCOfCzvClapPsssed3GzeFFeNY2vj0hxIS4hLtXSq565Sp+uLpyt2M=
+      x-amz-request-id:
+      - JRH1XHC2D55RHVY6
+    status:
+      code: 301
+      message: Moved Permanently
+- request:
+    body: null
+    headers:
+      Connection:
+      - close
+      Host:
+      - s3.amazonaws.com
+      User-Agent:
+      - Python-urllib/3.11
+    method: HEAD
+    uri: https://s3.amazonaws.com/custodian-replication-west
+  response:
+    body:
+      string: ''
+    headers:
+      Connection:
+      - close
+      Content-Type:
+      - application/xml
+      Date:
+      - Tue, 01 Aug 2023 14:23:51 GMT
+      Server:
+      - AmazonS3
+      x-amz-bucket-region:
+      - us-west-2
+      x-amz-id-2:
+      - YjTaJCYAvfjOB00Q70mdRJYbF9lGmg+NDMonbGW5FEAGOcmQhRWVYxP1he2UP3PFC4qf9ij6Wxo=
+      x-amz-request-id:
+      - JRHFR7EVB52TP4TV
+    status:
+      code: 301
+      message: Moved Permanently
+version: 1
diff --git a/tests/data/vcr_cassettes/test_s3/replication_filter_count.yaml b/tests/data/vcr_cassettes/test_s3/replication_filter_count.yaml
new file mode 100644
--- /dev/null
+++ b/tests/data/vcr_cassettes/test_s3/replication_filter_count.yaml
@@ -0,0 +1,66 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Connection:
+      - close
+      Host:
+      - s3.amazonaws.com
+      User-Agent:
+      - Python-urllib/3.11
+    method: HEAD
+    uri: https://s3.amazonaws.com/custodian-replication-west
+  response:
+    body:
+      string: ''
+    headers:
+      Connection:
+      - close
+      Content-Type:
+      - application/xml
+      Date:
+      - Tue, 01 Aug 2023 14:11:08 GMT
+      Server:
+      - AmazonS3
+      x-amz-bucket-region:
+      - us-west-2
+      x-amz-id-2:
+      - ocFZRbWdjU2wnd4KmOGplwtm5bCjR2jA31sLpeW9M55lNFXvsqON7q6Zhi4fl0xvt8VNnU3LO6g=
+      x-amz-request-id:
+      - XYQDPDDCHH6JTH60
+    status:
+      code: 301
+      message: Moved Permanently
+- request:
+    body: null
+    headers:
+      Connection:
+      - close
+      Host:
+      - s3.amazonaws.com
+      User-Agent:
+      - Python-urllib/3.11
+    method: HEAD
+    uri: https://s3.amazonaws.com/custodian-replication-west
+  response:
+    body:
+      string: ''
+    headers:
+      Connection:
+      - close
+      Content-Type:
+      - application/xml
+      Date:
+      - Tue, 01 Aug 2023 14:11:09 GMT
+      Server:
+      - AmazonS3
+      x-amz-bucket-region:
+      - us-west-2
+      x-amz-id-2:
+      - sQQAKVBFLxcy54Mh9vArg2RjZjVa/lFsOy8SRzXodHumCht8Jlb7oi6eMAyhqSExY0cZWcen674=
+      x-amz-request-id:
+      - XYQAKF1QXNPMHM69
+    status:
+      code: 301
+      message: Moved Permanently
+version: 1
diff --git a/tests/data/vcr_cassettes/test_s3/replication_rule.yaml b/tests/data/vcr_cassettes/test_s3/replication_rule.yaml
new file mode 100644
--- /dev/null
+++ b/tests/data/vcr_cassettes/test_s3/replication_rule.yaml
@@ -0,0 +1,66 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Connection:
+      - close
+      Host:
+      - s3.amazonaws.com
+      User-Agent:
+      - Python-urllib/3.11
+    method: HEAD
+    uri: https://s3.amazonaws.com/custodian-replication-west
+  response:
+    body:
+      string: ''
+    headers:
+      Connection:
+      - close
+      Content-Type:
+      - application/xml
+      Date:
+      - Tue, 01 Aug 2023 02:54:05 GMT
+      Server:
+      - AmazonS3
+      x-amz-bucket-region:
+      - us-west-2
+      x-amz-id-2:
+      - osPW5X65siRd5efyvp2LMZzycw68xSrOCGVQhtnCdO8vnSkIrye2fp8Ki9Hzvb94vZJOk33H58U=
+      x-amz-request-id:
+      - M7Z9EA0T1CMB7J29
+    status:
+      code: 301
+      message: Moved Permanently
+- request:
+    body: null
+    headers:
+      Connection:
+      - close
+      Host:
+      - s3.amazonaws.com
+      User-Agent:
+      - Python-urllib/3.11
+    method: HEAD
+    uri: https://s3.amazonaws.com/custodian-replication-west
+  response:
+    body:
+      string: ''
+    headers:
+      Connection:
+      - close
+      Content-Type:
+      - application/xml
+      Date:
+      - Tue, 01 Aug 2023 02:54:05 GMT
+      Server:
+      - AmazonS3
+      x-amz-bucket-region:
+      - us-west-2
+      x-amz-id-2:
+      - nE+7LfpC3lr2qo8xAtz44hcedIuRySM07voQxEJpcMPrc5awn0yJ8GOQQDRsxnc1H9/vj31EuHM=
+      x-amz-request-id:
+      - M7Z6T8ETG7K3B188
+    status:
+      code: 301
+      message: Moved Permanently
+version: 1
diff --git a/tests/test_route53.py b/tests/test_route53.py
--- a/tests/test_route53.py
+++ b/tests/test_route53.py
@@ -602,16 +602,3 @@ def test_control_panel_safety_rule_filter(self):
         self.assertEqual(len(resources), 1)
         self.assertEqual(resources[0]['ControlPanelArn'], \
             'arn:aws:route53-recovery-control::644160558196:controlpanel/fd5a6bfc73364a0dbd48d3915867a306')
-        return
-        p = self.load_policy(
-            {
-                "name": "control-panel-safety-rule",
-                "resource": "recovery-control-panel",
-                "filters": [{'type': 'safety-rule', 'count': 0}],
-            },
-            session_factory=session_factory,
-        )
-        resources = p.run()
-        self.assertEqual(len(resources), 1)
-        self.assertEqual(resources[0]['ControlPanelArn'], \
-             'arn:aws:route53-recovery-control::644160558196:controlpanel/7a721a1a44014ad1973539b3d83161ff')
diff --git a/tests/test_s3.py b/tests/test_s3.py
--- a/tests/test_s3.py
+++ b/tests/test_s3.py
@@ -25,6 +25,7 @@
 from c7n.mu import LambdaManager
 from c7n.ufuncs import s3crypt
 from c7n.utils import get_account_alias_from_sts, jmespath_search
+import vcr
 
 from .common import (
     BaseTest,
@@ -4334,3 +4335,96 @@ def test_s3_list_tiering_config_denied_method(self):
         self.assertIn(
           'Access Denied Bucket:example-abc-123 while reading intelligent tiering configurations',
             log_output.getvalue())
+
+
+class BucketReplication(BaseTest):
+    def test_s3_bucket_replication_filter(self):
+        self.patch(s3.S3, "executor_factory", MainThreadExecutor)
+        self.patch(s3, "S3_AUGMENT_TABLE", [])
+        self.patch(s3, "S3_AUGMENT_TABLE", [('get_bucket_replication',
+        'Replication', None, None, 's3:GetReplicationConfiguration')])
+        session_factory = self.replay_flight_data("test_s3_bucket_replication_filter")
+        p = self.load_policy(
+            {
+                "name": "s3-replication-rule",
+                "resource": "s3",
+                "filters": [
+                        {
+                            "type": "bucket-replication",
+                            "attrs": [
+                            {"Status": "Enabled"},
+                            {"Filter": {
+                                "And": {
+                                    "Prefix": "abc", "Tags": [{"Key": "Owner", "Value": "c7n"}]}}},
+                            {"DestinationRegion": "us-west-2"},
+                            {"CrossRegion": True }
+                            ]
+                        }
+                    ],
+                },
+            session_factory=session_factory,
+        )
+        with vcr.use_cassette(
+          'tests/data/vcr_cassettes/test_s3/replication_rule.yaml',
+           record_mode='none'
+        ):
+            resources = p.run()
+            self.assertEqual(len(resources), 1)
+            self.assertTrue("Replication" in resources[0])
+            self.assertEqual(len(resources[0].get("c7n:ListItemMatches")), 1)
+
+    def test_s3_bucket_replication_filter_count(self):
+        self.patch(s3.S3, "executor_factory", MainThreadExecutor)
+        self.patch(s3, "S3_AUGMENT_TABLE", [])
+        self.patch(s3, "S3_AUGMENT_TABLE", [('get_bucket_replication',
+        'Replication', None, None, 's3:GetReplicationConfiguration')])
+        session_factory = self.replay_flight_data("test_s3_bucket_replication_filter_count")
+        p = self.load_policy(
+            {
+                "name": "s3-replication-filter-count",
+                "resource": "s3",
+                "filters": [
+                    {
+                        "type": "bucket-replication",
+                        "count": 1,
+                        "count_op": "eq"
+                    }
+                ],
+            },
+            session_factory=session_factory,
+        )
+        with vcr.use_cassette(
+          'tests/data/vcr_cassettes/test_s3/replication_filter_count.yaml',
+           record_mode='none'
+        ):
+            resources = p.run()
+            self.assertEqual(len(resources), 1)
+            self.assertEqual(resources[0]['Name'],'custodian-replication-test-1')
+
+    def test_s3_bucket_no_replication_rule(self):
+        self.patch(s3.S3, "executor_factory", MainThreadExecutor)
+        self.patch(s3, "S3_AUGMENT_TABLE", [])
+        self.patch(s3, "S3_AUGMENT_TABLE", [('get_bucket_replication',
+        'Replication', None, None, 's3:GetReplicationConfiguration')])
+        session_factory = self.replay_flight_data("test_s3_bucket_no_replication_rule")
+        p = self.load_policy(
+            {
+                "name": "s3-no-replication-rule",
+                "resource": "s3",
+                "filters": [
+                    {
+                        "not": [
+                            "bucket-replication"
+                        ]
+                    }
+                ],
+            },
+            session_factory=session_factory,
+        )
+        with vcr.use_cassette(
+          'tests/data/vcr_cassettes/test_s3/no_replication_rule.yaml',
+           record_mode='none'
+        ):
+            resources = p.run()
+            self.assertEqual(len(resources), 1)
+            self.assertEqual(resources[0]['Name'],'custodian-replication-west')