Repository: getmoto/moto
Pull request #6051 (2023-03-10 21:40:21)

Techdebt: Sure - Documentation
- Removing sure: #6035


Patch:
diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md
index ce2a77809..51718c2fe 100644
--- a/IMPLEMENTATION_COVERAGE.md
+++ b/IMPLEMENTATION_COVERAGE.md
@@ -6055,11 +6055,11 @@
 
 ## secretsmanager
 <details>
-<summary>72% implemented</summary>
+<summary>81% implemented</summary>
 
 - [X] cancel_rotate_secret
 - [X] create_secret
-- [ ] delete_resource_policy
+- [X] delete_resource_policy
 - [X] delete_secret
 - [X] describe_secret
 - [X] get_random_password
@@ -6067,7 +6067,7 @@
 - [X] get_secret_value
 - [X] list_secret_version_ids
 - [X] list_secrets
-- [ ] put_resource_policy
+- [X] put_resource_policy
 - [X] put_secret_value
 - [ ] remove_regions_from_replication
 - [ ] replicate_secret_to_regions
diff --git a/docs/docs/services/secretsmanager.rst b/docs/docs/services/secretsmanager.rst
index fe4775f9e..9571d804b 100644
--- a/docs/docs/services/secretsmanager.rst
+++ b/docs/docs/services/secretsmanager.rst
@@ -27,7 +27,7 @@ secretsmanager
 
 - [X] cancel_rotate_secret
 - [X] create_secret
-- [ ] delete_resource_policy
+- [X] delete_resource_policy
 - [X] delete_secret
 - [X] describe_secret
 - [X] get_random_password
@@ -35,7 +35,11 @@ secretsmanager
 - [X] get_secret_value
 - [X] list_secret_version_ids
 - [X] list_secrets
-- [ ] put_resource_policy
+- [X] put_resource_policy
+  
+        The BlockPublicPolicy-parameter is not yet implemented
+        
+
 - [X] put_secret_value
 - [ ] remove_regions_from_replication
 - [ ] replicate_secret_to_regions
diff --git a/moto/resourcegroupstaggingapi/models.py b/moto/resourcegroupstaggingapi/models.py
index 0514901c6..4abb7893f 100644
--- a/moto/resourcegroupstaggingapi/models.py
+++ b/moto/resourcegroupstaggingapi/models.py
@@ -13,6 +13,7 @@ from moto.glacier import glacier_backends
 from moto.redshift import redshift_backends
 from moto.emr import emr_backends
 from moto.awslambda import lambda_backends
+from moto.ecs import ecs_backends
 
 # Left: EC2 ElastiCache RDS ELB CloudFront WorkSpaces Lambda EMR Glacier Kinesis Redshift Route53
 # StorageGateway DynamoDB MachineLearning ACM DirectConnect DirectoryService CloudHSM
