Repository: getmoto/moto
Pull request #7091 (2023-12-03 05:30:27)

Improve typing for IAM
This MR cleans up as many ignores in moto.iam as I felt like I could do safely. I also enabled additional mypy strictness locally to see what else might turn up in there.

Of particular note:

 - updates moto.core.common_models.ConfigQueryModel to be a generic type, parameterized by the kind of backend in use
 - mypy --install-types wasn't installing up botocore-stubs, so I added that to the requirements-dev.txt file
 - I refactored some logic in moto/iam/config.py so that mypy could follow what was going on. It should be identical in effect, but the flow of conditionals was too complicated before.
 - Separate from the issue of typing per se, I added my solution for the issue of outside users manually setting AccessKey.last_used (of which I am one in one codebase I maintain). This allows you to set it to a datetime, but the value that gets stored is a AccessKeyLastUsed object generated from that datetime object. In theory, this could cause an issue for any user who accesses the value directly after setting it initially? I don't know if that means you'll want to hold it back for a major bump or not. There's also the potential issue that setting service and region to "unknown" isn't actually something that AWS would ever return? But speaking personally I would find this convenient.


Patch:
diff --git a/moto/__init__.py b/moto/__init__.py
index 358c56f5a..c4a944bf1 100644
--- a/moto/__init__.py
+++ b/moto/__init__.py
@@ -263,7 +263,7 @@ __version__ = "4.2.12.dev"
 
 try:
     # Need to monkey-patch botocore requests back to underlying urllib3 classes
-    from botocore.awsrequest import (
+    from botocore.awsrequest import (  # type: ignore[attr-defined]
         HTTPConnection,
         HTTPConnectionPool,
         HTTPSConnectionPool,
diff --git a/moto/config/models.py b/moto/config/models.py
index f324884d2..821bfd73a 100644
--- a/moto/config/models.py
+++ b/moto/config/models.py
@@ -70,7 +70,7 @@ DEFAULT_PAGE_SIZE = 100
 CONFIG_RULE_PAGE_SIZE = 25
 
 # Map the Config resource type to a backend:
-RESOURCE_MAP: Dict[str, ConfigQueryModel] = {
+RESOURCE_MAP: Dict[str, ConfigQueryModel[Any]] = {
     "AWS::S3::Bucket": s3_config_query,
     "AWS::S3::AccountPublicAccessBlock": s3_account_public_access_block_query,
     "AWS::IAM::Role": role_config_query,
diff --git a/moto/core/botocore_stubber.py b/moto/core/botocore_stubber.py
index 1319b6727..54f7e150f 100644
--- a/moto/core/botocore_stubber.py
+++ b/moto/core/botocore_stubber.py
@@ -1,6 +1,6 @@
 from collections import defaultdict
 from io import BytesIO
-from typing import Any, Callable, Dict, List, Pattern, Tuple, Union
+from typing import Any, Callable, Dict, List, Optional, Pattern, Tuple, Union
 
 from botocore.awsrequest import AWSResponse
 
@@ -38,7 +38,9 @@ class BotocoreStubber:
         matchers = self.methods[method]
         matchers.append((pattern, response))
 
-    def __call__(self, event_name: str, request: Any, **kwargs: Any) -> AWSResponse:
+    def __call__(
+        self, event_name: str, request: Any, **kwargs: Any
+    ) -> Optional[AWSResponse]:
         if not self.enabled:
             return None
 
@@ -70,6 +72,6 @@ class BotocoreStubber:
                 headers = e.get_headers()  # type: ignore[assignment]
                 body = e.get_body()
             raw_response = MockRawResponse(body)
-            response = AWSResponse(request.url, status, headers, raw_response)
+            response = AWSResponse(request.url, status, headers, raw_response)  # type: ignore[arg-type]
 
         return response
diff --git a/moto/core/common_models.py b/moto/core/common_models.py
index f070e1a7e..fdf621f3e 100644
--- a/moto/core/common_models.py
+++ b/moto/core/common_models.py
@@ -1,7 +1,7 @@
 from abc import abstractmethod
-from typing import Any, Dict, List, Optional, Tuple
+from typing import Any, Dict, Generic, List, Optional, Tuple
 
-from .base_backend import InstanceTrackerMeta
+from .base_backend import SERVICE_BACKEND, BackendDict, InstanceTrackerMeta
 
 
 class BaseModel(metaclass=InstanceTrackerMeta):
@@ -94,8 +94,8 @@ class CloudFormationModel(BaseModel):
         return True
 
 
-class ConfigQueryModel:
-    def __init__(self, backends: Any):
+class ConfigQueryModel(Generic[SERVICE_BACKEND]):
+    def __init__(self, backends: BackendDict[SERVICE_BACKEND]):
         """Inits based on the resource type's backends (1 for each region if applicable)"""
         self.backends = backends
 
diff --git a/moto/core/models.py b/moto/core/models.py
index 8017c8635..9d5dc2c0e 100644
--- a/moto/core/models.py
+++ b/moto/core/models.py
@@ -293,7 +293,7 @@ def patch_client(client: botocore.client.BaseClient) -> None:
     if isinstance(client, botocore.client.BaseClient):
         # Check if our event handler was already registered
         try:
-            event_emitter = client._ruleset_resolver._event_emitter._emitter
+            event_emitter = client._ruleset_resolver._event_emitter._emitter  # type: ignore[attr-defined]
             all_handlers = event_emitter._handlers._root["children"]
             handler_trie = list(all_handlers["before-send"].values())[1]
             handlers_list = handler_trie.first + handler_trie.middle + handler_trie.last
diff --git a/moto/iam/access_control.py b/moto/iam/access_control.py
index 0ec12b595..c7eb0c2d0 100644
--- a/moto/iam/access_control.py
+++ b/moto/iam/access_control.py
@@ -257,7 +257,7 @@ class IAMRequestBase(object, metaclass=ABCMeta):
         raise NotImplementedError()
 
     @abstractmethod
-    def _create_auth(self, credentials: Credentials) -> SigV4Auth:  # type: ignore[misc]
+    def _create_auth(self, credentials: Credentials) -> SigV4Auth:
         raise NotImplementedError()
 
     @staticmethod
diff --git a/moto/iam/config.py b/moto/iam/config.py
index ca2e67c8f..8d929bcb1 100644
--- a/moto/iam/config.py
+++ b/moto/iam/config.py
@@ -5,10 +5,10 @@ import boto3
 
 from moto.core.common_models import ConfigQueryModel
 from moto.core.exceptions import InvalidNextTokenException
-from moto.iam import iam_backends
+from moto.iam.models import IAMBackend, iam_backends
 
 
-class RoleConfigQuery(ConfigQueryModel):
+class RoleConfigQuery(ConfigQueryModel[IAMBackend]):
     def list_config_service_resources(
         self,
         account_id: str,
@@ -32,26 +32,27 @@ class RoleConfigQuery(ConfigQueryModel):
             return [], None
 
         # Filter by resource name or ids
-        if resource_name or resource_ids:
-            filtered_roles = []
-            # resource_name takes precedence over resource_ids
-            if resource_name:
-                for role in role_list:
-                    if role.name == resource_name:
-                        filtered_roles = [role]
-                        break
-                # but if both are passed, it must be a subset
-                if filtered_roles and resource_ids:
-                    if filtered_roles[0].id not in resource_ids:
-                        return [], None
-            else:
-                for role in role_list:
-                    if role.id in resource_ids:  # type: ignore[operator]
-                        filtered_roles.append(role)
+        # resource_name takes precedence over resource_ids
+        filtered_roles = []
+        if resource_name:
+            for role in role_list:
+                if role.name == resource_name:
+                    filtered_roles = [role]
+                    break
+            # but if both are passed, it must be a subset
+            if filtered_roles and resource_ids:
+                if filtered_roles[0].id not in resource_ids:
+                    return [], None
 
             # Filtered roles are now the subject for the listing
             role_list = filtered_roles
 
+        elif resource_ids:
+            for role in role_list:
+                if role.id in resource_ids:
+                    filtered_roles.append(role)
+            role_list = filtered_roles
+
         if aggregator:
             # IAM is a little special; Roles are created in us-east-1 (which AWS calls the "global" region)
             # However, the resource will return in the aggregator (in duplicate) for each region in the aggregator
@@ -77,7 +78,6 @@ class RoleConfigQuery(ConfigQueryModel):
                     duplicate_role_list.append(
                         {
                             "_id": f"{role.id}{region}",  # this is only for sorting, isn't returned outside of this function
-                            "type": "AWS::IAM::Role",
                             "id": role.id,
                             "name": role.name,
                             "region": region,
@@ -89,7 +89,10 @@ class RoleConfigQuery(ConfigQueryModel):
         else:
             # Non-aggregated queries are in the else block, and we can treat these like a normal config resource
             # Pagination logic, sort by role id
-            sorted_roles = sorted(role_list, key=lambda role: role.id)  # type: ignore[attr-defined]
+            sorted_roles = [
+                {"_id": role.id, "id": role.id, "name": role.name, "region": "global"}
+                for role in sorted(role_list, key=lambda role: role.id)
+            ]
 
         new_token = None
 
@@ -102,27 +105,27 @@ class RoleConfigQuery(ConfigQueryModel):
                 start = next(
                     index
                     for (index, r) in enumerate(sorted_roles)
-                    if next_token == (r["_id"] if aggregator else r.id)  # type: ignore[attr-defined]
+                    if next_token == r["_id"]
                 )
             except StopIteration:
                 raise InvalidNextTokenException()
 
         # Get the list of items to collect:
-        role_list = sorted_roles[start : (start + limit)]
+        collected_role_list = sorted_roles[start : (start + limit)]
 
         if len(sorted_roles) > (start + limit):
             record = sorted_roles[start + limit]
-            new_token = record["_id"] if aggregator else record.id  # type: ignore[attr-defined]
+            new_token = record["_id"]
 
         return (
             [
                 {
                     "type": "AWS::IAM::Role",
-                    "id": role["id"] if aggregator else role.id,  # type: ignore[attr-defined]
-                    "name": role["name"] if aggregator else role.name,  # type: ignore[attr-defined]
-                    "region": role["region"] if aggregator else "global",
+                    "id": role["id"],
+                    "name": role["name"],
+                    "region": role["region"],
                 }
-                for role in role_list
+                for role in collected_role_list
             ],
             new_token,
         )
@@ -136,7 +139,7 @@ class RoleConfigQuery(ConfigQueryModel):
         resource_region: Optional[str] = None,
     ) -> Optional[Dict[str, Any]]:
 
-        role = self.backends[account_id]["global"].roles.get(resource_id, {})
+        role = self.backends[account_id]["global"].roles.get(resource_id)
 
         if not role:
             return None
@@ -158,7 +161,7 @@ class RoleConfigQuery(ConfigQueryModel):
         return config_data
 
 
-class PolicyConfigQuery(ConfigQueryModel):
+class PolicyConfigQuery(ConfigQueryModel[IAMBackend]):
     def list_config_service_resources(
         self,
         account_id: str,
@@ -194,27 +197,27 @@ class PolicyConfigQuery(ConfigQueryModel):
             return [], None
 
         # Filter by resource name or ids
-        if resource_name or resource_ids:
-            filtered_policies = []
-            # resource_name takes precedence over resource_ids
-            if resource_name:
-                for policy in policy_list:
-                    if policy.name == resource_name:
-                        filtered_policies = [policy]
-                        break
-                # but if both are passed, it must be a subset
-                if filtered_policies and resource_ids:
-                    if filtered_policies[0].id not in resource_ids:
-                        return [], None
-
-            else:
-                for policy in policy_list:
-                    if policy.id in resource_ids:  # type: ignore[operator]
-                        filtered_policies.append(policy)
+        # resource_name takes precedence over resource_ids
+        filtered_policies = []
+        if resource_name:
+            for policy in policy_list:
+                if policy.name == resource_name:
+                    filtered_policies = [policy]
+                    break
+            # but if both are passed, it must be a subset
+            if filtered_policies and resource_ids:
+                if filtered_policies[0].id not in resource_ids:
+                    return [], None
 
             # Filtered roles are now the subject for the listing
             policy_list = filtered_policies
 
+        elif resource_ids:
+            for policy in policy_list:
+                if policy.id in resource_ids:
+                    filtered_policies.append(policy)
+            policy_list = filtered_policies
+
         if aggregator:
             # IAM is a little special; Policies are created in us-east-1 (which AWS calls the "global" region)
             # However, the resource will return in the aggregator (in duplicate) for each region in the aggregator
@@ -240,7 +243,6 @@ class PolicyConfigQuery(ConfigQueryModel):
                     duplicate_policy_list.append(
                         {
                             "_id": f"{policy.id}{region}",  # this is only for sorting, isn't returned outside of this function
-                            "type": "AWS::IAM::Policy",
                             "id": policy.id,
                             "name": policy.name,
                             "region": region,
@@ -255,7 +257,15 @@ class PolicyConfigQuery(ConfigQueryModel):
         else:
             # Non-aggregated queries are in the else block, and we can treat these like a normal config resource
             # Pagination logic, sort by role id
-            sorted_policies = sorted(policy_list, key=lambda role: role.id)  # type: ignore[attr-defined]
+            sorted_policies = [
+                {
+                    "_id": policy.id,
+                    "id": policy.id,
+                    "name": policy.name,
+                    "region": "global",
+                }
+                for policy in sorted(policy_list, key=lambda role: role.id)
+            ]
 
         new_token = None
 
@@ -268,27 +278,27 @@ class PolicyConfigQuery(ConfigQueryModel):
                 start = next(
                     index
                     for (index, p) in enumerate(sorted_policies)
-                    if next_token == (p["_id"] if aggregator else p.id)  # type: ignore[attr-defined]
+                    if next_token == p["_id"]
                 )
             except StopIteration:
                 raise InvalidNextTokenException()
 
         # Get the list of items to collect:
-        policy_list = sorted_policies[start : (start + limit)]
+        collected_policy_list = sorted_policies[start : (start + limit)]
 
         if len(sorted_policies) > (start + limit):
             record = sorted_policies[start + limit]
-            new_token = record["_id"] if aggregator else record.id  # type: ignore[attr-defined]
+            new_token = record["_id"]
 
         return (
             [
                 {
                     "type": "AWS::IAM::Policy",
-                    "id": policy["id"] if aggregator else policy.id,  # type: ignore[attr-defined]
-                    "name": policy["name"] if aggregator else policy.name,  # type: ignore[attr-defined]
-                    "region": policy["region"] if aggregator else "global",
+                    "id": policy["id"],
+                    "name": policy["name"],
+                    "region": policy["region"],
                 }
-                for policy in policy_list
+                for policy in collected_policy_list
             ],
             new_token,
         )
diff --git a/moto/iam/models.py b/moto/iam/models.py
index f555874e9..8d6de8062 100644
--- a/moto/iam/models.py
+++ b/moto/iam/models.py
@@ -114,7 +114,7 @@ class MFADevice:
 
     @property
     def enabled_iso_8601(self) -> str:
-        return iso_8601_datetime_without_milliseconds(self.enable_date)  # type: ignore[return-value]
+        return iso_8601_datetime_without_milliseconds(self.enable_date)
 
 
 class VirtualMfaDevice:
@@ -177,7 +177,11 @@ class Policy(CloudFormationModel):
             self.next_version_num = 2
         self.versions = [
             PolicyVersion(
-                self.arn, document, True, self.default_version_id, update_date  # type: ignore
+                self.arn,  # type: ignore[attr-defined]
+                document,
+                True,
+                self.default_version_id,
+                update_date,
             )
         ]
 
@@ -243,7 +247,7 @@ class OpenIDConnectProvider(BaseModel):
 
     @property
     def created_iso_8601(self) -> str:
-        return iso_8601_datetime_without_milliseconds(self.create_date)  # type: ignore[return-value]
+        return iso_8601_datetime_without_milliseconds(self.create_date)
 
     def _validate(
         self, url: str, thumbprint_list: List[str], client_id_list: List[str]
@@ -315,7 +319,7 @@ class PolicyVersion:
     def __init__(
         self,
         policy_arn: str,
-        document: str,
+        document: Optional[str],
         is_default: bool = False,
         version_id: str = "v1",
         create_date: Optional[datetime] = None,
@@ -343,7 +347,7 @@ class ManagedPolicy(Policy, CloudFormationModel):
 
     def attach_to(self, obj: Union["Role", "Group", "User"]) -> None:
         self.attachment_count += 1
-        obj.managed_policies[self.arn] = self  # type: ignore[assignment]
+        obj.managed_policies[self.arn] = self
 
     def detach_from(self, obj: Union["Role", "Group", "User"]) -> None:
         self.attachment_count -= 1
@@ -412,7 +416,7 @@ class ManagedPolicy(Policy, CloudFormationModel):
     def create_from_cloudformation_json(  # type: ignore[misc]
         cls,
         resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
         **kwargs: Any,
@@ -449,7 +453,7 @@ class ManagedPolicy(Policy, CloudFormationModel):
         return policy
 
     def __eq__(self, other: Any) -> bool:
-        return self.arn == other.arn
+        return self.arn == other.arn  # type: ignore[no-any-return]
 
     def __hash__(self) -> int:
         return self.arn.__hash__()
@@ -532,7 +536,7 @@ class InlinePolicy(CloudFormationModel):
     def create_from_cloudformation_json(  # type: ignore[misc]
         cls,
         resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
         **kwargs: Any,
@@ -556,9 +560,9 @@ class InlinePolicy(CloudFormationModel):
     @classmethod
     def update_from_cloudformation_json(  # type: ignore[misc]
         cls,
-        original_resource: Any,
+        original_resource: "InlinePolicy",
         new_resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
     ) -> "InlinePolicy":
@@ -601,7 +605,7 @@ class InlinePolicy(CloudFormationModel):
     def delete_from_cloudformation_json(  # type: ignore[misc]
         cls,
         resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
     ) -> None:
@@ -705,7 +709,7 @@ class Role(CloudFormationModel):
     def create_from_cloudformation_json(  # type: ignore[misc]
         cls,
         resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
         **kwargs: Any,
@@ -736,7 +740,7 @@ class Role(CloudFormationModel):
     def delete_from_cloudformation_json(  # type: ignore[misc]
         cls,
         resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
     ) -> None:
@@ -850,8 +854,8 @@ class Role(CloudFormationModel):
             return self.arn
         raise UnformattedGetAttTemplateException()
 
-    def get_tags(self) -> List[str]:
-        return [self.tags[tag] for tag in self.tags]  # type: ignore
+    def get_tags(self) -> List[Dict[str, str]]:
+        return [self.tags[tag] for tag in self.tags]
 
     @property
     def description_escaped(self) -> str:
@@ -938,7 +942,7 @@ class InstanceProfile(CloudFormationModel):
     def create_from_cloudformation_json(  # type: ignore[misc]
         cls,
         resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
         **kwargs: Any,
@@ -956,7 +960,7 @@ class InstanceProfile(CloudFormationModel):
     def delete_from_cloudformation_json(  # type: ignore[misc]
         cls,
         resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
     ) -> None:
@@ -1060,7 +1064,7 @@ class SigningCertificate(BaseModel):
 
     @property
     def uploaded_iso_8601(self) -> str:
-        return iso_8601_datetime_without_milliseconds(self.upload_date)  # type: ignore
+        return iso_8601_datetime_without_milliseconds(self.upload_date)
 
 
 class AccessKeyLastUsed:
@@ -1071,7 +1075,7 @@ class AccessKeyLastUsed:
 
     @property
     def timestamp(self) -> str:
-        return iso_8601_datetime_without_milliseconds(self._timestamp)  # type: ignore
+        return iso_8601_datetime_without_milliseconds(self._timestamp)
 
     def strftime(self, date_format: str) -> str:
         return self._timestamp.strftime(date_format)
@@ -1105,7 +1109,7 @@ class AccessKey(CloudFormationModel):
 
     @property
     def created_iso_8601(self) -> str:
-        return iso_8601_datetime_without_milliseconds(self.create_date)  # type: ignore
+        return iso_8601_datetime_without_milliseconds(self.create_date)
 
     @classmethod
     def has_cfn_attr(cls, attr: str) -> bool:
@@ -1130,7 +1134,7 @@ class AccessKey(CloudFormationModel):
     def create_from_cloudformation_json(  # type: ignore[misc]
         cls,
         resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
         **kwargs: Any,
@@ -1146,9 +1150,9 @@ class AccessKey(CloudFormationModel):
     @classmethod
     def update_from_cloudformation_json(  # type: ignore[misc]
         cls,
-        original_resource: Any,
+        original_resource: "AccessKey",
         new_resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
     ) -> "AccessKey":
@@ -1170,14 +1174,16 @@ class AccessKey(CloudFormationModel):
             properties = cloudformation_json.get("Properties", {})
             status = properties.get("Status")
             return iam_backends[account_id]["global"].update_access_key(
-                original_resource.user_name, original_resource.access_key_id, status
+                original_resource.user_name,  # type: ignore[arg-type]
+                original_resource.access_key_id,
+                status,
             )
 
     @classmethod
     def delete_from_cloudformation_json(  # type: ignore[misc]
         cls,
         resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
     ) -> None:
@@ -1209,7 +1215,7 @@ class SshPublicKey(BaseModel):
 
     @property
     def uploaded_iso_8601(self) -> str:
-        return iso_8601_datetime_without_milliseconds(self.upload_date)  # type: ignore
+        return iso_8601_datetime_without_milliseconds(self.upload_date)
 
 
 class Group(BaseModel):
@@ -1221,7 +1227,7 @@ class Group(BaseModel):
         self.create_date = utcnow()
 
         self.users: List[User] = []
-        self.managed_policies: Dict[str, str] = {}
+        self.managed_policies: Dict[str, ManagedPolicy] = {}
         self.policies: Dict[str, str] = {}
 
     @property
@@ -1281,7 +1287,7 @@ class User(CloudFormationModel):
         self.create_date = utcnow()
         self.mfa_devices: Dict[str, MFADevice] = {}
         self.policies: Dict[str, str] = {}
-        self.managed_policies: Dict[str, Dict[str, str]] = {}
+        self.managed_policies: Dict[str, ManagedPolicy] = {}
         self.access_keys: List[AccessKey] = []
         self.ssh_public_keys: List[SshPublicKey] = []
         self.password: Optional[str] = None
@@ -1510,7 +1516,7 @@ class User(CloudFormationModel):
     def create_from_cloudformation_json(  # type: ignore[misc]
         cls,
         resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
         **kwargs: Any,
@@ -1523,9 +1529,9 @@ class User(CloudFormationModel):
     @classmethod
     def update_from_cloudformation_json(  # type: ignore[misc]
         cls,
-        original_resource: Any,
+        original_resource: "User",
         new_resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
     ) -> "User":
@@ -1556,7 +1562,7 @@ class User(CloudFormationModel):
     def delete_from_cloudformation_json(  # type: ignore[misc]
         cls,
         resource_name: str,
-        cloudformation_json: Any,
+        cloudformation_json: Dict[str, Any],
         account_id: str,
         region_name: str,
     ) -> None:
@@ -1796,10 +1802,10 @@ class IAMBackend(BaseBackend):
     def __init__(
         self,
         region_name: str,
-        account_id: Optional[str] = None,
+        account_id: str,
         aws_policies: Optional[List[ManagedPolicy]] = None,
     ):
-        super().__init__(region_name=region_name, account_id=account_id)  # type: ignore
+        super().__init__(region_name=region_name, account_id=account_id)
         self.instance_profiles: Dict[str, InstanceProfile] = {}
         self.roles: Dict[str, Role] = {}
         self.certificates: Dict[str, Certificate] = {}
@@ -1840,7 +1846,7 @@ class IAMBackend(BaseBackend):
         # Do not reset these policies, as they take a long time to load
         aws_policies = self.aws_managed_policies
         self.__dict__ = {}
-        self.__init__(region_name, account_id, aws_policies)  # type: ignore[misc]
+        IAMBackend.__init__(self, region_name, account_id, aws_policies)
 
     def initialize_service_roles(self) -> None:
         pass
@@ -2828,8 +2834,9 @@ class IAMBackend(BaseBackend):
     def delete_access_key_by_name(self, name: str) -> None:
         key = self.access_keys[name]
         try:  # User may have been deleted before their access key...
-            user = self.get_user(key.user_name)  # type: ignore
-            user.delete_access_key(key.access_key_id)
+            if key.user_name is not None:
+                user = self.get_user(key.user_name)
+                user.delete_access_key(key.access_key_id)
         except NoSuchEntity:
             pass
         del self.access_keys[name]
diff --git a/moto/moto_proxy/proxy3.py b/moto/moto_proxy/proxy3.py
index a6289efb9..6cb77bbd6 100644
--- a/moto/moto_proxy/proxy3.py
+++ b/moto/moto_proxy/proxy3.py
@@ -70,7 +70,7 @@ class MotoRequestHandler:
         request = AWSPreparedRequest(
             method, full_url, headers, body, stream_output=False
         )
-        request.form_data = form_data
+        request.form_data = form_data  # type: ignore[attr-defined]
         return handler(request, full_url, headers)
 
 
@@ -160,7 +160,7 @@ class ProxyRequestHandler(BaseHTTPRequestHandler):
                 host=host,
                 path=path,
                 headers=req.headers,
-                body=req_body,
+                body=req_body,  # type: ignore[arg-type]
                 form_data=form_data,
             )
             debug("\t=====RESPONSE========")
diff --git a/moto/resourcegroupstaggingapi/models.py b/moto/resourcegroupstaggingapi/models.py
index 5e904b9c6..41219e4d5 100644
--- a/moto/resourcegroupstaggingapi/models.py
+++ b/moto/resourcegroupstaggingapi/models.py
@@ -18,6 +18,7 @@ from moto.moto_api._internal import mock_random
 from moto.rds.models import RDSBackend, rds_backends
 from moto.redshift.models import RedshiftBackend, redshift_backends
 from moto.s3.models import S3Backend, s3_backends
+from moto.sqs.models import SQSBackend, sqs_backends
 from moto.utilities.tagging_service import TaggingService
 
 # Left: EC2 ElastiCache RDS ELB CloudFront WorkSpaces Lambda EMR Glacier Kinesis Redshift Route53
@@ -95,6 +96,10 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
     def acm_backend(self) -> AWSCertificateManagerBackend:
         return acm_backends[self.account_id][self.region_name]
 
+    @property
+    def sqs_backend(self) -> SQSBackend:
+        return sqs_backends[self.account_id][self.region_name]
+
     def _get_resources_generator(
         self,
         tag_filters: Optional[List[Dict[str, Any]]] = None,
@@ -442,6 +447,17 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
         # RedShift Snapshot
         # RedShift Subnet group
 
+        # SQS
+        if not resource_type_filters or "sqs" in resource_type_filters:
+            for queue in self.sqs_backend.queues.values():
+                tags = format_tags(queue.tags)
+                if not tags or not tag_filter(
+                    tags
+                ):  # Skip if no tags, or invalid filter
+                    continue
+
+                yield {"ResourceARN": f"{queue.queue_arn}", "Tags": tags}
+
         # VPC
         if (
             not resource_type_filters
diff --git a/moto/s3/config.py b/moto/s3/config.py
index 45258f9c3..0db38da5f 100644
--- a/moto/s3/config.py
+++ b/moto/s3/config.py
@@ -4,9 +4,10 @@ from typing import Any, Dict, List, Optional, Tuple
 from moto.core.common_models import ConfigQueryModel
 from moto.core.exceptions import InvalidNextTokenException
 from moto.s3 import s3_backends
+from moto.s3.models import S3Backend
 
 
-class S3ConfigQuery(ConfigQueryModel):
+class S3ConfigQuery(ConfigQueryModel[S3Backend]):
     def list_config_service_resources(
         self,
         account_id: str,
@@ -103,7 +104,7 @@ class S3ConfigQuery(ConfigQueryModel):
         resource_region: Optional[str] = None,
     ) -> Optional[Dict[str, Any]]:
         # Get the bucket:
-        bucket = self.backends[account_id]["global"].buckets.get(resource_id, {})
+        bucket = self.backends[account_id]["global"].buckets.get(resource_id)
 
         if not bucket:
             return None
diff --git a/moto/s3control/config.py b/moto/s3control/config.py
index 8d30236a0..0f17b4a88 100644
--- a/moto/s3control/config.py
+++ b/moto/s3control/config.py
@@ -7,9 +7,10 @@ from moto.core.common_models import ConfigQueryModel
 from moto.core.exceptions import InvalidNextTokenException
 from moto.core.utils import unix_time, utcnow
 from moto.s3control import s3control_backends
+from moto.s3control.models import S3ControlBackend
 
 
-class S3AccountPublicAccessBlockConfigQuery(ConfigQueryModel):
+class S3AccountPublicAccessBlockConfigQuery(ConfigQueryModel[S3ControlBackend]):
     def list_config_service_resources(
         self,
         account_id: str,
diff --git a/moto/ssm/resources/regions.json b/moto/ssm/resources/regions.json
index f6f690c72..0cc128428 100644
--- a/moto/ssm/resources/regions.json
+++ b/moto/ssm/resources/regions.json
@@ -562,6 +562,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.af-south-1.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -793,6 +799,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.af-south-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -2123,6 +2135,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.ap-east-1.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -2363,6 +2381,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-east-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -4074,6 +4098,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.ap-northeast-1.api.aws"
+                }
+              },
               "elastic-inference": {
                 "Value": "elastic-inference",
                 "endpoint": {
@@ -4419,6 +4449,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-northeast-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -6636,6 +6672,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.ap-northeast-2.api.aws"
+                }
+              },
               "elastic-inference": {
                 "Value": "elastic-inference",
                 "endpoint": {
@@ -6948,6 +6990,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-northeast-2.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -8685,6 +8733,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.ap-northeast-3.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -8898,6 +8952,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-northeast-3.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -10398,6 +10458,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.ap-south-1.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -10689,6 +10755,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-south-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -11796,6 +11868,9 @@
                   "Value": "HTTPS"
                 }
               },
+              "thinclient": {
+                "Value": "thinclient"
+              },
               "transcribe": {
                 "Value": "transcribe",
                 "endpoint": {
@@ -12346,6 +12421,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.ap-south-2.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -13918,6 +13999,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.ap-southeast-1.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -14272,6 +14359,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-southeast-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -16507,6 +16600,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.ap-southeast-2.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -16861,6 +16960,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-southeast-2.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -18764,6 +18869,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.ap-southeast-3.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -18845,6 +18956,9 @@
                   "Value": "HTTPS"
                 }
               },
+              "fargate": {
+                "Value": "fargate"
+              },
               "firehose": {
                 "Value": "firehose",
                 "endpoint": {
@@ -18971,6 +19085,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-southeast-3.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -20025,6 +20145,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.ap-southeast-4.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -21508,6 +21634,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.ca-central-1.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -21790,6 +21922,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.ca-central-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -22876,6 +23014,9 @@
                   "Value": "HTTPS"
                 }
               },
+              "thinclient": {
+                "Value": "thinclient"
+              },
               "tnb": {
                 "Value": "tnb",
                 "endpoint": {
@@ -24073,6 +24214,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "redshift-serverless": {
+                "Value": "redshift-serverless",
+                "endpoint": {
+                  "Value": "redshift-serverless.cn-north-1.amazonaws.com.cn"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "resource-groups": {
                 "Value": "resource-groups",
                 "endpoint": {
@@ -26657,6 +26807,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.eu-central-1.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -26993,6 +27149,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-central-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -27848,6 +28010,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "repostspace": {
+                "Value": "repostspace",
+                "endpoint": {
+                  "Value": "repostspace.eu-central-1.amazonaws.com"
+                }
+              },
               "resiliencehub": {
                 "Value": "resiliencehub",
                 "endpoint": {
@@ -28298,6 +28466,9 @@
                   "Value": "HTTPS"
                 }
               },
+              "thinclient": {
+                "Value": "thinclient"
+              },
               "timestream": {
                 "Value": "timestream"
               },
@@ -28916,6 +29087,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.eu-central-2.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -29090,6 +29267,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-central-2.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -30321,6 +30504,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.eu-north-1.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -30588,6 +30777,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-north-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -32221,6 +32416,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.eu-south-1.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -32443,6 +32644,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-south-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -33554,6 +33761,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.eu-south-2.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -35088,6 +35301,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.eu-west-1.api.aws"
+                }
+              },
               "elastic-inference": {
                 "Value": "elastic-inference",
                 "endpoint": {
@@ -35469,6 +35688,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-west-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -36837,6 +37062,9 @@
                   "Value": "HTTPS"
                 }
               },
+              "thinclient": {
+                "Value": "thinclient"
+              },
               "timestream": {
                 "Value": "timestream"
               },
@@ -37867,6 +38095,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.eu-west-2.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -38167,6 +38401,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-west-2.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -39277,6 +39517,9 @@
                   "Value": "HTTPS"
                 }
               },
+              "thinclient": {
+                "Value": "thinclient"
+              },
               "transcribe": {
                 "Value": "transcribe",
                 "endpoint": {
@@ -40108,6 +40351,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.eu-west-3.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -40339,6 +40588,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-west-3.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -41816,6 +42071,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.il-central-1.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -42545,6 +42806,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "workspaces": {
+                "Value": "workspaces",
+                "endpoint": {
+                  "Value": "workspaces.il-central-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "xray": {
                 "Value": "xray",
                 "endpoint": {
@@ -42996,6 +43266,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.me-central-1.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -44347,6 +44623,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.me-south-1.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -44587,6 +44869,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.me-south-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -46067,6 +46355,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.sa-east-1.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -46313,6 +46607,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.sa-east-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -48113,6 +48413,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "cost-optimization-hub": {
+                "Value": "cost-optimization-hub",
+                "endpoint": {
+                  "Value": "cost-optimization-hub.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "costexplorer": {
                 "Value": "costexplorer",
                 "endpoint": {
@@ -48377,6 +48686,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.us-east-1.api.aws"
+                }
+              },
               "elastic-inference": {
                 "Value": "elastic-inference",
                 "endpoint": {
@@ -48767,6 +49082,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.us-east-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -50243,6 +50564,9 @@
                   "Value": "HTTPS"
                 }
               },
+              "thinclient": {
+                "Value": "thinclient"
+              },
               "timestream": {
                 "Value": "timestream"
               },
@@ -51269,6 +51593,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.us-east-2.api.aws"
+                }
+              },
               "elastic-inference": {
                 "Value": "elastic-inference",
                 "endpoint": {
@@ -51641,6 +51971,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.us-east-2.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -53064,6 +53400,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "arc-zonal-shift": {
+                "Value": "arc-zonal-shift",
+                "endpoint": {
+                  "Value": "arc-zonal-shift.us-gov-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "artifact": {
                 "Value": "artifact"
               },
@@ -53328,6 +53673,15 @@
                   "Value": "HTTPS, HTTP"
                 }
               },
+              "drs": {
+                "Value": "drs",
+                "endpoint": {
+                  "Value": "drs.us-gov-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "ds": {
                 "Value": "ds",
                 "endpoint": {
@@ -53628,6 +53982,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.us-gov-east-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -54433,6 +54793,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "arc-zonal-shift": {
+                "Value": "arc-zonal-shift",
+                "endpoint": {
+                  "Value": "arc-zonal-shift.us-gov-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "artifact": {
                 "Value": "artifact"
               },
@@ -54760,6 +55129,15 @@
                   "Value": "HTTPS, HTTP"
                 }
               },
+              "drs": {
+                "Value": "drs",
+                "endpoint": {
+                  "Value": "drs.us-gov-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "ds": {
                 "Value": "ds",
                 "endpoint": {
@@ -55069,6 +55447,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.us-gov-west-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -56582,6 +56966,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.us-west-1.api.aws"
+                }
+              },
               "elasticache": {
                 "Value": "elasticache",
                 "endpoint": {
@@ -56846,6 +57236,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.us-west-1.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -57936,9 +58332,6 @@
               "usw2-las1-az1": {
                 "Value": "usw2-las1-az1"
               },
-              "usw2-las1-az2": {
-                "Value": "usw2-las1-az2"
-              },
               "usw2-lax1-az1": {
                 "Value": "usw2-lax1-az1"
               },
@@ -58868,6 +59261,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "eks-auth": {
+                "Value": "eks-auth",
+                "endpoint": {
+                  "Value": "eks-auth.us-west-2.api.aws"
+                }
+              },
               "elastic-inference": {
                 "Value": "elastic-inference",
                 "endpoint": {
@@ -59258,6 +59657,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "inspector-scan": {
+                "Value": "inspector-scan",
+                "endpoint": {
+                  "Value": "inspector-scan.us-west-2.amazonaws.com"
+                }
+              },
               "inspector2": {
                 "Value": "inspector2",
                 "endpoint": {
@@ -60161,6 +60566,12 @@
                   "Value": "HTTPS"
                 }
               },
+              "repostspace": {
+                "Value": "repostspace",
+                "endpoint": {
+                  "Value": "repostspace.us-west-2.amazonaws.com"
+                }
+              },
               "resiliencehub": {
                 "Value": "resiliencehub",
                 "endpoint": {
@@ -60659,6 +61070,9 @@
                   "Value": "HTTPS"
                 }
               },
+              "thinclient": {
+                "Value": "thinclient"
+              },
               "timestream": {
                 "Value": "timestream"
               },
diff --git a/moto/ssm/resources/services.json b/moto/ssm/resources/services.json
index 78da2d2ce..0c2620117 100644
--- a/moto/ssm/resources/services.json
+++ b/moto/ssm/resources/services.json
@@ -4982,6 +4982,24 @@
                   "Value": "HTTPS"
                 }
               },
+              "us-gov-east-1": {
+                "Value": "us-gov-east-1",
+                "endpoint": {
+                  "Value": "arc-zonal-shift.us-gov-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "us-gov-west-1": {
+                "Value": "us-gov-west-1",
+                "endpoint": {
+                  "Value": "arc-zonal-shift.us-gov-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "us-west-1": {
                 "Value": "us-west-1",
                 "endpoint": {
@@ -15069,6 +15087,23 @@
               }
             }
           },
+          "cost-optimization-hub": {
+            "Value": "cost-optimization-hub",
+            "longName": {
+              "Value": "Cost Optimization Hub"
+            },
+            "regions": {
+              "us-east-1": {
+                "Value": "us-east-1",
+                "endpoint": {
+                  "Value": "cost-optimization-hub.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              }
+            }
+          },
           "costexplorer": {
             "Value": "costexplorer",
             "longName": {
@@ -18016,6 +18051,24 @@
                   "Value": "HTTPS"
                 }
               },
+              "us-gov-east-1": {
+                "Value": "us-gov-east-1",
+                "endpoint": {
+                  "Value": "drs.us-gov-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "us-gov-west-1": {
+                "Value": "us-gov-west-1",
+                "endpoint": {
+                  "Value": "drs.us-gov-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "us-west-1": {
                 "Value": "us-west-1",
                 "endpoint": {
@@ -20741,6 +20794,182 @@
               }
             }
           },
+          "eks-auth": {
+            "Value": "eks-auth",
+            "longName": {
+              "Value": "Amazon EKS Auth"
+            },
+            "regions": {
+              "af-south-1": {
+                "Value": "af-south-1",
+                "endpoint": {
+                  "Value": "eks-auth.af-south-1.api.aws"
+                }
+              },
+              "ap-east-1": {
+                "Value": "ap-east-1",
+                "endpoint": {
+                  "Value": "eks-auth.ap-east-1.api.aws"
+                }
+              },
+              "ap-northeast-1": {
+                "Value": "ap-northeast-1",
+                "endpoint": {
+                  "Value": "eks-auth.ap-northeast-1.api.aws"
+                }
+              },
+              "ap-northeast-2": {
+                "Value": "ap-northeast-2",
+                "endpoint": {
+                  "Value": "eks-auth.ap-northeast-2.api.aws"
+                }
+              },
+              "ap-northeast-3": {
+                "Value": "ap-northeast-3",
+                "endpoint": {
+                  "Value": "eks-auth.ap-northeast-3.api.aws"
+                }
+              },
+              "ap-south-1": {
+                "Value": "ap-south-1",
+                "endpoint": {
+                  "Value": "eks-auth.ap-south-1.api.aws"
+                }
+              },
+              "ap-south-2": {
+                "Value": "ap-south-2",
+                "endpoint": {
+                  "Value": "eks-auth.ap-south-2.api.aws"
+                }
+              },
+              "ap-southeast-1": {
+                "Value": "ap-southeast-1",
+                "endpoint": {
+                  "Value": "eks-auth.ap-southeast-1.api.aws"
+                }
+              },
+              "ap-southeast-2": {
+                "Value": "ap-southeast-2",
+                "endpoint": {
+                  "Value": "eks-auth.ap-southeast-2.api.aws"
+                }
+              },
+              "ap-southeast-3": {
+                "Value": "ap-southeast-3",
+                "endpoint": {
+                  "Value": "eks-auth.ap-southeast-3.api.aws"
+                }
+              },
+              "ap-southeast-4": {
+                "Value": "ap-southeast-4",
+                "endpoint": {
+                  "Value": "eks-auth.ap-southeast-4.api.aws"
+                }
+              },
+              "ca-central-1": {
+                "Value": "ca-central-1",
+                "endpoint": {
+                  "Value": "eks-auth.ca-central-1.api.aws"
+                }
+              },
+              "eu-central-1": {
+                "Value": "eu-central-1",
+                "endpoint": {
+                  "Value": "eks-auth.eu-central-1.api.aws"
+                }
+              },
+              "eu-central-2": {
+                "Value": "eu-central-2",
+                "endpoint": {
+                  "Value": "eks-auth.eu-central-2.api.aws"
+                }
+              },
+              "eu-north-1": {
+                "Value": "eu-north-1",
+                "endpoint": {
+                  "Value": "eks-auth.eu-north-1.api.aws"
+                }
+              },
+              "eu-south-1": {
+                "Value": "eu-south-1",
+                "endpoint": {
+                  "Value": "eks-auth.eu-south-1.api.aws"
+                }
+              },
+              "eu-south-2": {
+                "Value": "eu-south-2",
+                "endpoint": {
+                  "Value": "eks-auth.eu-south-2.api.aws"
+                }
+              },
+              "eu-west-1": {
+                "Value": "eu-west-1",
+                "endpoint": {
+                  "Value": "eks-auth.eu-west-1.api.aws"
+                }
+              },
+              "eu-west-2": {
+                "Value": "eu-west-2",
+                "endpoint": {
+                  "Value": "eks-auth.eu-west-2.api.aws"
+                }
+              },
+              "eu-west-3": {
+                "Value": "eu-west-3",
+                "endpoint": {
+                  "Value": "eks-auth.eu-west-3.api.aws"
+                }
+              },
+              "il-central-1": {
+                "Value": "il-central-1",
+                "endpoint": {
+                  "Value": "eks-auth.il-central-1.api.aws"
+                }
+              },
+              "me-central-1": {
+                "Value": "me-central-1",
+                "endpoint": {
+                  "Value": "eks-auth.me-central-1.api.aws"
+                }
+              },
+              "me-south-1": {
+                "Value": "me-south-1",
+                "endpoint": {
+                  "Value": "eks-auth.me-south-1.api.aws"
+                }
+              },
+              "sa-east-1": {
+                "Value": "sa-east-1",
+                "endpoint": {
+                  "Value": "eks-auth.sa-east-1.api.aws"
+                }
+              },
+              "us-east-1": {
+                "Value": "us-east-1",
+                "endpoint": {
+                  "Value": "eks-auth.us-east-1.api.aws"
+                }
+              },
+              "us-east-2": {
+                "Value": "us-east-2",
+                "endpoint": {
+                  "Value": "eks-auth.us-east-2.api.aws"
+                }
+              },
+              "us-west-1": {
+                "Value": "us-west-1",
+                "endpoint": {
+                  "Value": "eks-auth.us-west-1.api.aws"
+                }
+              },
+              "us-west-2": {
+                "Value": "us-west-2",
+                "endpoint": {
+                  "Value": "eks-auth.us-west-2.api.aws"
+                }
+              }
+            }
+          },
           "elastic-inference": {
             "Value": "elastic-inference",
             "longName": {
@@ -23635,6 +23864,9 @@
               "ap-southeast-2": {
                 "Value": "ap-southeast-2"
               },
+              "ap-southeast-3": {
+                "Value": "ap-southeast-3"
+              },
               "ap-southeast-4": {
                 "Value": "ap-southeast-4"
               },
@@ -29600,6 +29832,164 @@
               }
             }
           },
+          "inspector-scan": {
+            "Value": "inspector-scan",
+            "longName": {
+              "Value": "Inspector Scan"
+            },
+            "regions": {
+              "af-south-1": {
+                "Value": "af-south-1",
+                "endpoint": {
+                  "Value": "inspector-scan.af-south-1.amazonaws.com"
+                }
+              },
+              "ap-east-1": {
+                "Value": "ap-east-1",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-east-1.amazonaws.com"
+                }
+              },
+              "ap-northeast-1": {
+                "Value": "ap-northeast-1",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-northeast-1.amazonaws.com"
+                }
+              },
+              "ap-northeast-2": {
+                "Value": "ap-northeast-2",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-northeast-2.amazonaws.com"
+                }
+              },
+              "ap-northeast-3": {
+                "Value": "ap-northeast-3",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-northeast-3.amazonaws.com"
+                }
+              },
+              "ap-south-1": {
+                "Value": "ap-south-1",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-south-1.amazonaws.com"
+                }
+              },
+              "ap-southeast-1": {
+                "Value": "ap-southeast-1",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-southeast-1.amazonaws.com"
+                }
+              },
+              "ap-southeast-2": {
+                "Value": "ap-southeast-2",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-southeast-2.amazonaws.com"
+                }
+              },
+              "ap-southeast-3": {
+                "Value": "ap-southeast-3",
+                "endpoint": {
+                  "Value": "inspector-scan.ap-southeast-3.amazonaws.com"
+                }
+              },
+              "ca-central-1": {
+                "Value": "ca-central-1",
+                "endpoint": {
+                  "Value": "inspector-scan.ca-central-1.amazonaws.com"
+                }
+              },
+              "eu-central-1": {
+                "Value": "eu-central-1",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-central-1.amazonaws.com"
+                }
+              },
+              "eu-central-2": {
+                "Value": "eu-central-2",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-central-2.amazonaws.com"
+                }
+              },
+              "eu-north-1": {
+                "Value": "eu-north-1",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-north-1.amazonaws.com"
+                }
+              },
+              "eu-south-1": {
+                "Value": "eu-south-1",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-south-1.amazonaws.com"
+                }
+              },
+              "eu-west-1": {
+                "Value": "eu-west-1",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-west-1.amazonaws.com"
+                }
+              },
+              "eu-west-2": {
+                "Value": "eu-west-2",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-west-2.amazonaws.com"
+                }
+              },
+              "eu-west-3": {
+                "Value": "eu-west-3",
+                "endpoint": {
+                  "Value": "inspector-scan.eu-west-3.amazonaws.com"
+                }
+              },
+              "me-south-1": {
+                "Value": "me-south-1",
+                "endpoint": {
+                  "Value": "inspector-scan.me-south-1.amazonaws.com"
+                }
+              },
+              "sa-east-1": {
+                "Value": "sa-east-1",
+                "endpoint": {
+                  "Value": "inspector-scan.sa-east-1.amazonaws.com"
+                }
+              },
+              "us-east-1": {
+                "Value": "us-east-1",
+                "endpoint": {
+                  "Value": "inspector-scan.us-east-1.amazonaws.com"
+                }
+              },
+              "us-east-2": {
+                "Value": "us-east-2",
+                "endpoint": {
+                  "Value": "inspector-scan.us-east-2.amazonaws.com"
+                }
+              },
+              "us-gov-east-1": {
+                "Value": "us-gov-east-1",
+                "endpoint": {
+                  "Value": "inspector-scan.us-gov-east-1.amazonaws.com"
+                }
+              },
+              "us-gov-west-1": {
+                "Value": "us-gov-west-1",
+                "endpoint": {
+                  "Value": "inspector-scan.us-gov-west-1.amazonaws.com"
+                }
+              },
+              "us-west-1": {
+                "Value": "us-west-1",
+                "endpoint": {
+                  "Value": "inspector-scan.us-west-1.amazonaws.com"
+                }
+              },
+              "us-west-2": {
+                "Value": "us-west-2",
+                "endpoint": {
+                  "Value": "inspector-scan.us-west-2.amazonaws.com"
+                }
+              }
+            }
+          },
           "inspector2": {
             "Value": "inspector2",
             "longName": {
@@ -47130,6 +47520,10 @@
             }
           },
           "redshift-serverless": {
+            "Value": "redshift-serverless",
+            "longName": {
+              "Value": "Amazon Redshift Serverless"
+            },
             "regions": {
               "ap-south-1": {
                 "Value": "ap-south-1",
@@ -47149,6 +47543,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "cn-north-1": {
+                "Value": "cn-north-1",
+                "endpoint": {
+                  "Value": "redshift-serverless.cn-north-1.amazonaws.com.cn"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "eu-west-3": {
                 "Value": "eu-west-3",
                 "endpoint": {
@@ -47315,6 +47718,26 @@
               }
             }
           },
+          "repostspace": {
+            "Value": "repostspace",
+            "longName": {
+              "Value": "AWS re:Post Private"
+            },
+            "regions": {
+              "eu-central-1": {
+                "Value": "eu-central-1",
+                "endpoint": {
+                  "Value": "repostspace.eu-central-1.amazonaws.com"
+                }
+              },
+              "us-west-2": {
+                "Value": "us-west-2",
+                "endpoint": {
+                  "Value": "repostspace.us-west-2.amazonaws.com"
+                }
+              }
+            }
+          },
           "resiliencehub": {
             "Value": "resiliencehub",
             "longName": {
@@ -59442,6 +59865,38 @@
               }
             }
           },
+          "thinclient": {
+            "Value": "thinclient",
+            "longName": {
+              "Value": "Amazon WorkSpaces Thin Client"
+            },
+            "marketingHomeURL": {
+              "Value": "https://aws.amazon.com/workspaces/thin-client/"
+            },
+            "regions": {
+              "ap-south-1": {
+                "Value": "ap-south-1"
+              },
+              "ca-central-1": {
+                "Value": "ca-central-1"
+              },
+              "eu-central-1": {
+                "Value": "eu-central-1"
+              },
+              "eu-west-1": {
+                "Value": "eu-west-1"
+              },
+              "eu-west-2": {
+                "Value": "eu-west-2"
+              },
+              "us-east-1": {
+                "Value": "us-east-1"
+              },
+              "us-west-2": {
+                "Value": "us-west-2"
+              }
+            }
+          },
           "timestream": {
             "Value": "timestream",
             "longName": {
@@ -62931,6 +63386,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "il-central-1": {
+                "Value": "il-central-1",
+                "endpoint": {
+                  "Value": "workspaces.il-central-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "sa-east-1": {
                 "Value": "sa-east-1",
                 "endpoint": {
diff --git a/requirements-dev.txt b/requirements-dev.txt
index ec4768281..509bc1ce8 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -12,6 +12,10 @@ packaging
 build
 prompt_toolkit
 
+# type stubs that mypy doesn't install automatically
+botocore-stubs
+
+
 # typing_extensions is currently used for:
 # Protocol  (3.8+)
 # ParamSpec  (3.10+)


Test patch:
diff --git a/.github/workflows/tests_sdk_dotnet.yml b/.github/workflows/tests_sdk_dotnet.yml
index cf84b9f7e..2c10a8a1b 100644
--- a/.github/workflows/tests_sdk_dotnet.yml
+++ b/.github/workflows/tests_sdk_dotnet.yml
@@ -19,7 +19,7 @@ jobs:
         python -m build
         docker run --rm -t --name motoserver -e TEST_SERVER_MODE=true -e AWS_SECRET_ACCESS_KEY=server_secret -e AWS_ACCESS_KEY_ID=server_key -v `pwd`:/moto -p 5000:5000 -v /var/run/docker.sock:/var/run/docker.sock python:3.10-slim /moto/scripts/ci_moto_server.sh &
         python scripts/ci_wait_for_server.py
-    - uses: actions/setup-dotnet@v3
+    - uses: actions/setup-dotnet@v4
     - uses: actions/cache@v3
       with:
         path: ~/.nuget/packages
diff --git a/.github/workflows/tests_sdk_java.yml b/.github/workflows/tests_sdk_java.yml
index 6e8199648..b2b8a523f 100644
--- a/.github/workflows/tests_sdk_java.yml
+++ b/.github/workflows/tests_sdk_java.yml
@@ -19,7 +19,7 @@ jobs:
         python -m build
         docker run --rm -t --name motoserver -e TEST_SERVER_MODE=true -e AWS_SECRET_ACCESS_KEY=server_secret -e AWS_ACCESS_KEY_ID=server_key -v `pwd`:/moto -p 5000:5000 -v /var/run/docker.sock:/var/run/docker.sock python:3.10-slim /moto/scripts/ci_moto_server.sh &
         python scripts/ci_wait_for_server.py
-    - uses: actions/setup-java@v3
+    - uses: actions/setup-java@v4
       with:
         distribution: 'temurin'
         java-version: '17'
diff --git a/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py b/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py
index 980c6b9d3..88fc908c1 100644
--- a/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py
+++ b/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py
@@ -14,6 +14,7 @@ from moto import (
     mock_lambda,
     mock_resourcegroupstaggingapi,
     mock_s3,
+    mock_sqs,
 )
 from tests import EXAMPLE_AMI_ID, EXAMPLE_AMI_ID2
 
@@ -715,6 +716,37 @@ def test_get_resources_lambda():
     assert_response(resp, [rectangle_arn])
 
 
+@mock_sqs
+@mock_resourcegroupstaggingapi
+def test_get_resources_sqs():
+    sqs = boto3.resource("sqs", region_name="eu-central-1")
+
+    # Create two tagged SQS queues
+    for i in range(1, 3):
+        i_str = str(i)
+
+        sqs.create_queue(
+            QueueName="sqs-tag-value-" + i_str,
+            tags={
+                "Test": i_str,
+            },
+        )
+
+    rtapi = boto3.client("resourcegroupstaggingapi", region_name="eu-central-1")
+
+    # Basic test
+    resp = rtapi.get_resources(ResourceTypeFilters=["sqs"])
+    assert len(resp["ResourceTagMappingList"]) == 2
+
+    # Test tag filtering
+    resp = rtapi.get_resources(
+        ResourceTypeFilters=["sqs"],
+        TagFilters=[{"Key": "Test", "Values": ["1"]}],
+    )
+    assert len(resp["ResourceTagMappingList"]) == 1
+    assert {"Key": "Test", "Value": "1"} in resp["ResourceTagMappingList"][0]["Tags"]
+
+
 @mock_resourcegroupstaggingapi
 def test_tag_resources_for_unknown_service():
     rtapi = boto3.client("resourcegroupstaggingapi", region_name="us-west-2")