@@ -106,6 +107,13 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
         """
         return lambda_backends[self.account_id][self.region_name]
 
+    @property
+    def ecs_backend(self):
+        """
+        :rtype: moto.ecs.models.EcsnBackend
+        """
+        return ecs_backends[self.account_id][self.region_name]
+
     def _get_resources_generator(self, tag_filters=None, resource_type_filters=None):
         # Look at
         # https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
@@ -143,7 +151,19 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
             else:
                 return True
 
-        # Do S3, resource type s3
+        def format_tags(tags):
+            result = []
+            for key, value in tags.items():
+                result.append({"Key": key, "Value": value})
+            return result
+
+        def format_tag_keys(tags, keys):
+            result = []
+            for tag in tags:
+                result.append({"Key": tag[keys[0]], "Value": tag[keys[1]]})
+            return result
+
+        # S3
         if not resource_type_filters or "s3" in resource_type_filters:
             for bucket in self.s3_backend.buckets.values():
                 tags = self.s3_backend.tagger.list_tags_for_resource(bucket.arn)["Tags"]
@@ -153,12 +173,45 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
                     continue
                 yield {"ResourceARN": "arn:aws:s3:::" + bucket.name, "Tags": tags}
 
-        # EC2 tags
-        def get_ec2_tags(res_id):
-            result = []
-            for key, value in self.ec2_backend.tags.get(res_id, {}).items():
-                result.append({"Key": key, "Value": value})
-            return result
+        # CloudFormation
+        if not resource_type_filters or "cloudformation:stack" in resource_type_filters:
+
+            try:
+                from moto.cloudformation import cloudformation_backends
+
+                backend = cloudformation_backends[self.account_id][self.region_name]
+
+                for stack in backend.stacks.values():
+                    tags = format_tags(stack.tags)
+                    if not tag_filter(tags):
+                        continue
+                    yield {"ResourceARN": f"{stack.stack_id}", "Tags": tags}
+
+            except Exception:
+                pass
+
+        # ECS
+        if not resource_type_filters or "ecs:service" in resource_type_filters:
+            for service in self.ecs_backend.services.values():
+                tags = format_tag_keys(service.tags, ["key", "value"])
+                if not tag_filter(tags):
+                    continue
+                yield {"ResourceARN": f"{service.physical_resource_id}", "Tags": tags}
+
+        if not resource_type_filters or "ecs:cluster" in resource_type_filters:
+            for cluster in self.ecs_backend.clusters.values():
+                tags = format_tag_keys(cluster.tags, ["key", "value"])
+                if not tag_filter(tags):
+                    continue
+                yield {"ResourceARN": f"{cluster.arn}", "Tags": tags}
+
+        if not resource_type_filters or "ecs:task" in resource_type_filters:
+            for task_dict in self.ecs_backend.tasks.values():
+                for task in task_dict.values():
+                    tags = format_tag_keys(task.tags, ["key", "value"])
+                    if not tag_filter(tags):
+                        continue
+                    yield {"ResourceARN": f"{task.task_arn}", "Tags": tags}
 
         # EC2 AMI, resource type ec2:image
         if (
@@ -167,7 +220,7 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
             or "ec2:image" in resource_type_filters
         ):
             for ami in self.ec2_backend.amis.values():
-                tags = get_ec2_tags(ami.id)
+                tags = format_tags(self.ec2_backend.tags.get(ami.id, {}))
 
                 if not tags or not tag_filter(
                     tags
@@ -186,7 +239,7 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
         ):
             for reservation in self.ec2_backend.reservations.values():
                 for instance in reservation.instances:
-                    tags = get_ec2_tags(instance.id)
+                    tags = format_tags(self.ec2_backend.tags.get(instance.id, {}))
 
                     if not tags or not tag_filter(
                         tags
@@ -204,7 +257,7 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
             or "ec2:network-interface" in resource_type_filters
         ):
             for eni in self.ec2_backend.enis.values():
-                tags = get_ec2_tags(eni.id)
+                tags = format_tags(self.ec2_backend.tags.get(eni.id, {}))
 
                 if not tags or not tag_filter(
                     tags
@@ -225,7 +278,7 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
         ):
             for vpc in self.ec2_backend.groups.values():
                 for sg in vpc.values():
-                    tags = get_ec2_tags(sg.id)
+                    tags = format_tags(self.ec2_backend.tags.get(sg.id, {}))
 
                     if not tags or not tag_filter(
                         tags
@@ -243,7 +296,7 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
             or "ec2:snapshot" in resource_type_filters
         ):
             for snapshot in self.ec2_backend.snapshots.values():
-                tags = get_ec2_tags(snapshot.id)
+                tags = format_tags(self.ec2_backend.tags.get(snapshot.id, {}))
 
                 if not tags or not tag_filter(
                     tags
@@ -263,7 +316,7 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
             or "ec2:volume" in resource_type_filters
         ):
             for volume in self.ec2_backend.volumes.values():
-                tags = get_ec2_tags(volume.id)
+                tags = format_tags(self.ec2_backend.tags.get(volume.id, {}))
 
                 if not tags or not tag_filter(
                     tags
@@ -312,15 +365,12 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
         # Kinesis
 
         # KMS
-        def get_kms_tags(kms_key_id):
-            result = []
-            for tag in self.kms_backend.list_resource_tags(kms_key_id).get("Tags", []):
-                result.append({"Key": tag["TagKey"], "Value": tag["TagValue"]})
-            return result
-
         if not resource_type_filters or "kms" in resource_type_filters:
             for kms_key in self.kms_backend.list_keys():
-                tags = get_kms_tags(kms_key.id)
+                tags = format_tag_keys(
+                    self.kms_backend.list_resource_tags(kms_key.id).get("Tags", []),
+                    ["TagKey", "TagValue"],
+                )
                 if not tag_filter(tags):  # Skip if no tags, or invalid filter
                     continue
 
@@ -408,7 +458,7 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
             or "ec2:vpc" in resource_type_filters
         ):
             for vpc in self.ec2_backend.vpcs.values():
-                tags = get_ec2_tags(vpc.id)
+                tags = format_tags(self.ec2_backend.tags.get(vpc.id, {}))
                 if not tags or not tag_filter(
                     tags
                 ):  # Skip if no tags, or invalid filter
@@ -427,15 +477,9 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
         # VPC VPN Connection
 
         # Lambda Instance
-        def transform_lambda_tags(dictTags):
-            result = []
-            for key, value in dictTags.items():
-                result.append({"Key": key, "Value": value})
-            return result
-
         if not resource_type_filters or "lambda" in resource_type_filters:
             for f in self.lambda_backend.list_functions():
-                tags = transform_lambda_tags(f.tags)
+                tags = format_tags(f.tags)
                 if not tags or not tag_filter(tags):
                     continue
                 yield {
@@ -447,7 +491,7 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
         # Look at
         # https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
 
-        # Do S3, resource type s3
+        # S3
         for bucket in self.s3_backend.buckets.values():
             tags = self.s3_backend.tagger.get_tag_dict_for_resource(bucket.arn)
             for key, _ in tags.items():
diff --git a/moto/secretsmanager/models.py b/moto/secretsmanager/models.py
index 0ae23bec5..e6cefd5a9 100644
--- a/moto/secretsmanager/models.py
+++ b/moto/secretsmanager/models.py
@@ -87,6 +87,7 @@ class FakeSecret:
         self.rotation_lambda_arn = ""
         self.auto_rotate_after_days = 0
         self.deleted_date = None
+        self.policy = None
 
     def update(
         self, description=None, tags=None, kms_key_id=None, last_changed_date=None
@@ -825,29 +826,37 @@ class SecretsManagerBackend(BaseBackend):
 
         return secret_id
 
-    @staticmethod
-    def get_resource_policy(secret_id):
-        resource_policy = {
-            "Version": "2012-10-17",
-            "Statement": {
-                "Effect": "Allow",
-                "Principal": {
-                    "AWS": [
-                        "arn:aws:iam::111122223333:root",
-                        "arn:aws:iam::444455556666:root",
-                    ]
-                },
-                "Action": ["secretsmanager:GetSecretValue"],
-                "Resource": "*",
-            },
+    def put_resource_policy(self, secret_id: str, policy: str):
+        """
+        The BlockPublicPolicy-parameter is not yet implemented
+        """
+        if not self._is_valid_identifier(secret_id):
+            raise SecretNotFoundException()
+
+        secret = self.secrets[secret_id]
+        secret.policy = policy
+        return secret.arn, secret.name
+
+    def get_resource_policy(self, secret_id):
+        if not self._is_valid_identifier(secret_id):
+            raise SecretNotFoundException()
+
+        secret = self.secrets[secret_id]
+        resp = {
+            "ARN": secret.arn,
+            "Name": secret.name,
         }
-        return json.dumps(
-            {
-                "ARN": secret_id,
-                "Name": secret_id,
-                "ResourcePolicy": json.dumps(resource_policy),
-            }
-        )
+        if secret.policy is not None:
+            resp["ResourcePolicy"] = secret.policy
+        return json.dumps(resp)
+
+    def delete_resource_policy(self, secret_id):
+        if not self._is_valid_identifier(secret_id):
+            raise SecretNotFoundException()
+
+        secret = self.secrets[secret_id]
+        secret.policy = None
+        return secret.arn, secret.name
 
 
 secretsmanager_backends = BackendDict(SecretsManagerBackend, "secretsmanager")
diff --git a/moto/secretsmanager/responses.py b/moto/secretsmanager/responses.py
index 87902d683..917579c41 100644
--- a/moto/secretsmanager/responses.py
+++ b/moto/secretsmanager/responses.py
@@ -174,6 +174,17 @@ class SecretsManagerResponse(BaseResponse):
         secret_id = self._get_param("SecretId")
         return self.backend.get_resource_policy(secret_id=secret_id)
 
+    def put_resource_policy(self):
+        secret_id = self._get_param("SecretId")
+        policy = self._get_param("ResourcePolicy")
+        arn, name = self.backend.put_resource_policy(secret_id, policy)
+        return json.dumps(dict(ARN=arn, Name=name))
+
+    def delete_resource_policy(self):
+        secret_id = self._get_param("SecretId")
+        arn, name = self.backend.delete_resource_policy(secret_id)
+        return json.dumps(dict(ARN=arn, Name=name))
+
     def tag_resource(self):
         secret_id = self._get_param("SecretId")
         tags = self._get_param("Tags", if_none=[])


Test patch:
diff --git a/docs/docs/contributing/development_tips/tests.rst b/docs/docs/contributing/development_tips/tests.rst
index 1168a4d85..b41488821 100644
--- a/docs/docs/contributing/development_tips/tests.rst
+++ b/docs/docs/contributing/development_tips/tests.rst
@@ -17,9 +17,9 @@ When writing negative tests, try to use the following format:
   with pytest.raises(botocore.exceptions.ClientError) as exc:
       client.failing_call(..)
   err = exc.value.response["Error"]
-  # These assertions use the 'sure' library, but any assertion style is accepted
-  err["Code"].should.equal(..)
-  err["Message"].should.equal(..)
+  # Use the pytest assert method, see https://docs.pytest.org/en/stable/how-to/assert.html#
+  assert err["Code"] == ..
+  assert err["Message"] == ..
 
 This is the best way to ensure that exceptions are dealt with correctly by Moto.
 
diff --git a/tests/terraformtests/terraform-tests.success.txt b/tests/terraformtests/terraform-tests.success.txt
index dfea7c1e4..0e4e3f71d 100644
--- a/tests/terraformtests/terraform-tests.success.txt
+++ b/tests/terraformtests/terraform-tests.success.txt
@@ -452,6 +452,14 @@ s3:
   - TestAccS3ObjectsDataSource_fetchOwner
 sagemaker:
   - TestAccSageMakerPrebuiltECRImageDataSource
+secretsmanager:
+  - TestAccSecretsManagerSecretDataSource_basic
+  - TestAccSecretsManagerSecretPolicy_
+  - TestAccSecretsManagerSecret_RecoveryWindowInDays_recreate
+  - TestAccSecretsManagerSecret_tags
+  - TestAccSecretsManagerSecret_kmsKeyID
+  - TestAccSecretsManagerSecret_withNamePrefix
+  - TestAccSecretsManagerSecret_rotationRules
 servicediscovery:
   - TestAccServiceDiscoveryDNSNamespaceDataSource
   - TestAccServiceDiscoveryHTTPNamespace
diff --git a/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py b/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py
index 072092ad3..cba164cfb 100644
--- a/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py
+++ b/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py
@@ -1,4 +1,5 @@
 import boto3
+import json
 import sure  # noqa # pylint: disable=unused-import
 from moto import mock_ec2
 from moto import mock_elbv2
@@ -8,10 +9,219 @@ from moto import mock_resourcegroupstaggingapi
 from moto import mock_s3
 from moto import mock_lambda
 from moto import mock_iam
+from moto import mock_cloudformation
+from moto import mock_ecs
 from botocore.client import ClientError
 from tests import EXAMPLE_AMI_ID, EXAMPLE_AMI_ID2
 
 
+@mock_kms
+@mock_cloudformation
+@mock_resourcegroupstaggingapi
+def test_get_resources_cloudformation():
+
+    template = {
+        "AWSTemplateFormatVersion": "2010-09-09",
+        "Resources": {"test": {"Type": "AWS::S3::Bucket"}},
+    }
+    template_json = json.dumps(template)
+
+    cf_client = boto3.client("cloudformation", region_name="us-east-1")
+
+    stack_one = cf_client.create_stack(
+        StackName="stack-1",
+        TemplateBody=template_json,
+        Tags=[{"Key": "tag", "Value": "one"}],
+    ).get("StackId")
+    stack_two = cf_client.create_stack(
+        StackName="stack-2",
+        TemplateBody=template_json,
+        Tags=[{"Key": "tag", "Value": "two"}],
+    ).get("StackId")
+    stack_three = cf_client.create_stack(
+        StackName="stack-3",
+        TemplateBody=template_json,
+        Tags=[{"Key": "tag", "Value": "three"}],
+    ).get("StackId")
+
+    rgta_client = boto3.client("resourcegroupstaggingapi", region_name="us-east-1")
+
+    resp = rgta_client.get_resources(TagFilters=[{"Key": "tag", "Values": ["one"]}])
+    resp["ResourceTagMappingList"].should.have.length_of(1)
+    resp["ResourceTagMappingList"][0]["ResourceARN"].should.contain(stack_one)
+
+    resp = rgta_client.get_resources(
+        TagFilters=[{"Key": "tag", "Values": ["one", "three"]}]
+    )
+    resp["ResourceTagMappingList"].should.have.length_of(2)
+    resp["ResourceTagMappingList"][0]["ResourceARN"].should.contain(stack_one)
+    resp["ResourceTagMappingList"][1]["ResourceARN"].should.contain(stack_three)
+
+    kms_client = boto3.client("kms", region_name="us-east-1")
+    kms_client.create_key(
+        KeyUsage="ENCRYPT_DECRYPT", Tags=[{"TagKey": "tag", "TagValue": "two"}]
+    )
+
+    resp = rgta_client.get_resources(TagFilters=[{"Key": "tag", "Values": ["two"]}])
+    resp["ResourceTagMappingList"].should.have.length_of(2)
+    resp["ResourceTagMappingList"][0]["ResourceARN"].should.contain(stack_two)
+    resp["ResourceTagMappingList"][1]["ResourceARN"].should.contain("kms")
+
+    resp = rgta_client.get_resources(
+        ResourceTypeFilters=["cloudformation:stack"],
+        TagFilters=[{"Key": "tag", "Values": ["two"]}],
+    )
+    resp["ResourceTagMappingList"].should.have.length_of(1)
+    resp["ResourceTagMappingList"][0]["ResourceARN"].should.contain(stack_two)
+
+
+@mock_ecs
+@mock_ec2
+@mock_resourcegroupstaggingapi
+def test_get_resources_ecs():
+
+    # ecs:cluster
+    client = boto3.client("ecs", region_name="us-east-1")
+    cluster_one = (
+        client.create_cluster(
+            clusterName="cluster-a", tags=[{"key": "tag", "value": "a tag"}]
+        )
+        .get("cluster")
+        .get("clusterArn")
+    )
+    cluster_two = (
+        client.create_cluster(
+            clusterName="cluster-b", tags=[{"key": "tag", "value": "b tag"}]
+        )
+        .get("cluster")
+        .get("clusterArn")
+    )
+
+    rgta_client = boto3.client("resourcegroupstaggingapi", region_name="us-east-1")
+    resp = rgta_client.get_resources(TagFilters=[{"Key": "tag", "Values": ["a tag"]}])
+    resp["ResourceTagMappingList"].should.have.length_of(1)
+    resp["ResourceTagMappingList"][0]["ResourceARN"].should.contain(cluster_one)
+
+    # ecs:service
+    service_one = (
+        client.create_service(
+            cluster=cluster_one,
+            serviceName="service-a",
+            tags=[{"key": "tag", "value": "a tag"}],
+        )
+        .get("service")
+        .get("serviceArn")
+    )
+
+    service_two = (
+        client.create_service(
+            cluster=cluster_two,
+            serviceName="service-b",
+            tags=[{"key": "tag", "value": "b tag"}],
+        )
+        .get("service")
+        .get("serviceArn")
+    )
+
+    resp = rgta_client.get_resources(TagFilters=[{"Key": "tag", "Values": ["a tag"]}])
+    resp["ResourceTagMappingList"].should.have.length_of(2)
+    resp["ResourceTagMappingList"][0]["ResourceARN"].should.contain(service_one)
+    resp["ResourceTagMappingList"][1]["ResourceARN"].should.contain(cluster_one)
+
+    resp = rgta_client.get_resources(
+        ResourceTypeFilters=["ecs:cluster"],
+        TagFilters=[{"Key": "tag", "Values": ["b tag"]}],
+    )
+    resp["ResourceTagMappingList"].should.have.length_of(1)
+    resp["ResourceTagMappingList"][0]["ResourceARN"].should_not.contain(service_two)
+    resp["ResourceTagMappingList"][0]["ResourceARN"].should.contain(cluster_two)
+
+    resp = rgta_client.get_resources(
+        ResourceTypeFilters=["ecs:service"],
+        TagFilters=[{"Key": "tag", "Values": ["b tag"]}],
+    )
+    resp["ResourceTagMappingList"].should.have.length_of(1)
+    resp["ResourceTagMappingList"][0]["ResourceARN"].should.contain(service_two)
+    resp["ResourceTagMappingList"][0]["ResourceARN"].should_not.contain(cluster_two)
+
+    # ecs:task
+    resp = client.register_task_definition(
+        family="test_ecs_task",
+        containerDefinitions=[
+            {
+                "name": "hello_world",
+                "image": "docker/hello-world:latest",
+                "cpu": 1024,
+                "memory": 400,
+                "essential": True,
+                "environment": [
+                    {"name": "AWS_ACCESS_KEY_ID", "value": "SOME_ACCESS_KEY"}
+                ],
+                "logConfiguration": {"logDriver": "json-file"},
+            }
+        ],
+    )
+
+    ec2_client = boto3.client("ec2", region_name="us-east-1")
+    vpc = ec2_client.create_vpc(CidrBlock="10.0.0.0/16").get("Vpc").get("VpcId")
+    subnet = (
+        ec2_client.create_subnet(VpcId=vpc, CidrBlock="10.0.0.0/18")
+        .get("Subnet")
+        .get("SubnetId")
+    )
+    sg = ec2_client.create_security_group(
+        VpcId=vpc, GroupName="test-ecs", Description="moto ecs"
+    ).get("GroupId")
+
+    task_one = (
+        client.run_task(
+            cluster="cluster-a",
+            taskDefinition="test_ecs_task",
+            launchType="FARGATE",
+            networkConfiguration={
+                "awsvpcConfiguration": {
+                    "subnets": [subnet],
+                    "securityGroups": [sg],
+                }
+            },
+            tags=[{"key": "tag", "value": "a tag"}],
+        )
+        .get("tasks")[0]
+        .get("taskArn")
+    )
+
+    task_two = (
+        client.run_task(
+            cluster="cluster-b",
+            taskDefinition="test_ecs_task",
+            launchType="FARGATE",
+            networkConfiguration={
+                "awsvpcConfiguration": {
+                    "subnets": [subnet],
+                    "securityGroups": [sg],
+                }
+            },
+            tags=[{"key": "tag", "value": "b tag"}],
+        )
+        .get("tasks")[0]
+        .get("taskArn")
+    )
+
+    resp = rgta_client.get_resources(TagFilters=[{"Key": "tag", "Values": ["b tag"]}])
+    resp["ResourceTagMappingList"].should.have.length_of(3)
+    resp["ResourceTagMappingList"][0]["ResourceARN"].should.contain(service_two)
+    resp["ResourceTagMappingList"][1]["ResourceARN"].should.contain(cluster_two)
+    resp["ResourceTagMappingList"][2]["ResourceARN"].should.contain(task_two)
+
+    resp = rgta_client.get_resources(
+        ResourceTypeFilters=["ecs:task"],
+        TagFilters=[{"Key": "tag", "Values": ["a tag"]}],
+    )
+    resp["ResourceTagMappingList"].should.have.length_of(1)
+    resp["ResourceTagMappingList"][0]["ResourceARN"].should.contain(task_one)
+    resp["ResourceTagMappingList"][0]["ResourceARN"].should_not.contain(task_two)
+
+
 @mock_rds
 @mock_ec2
 @mock_resourcegroupstaggingapi
@@ -422,50 +632,6 @@ def test_get_resources_rds():
     assert_response(resp, 2)
 
 
-@mock_rds
-@mock_resourcegroupstaggingapi
-def test_get_resources_rds_clusters():
-    client = boto3.client("rds", region_name="us-west-2")
-    resources_tagged = []
-    resources_untagged = []
-    for i in range(3):
-        cluster = client.create_db_cluster(
-            DBClusterIdentifier=f"db-cluster-{i}",
-            Engine="postgres",
-            MasterUsername="admin",
-            MasterUserPassword="P@ssw0rd!",
-            CopyTagsToSnapshot=True if i else False,
-            Tags=[{"Key": "test", "Value": f"value-{i}"}] if i else [],
-        ).get("DBCluster")
-        snapshot = client.create_db_cluster_snapshot(
-            DBClusterIdentifier=cluster["DBClusterIdentifier"],
-            DBClusterSnapshotIdentifier=f"snapshot-{i}",
-        ).get("DBClusterSnapshot")
-        group = resources_tagged if i else resources_untagged
-        group.append(cluster["DBClusterArn"])
-        group.append(snapshot["DBClusterSnapshotArn"])
-
-    def assert_response(response, expected_count, resource_type=None):
-        results = response.get("ResourceTagMappingList", [])
-        results.should.have.length_of(expected_count)
-        for item in results:
-            arn = item["ResourceARN"]
-            arn.should.be.within(resources_tagged)
-            arn.should_not.be.within(resources_untagged)
-            if resource_type:
-                sure.this(f":{resource_type}:").should.be.within(arn)
-
-    rtapi = boto3.client("resourcegroupstaggingapi", region_name="us-west-2")
-    resp = rtapi.get_resources(ResourceTypeFilters=["rds"])
-    assert_response(resp, 4)
-    resp = rtapi.get_resources(ResourceTypeFilters=["rds:cluster"])
-    assert_response(resp, 2, resource_type="cluster")
-    resp = rtapi.get_resources(ResourceTypeFilters=["rds:cluster-snapshot"])
-    assert_response(resp, 2, resource_type="cluster-snapshot")
-    resp = rtapi.get_resources(TagFilters=[{"Key": "test", "Values": ["value-1"]}])
-    assert_response(resp, 2)
-
-
 @mock_lambda
 @mock_resourcegroupstaggingapi
 @mock_iam
diff --git a/tests/test_secretsmanager/test_policy.py b/tests/test_secretsmanager/test_policy.py
new file mode 100644
index 000000000..865f62d8e
--- /dev/null
+++ b/tests/test_secretsmanager/test_policy.py
@@ -0,0 +1,77 @@
+import boto3
+import json
+import pytest
+
+from botocore.exceptions import ClientError
+from moto import mock_secretsmanager
+
+
+@mock_secretsmanager
+def test_get_initial_policy():
+    client = boto3.client("secretsmanager", region_name="us-west-2")
+    client.create_secret(Name="test-secret")
+
+    resp = client.get_resource_policy(SecretId="test-secret")
+    assert resp.get("Name") == "test-secret"
+    assert "ARN" in resp
+    assert "ResourcePolicy" not in resp
+
+
+@mock_secretsmanager
+def test_put_resource_policy():
+    client = boto3.client("secretsmanager", region_name="us-west-2")
+    client.create_secret(Name="test-secret")
+
+    policy = {
+        "Statement": [
+            {
+                "Action": "secretsmanager:GetSecretValue",
+                "Effect": "Allow",
+                "Principal": {
+                    "AWS": "arn:aws:iam::123456789012:role/tf-acc-test-655046176950657276"
+                },
+                "Resource": "*",
+                "Sid": "EnableAllPermissions",
+            }
+        ],
+        "Version": "2012-10-17",
+    }
+    resp = client.put_resource_policy(
+        SecretId="test-secret", ResourcePolicy=json.dumps(policy)
+    )
+    assert "ARN" in resp
+    assert "Name" in resp
+
+    resp = client.get_resource_policy(SecretId="test-secret")
+    assert "ResourcePolicy" in resp
+    assert json.loads(resp["ResourcePolicy"]) == policy
+
+
+@mock_secretsmanager
+def test_delete_resource_policy():
+    client = boto3.client("secretsmanager", region_name="us-west-2")
+    client.create_secret(Name="test-secret")
+
+    client.put_resource_policy(SecretId="test-secret", ResourcePolicy="some policy")
+
+    client.delete_resource_policy(SecretId="test-secret")
+
+    resp = client.get_resource_policy(SecretId="test-secret")
+    assert "ResourcePolicy" not in resp
+
+
+@mock_secretsmanager
+def test_policies_for_unknown_secrets():
+    client = boto3.client("secretsmanager", region_name="us-west-2")
+
+    with pytest.raises(ClientError) as exc:
+        client.put_resource_policy(SecretId="unknown secret", ResourcePolicy="p")
+    assert exc.value.response["Error"]["Code"] == "ResourceNotFoundException"
+
+    with pytest.raises(ClientError) as exc:
+        client.get_resource_policy(SecretId="unknown secret")
+    assert exc.value.response["Error"]["Code"] == "ResourceNotFoundException"
+
+    with pytest.raises(ClientError) as exc:
+        client.delete_resource_policy(SecretId="unknown secret")
+    assert exc.value.response["Error"]["Code"] == "ResourceNotFoundException"