We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
SSM - labeling more than 10 parameters does not work right
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Current Behavior

Adding and labeling more than 10 parameters only labels (or only returns) the first 10 labeled parameters.

### Expected Behavior

Adding and labeling more than 10 parameters should add & then return all the parameters.

### How are you starting LocalStack?

With a docker-compose file

### Steps To Reproduce

#### How are you starting localstack (e.g., `bin/localstack` command, arguments, or `docker-compose.yml`)

docker-compose.yml

#### Client commands (e.g., AWS SDK code snippet, or sequence of "awslocal" commands)

```
params = [ ... ]  # create a list of **more** than 10 parameters ( Name + Value)
for param of params:
       # add the parameter (returns 200)
        res = ssm.put_parameter(Name=param["Name"], Value=param["Value], Type='String')

       # label the returned version with 'latest' (returns 200)
        label_res = ssm.label_parameter_version(Name=path, ParameterVersion=res['Version'], Labels=['latest'])

       # get the added parameter (returns the parameter successfully)
        prm = ssm.get_parameter(Name=path)

# get all parameters with the 'latest' label - this returns the first 10 parameters (although `MaxResults` is 100), and also doesn't return a `NextToken` property to iterate through the next batch of parameters.
ps = ssm.get_parameters_by_path(Path=base_path,
                                        ParameterFilters=[  {  'Key': 'Label',  'Values': [  'latest'  ] } ],
                                        MaxResults=100) 

```


### Environment

```markdown
- OS: Windows 10
- LocalStack: 0.12.17.5
```


### Anything else?

_No response_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `localstack/services/ssm/ssm_listener.py`
Content:
```
1 import json
2 import logging
3 import time
4 import traceback
5 
6 from requests.models import Request
7 
8 from localstack.utils.aws import aws_stack
9 from localstack.utils.bootstrap import is_api_enabled
10 from localstack.utils.common import to_str
11 from localstack.utils.persistence import PersistingProxyListener
12 
13 # logger
14 LOG = logging.getLogger(__name__)
15 
16 ACTION_PUT_PARAM = "AmazonSSM.PutParameter"
17 ACTION_GET_PARAM = "AmazonSSM.GetParameter"
18 ACTION_GET_PARAMS = "AmazonSSM.GetParameters"
19 ACTION_DELETE_PARAM = "AmazonSSM.DeleteParameter"
20 ACTION_GET_PARAMS_BY_PATH = "AmazonSSM.GetParametersByPath"
21 ACTION_LABEL_PARAM_VERSION = "AmazonSSM.LabelParameterVersion"
22 
23 # maps SSM target header names to operation names used in EventBridge event notifications
24 EVENT_BRIDGE_OPERATIONS = {
25     ACTION_PUT_PARAM: "Create",
26     ACTION_DELETE_PARAM: "Delete",
27     ACTION_LABEL_PARAM_VERSION: "LabelParameterVersion",
28 }
29 
30 
31 def normalize_name(param_name):
32     param_name = param_name.strip("/")
33     param_name = param_name.replace("//", "/")
34     if "/" in param_name:
35         param_name = "/%s" % param_name
36     return param_name
37 
38 
39 def get_secrets_information(name, resource_name):
40     client = aws_stack.connect_to_service("secretsmanager")
41     try:
42         secret_info = client.get_secret_value(SecretId=resource_name)
43 
44         del secret_info["ResponseMetadata"]
45         created_date_timestamp = time.mktime(secret_info["CreatedDate"].timetuple())
46         secret_info["CreatedDate"] = created_date_timestamp
47         result = {
48             "Parameter": {
49                 "SourceResult": json.dumps(secret_info, default=str),
50                 "Name": name,
51                 "Value": secret_info.get("SecretString"),
52                 "Type": "SecureString",
53                 "LastModifiedDate": created_date_timestamp,
54             }
55         }
56         return result
57     except client.exceptions.ResourceNotFoundException:
58         return None
59 
60 
61 def has_secrets(names):
62     for name in names:
63         if name.startswith("/aws/reference/secretsmanager"):
64             return True
65 
66 
67 def get_params_and_secrets(names):
68     ssm_client = aws_stack.connect_to_service("ssm")
69     result = {"Parameters": [], "InvalidParameters": []}
70     secrets_prefix = "/aws/reference/secretsmanager"
71 
72     for name in names:
73         if name.startswith(secrets_prefix):
74             secret = get_secrets_information(name, name[len(secrets_prefix) + 1 :])
75             if secret is not None:
76                 secret = secret["Parameter"]
77                 result["Parameters"].append(secret)
78             else:
79                 result["InvalidParameters"].append(name)
80         else:
81             try:
82                 param = ssm_client.get_parameter(Name=name)
83                 param["Parameter"]["LastModifiedDate"] = time.mktime(
84                     param["Parameter"]["LastModifiedDate"].timetuple()
85                 )
86                 result["Parameters"].append(param["Parameter"])
87             except ssm_client.exceptions.ParameterNotFound:
88                 result["InvalidParameters"].append(name)
89 
90     return result
91 
92 
93 def get_params_by_path_with_labels(
94     path="", param_filters=None, labels_to_filter=None, recursive=False
95 ):
96     ssm_client = aws_stack.connect_to_service("ssm")
97     result = {"Parameters": []}
98     filters = [{"Key": "Path", "Values": [path]}]
99     filters.extend(param_filters)
100     if recursive:
101         filters[0]["Option"] = "Recursive"
102 
103     def filter_by_label(param, labels):
104         for label in param["Labels"]:
105             if label in labels:
106                 return param
107 
108     try:
109         # Get all the params in the path
110         params_in_path = ssm_client.describe_parameters(ParameterFilters=filters)["Parameters"]
111 
112         # Get parameter with all its labels (for all the parameters in params_in_path)
113         # Labels of the parameters can be obtained by calling get_parameter_history with parameter name
114         all_params = []
115         for params in params_in_path:
116             all_params.extend(ssm_client.get_parameter_history(Name=params["Name"])["Parameters"])
117 
118         # Filter the params with matched labels
119         filtered_params = list(
120             filter(
121                 lambda param: filter_by_label(param=param, labels=labels_to_filter),
122                 all_params,
123             )
124         )
125 
126         # Get details of the filtered params to return
127         # This step is needed because get_parameter_history doesn't return parameter's ARN
128         details_of_filtered_params = list(
129             map(
130                 lambda param: ssm_client.get_parameter(Name=param["Name"])["Parameter"],
131                 filtered_params,
132             )
133         )
134         result["Parameters"].extend(details_of_filtered_params)
135     except Exception as e:
136         LOG.info(
137             "Unable to get SSM parameters by path and filter by labels : %s %s"
138             % (e, traceback.format_exc())
139         )
140         raise e
141     return result
142 
143 
144 def notify_event_subscribers(data, target_header):
145     """Publish an EventBridge event to notify subscribers of changes."""
146     if not is_api_enabled("events"):
147         return
148     events = aws_stack.connect_to_service("events")
149     operation = EVENT_BRIDGE_OPERATIONS.get(target_header)
150     if not operation:
151         LOG.warning(
152             "Unexpected target header '%s' when sending EventBridge notification from SSM",
153             target_header,
154         )
155     detail = {"name": data["Name"], "operation": operation}
156     event = {
157         "Source": "aws.ssm",
158         "Detail": json.dumps(detail),
159         "DetailType": "Parameter Store Change",
160     }
161     events.put_events(Entries=[event])
162 
163 
164 class ProxyListenerSSM(PersistingProxyListener):
165     def api_name(self):
166         return "ssm"
167 
168     def forward_request(self, method, path, data, headers):
169         if method == "OPTIONS":
170             return 200
171 
172         target = headers.get("X-Amz-Target")
173         data_orig = data
174         if method == "POST" and target:
175             data = json.loads(to_str(data))
176             if target == ACTION_GET_PARAMS:
177                 names = data["Names"] = data.get("Names") or []
178                 if has_secrets(names):
179                     return get_params_and_secrets(names)
180                 else:
181                     for i in range(len(names)):
182                         names[i] = normalize_name(names[i])
183             elif target in [ACTION_PUT_PARAM, ACTION_GET_PARAM]:
184                 name = data.get("Name") or ""
185                 data["Name"] = normalize_name(name)
186                 if target == ACTION_GET_PARAM:
187                     details = name.split("/")
188                     if len(details) > 4:
189                         service = details[3]
190                         if service == "secretsmanager":
191                             resource_name = "/".join(details[4:])
192                             secret = get_secrets_information(name, resource_name)
193                             if secret is not None:
194                                 return secret
195             elif target == ACTION_GET_PARAMS_BY_PATH and data.get("ParameterFilters"):
196                 params_filters = data.get("ParameterFilters") or []
197                 labels = []
198                 for filter in params_filters:
199                     if filter["Key"] == "Label":
200                         labels = filter["Values"]
201                         params_filters.remove(filter)
202                 if labels:
203                     path = data.get("Path")
204                     recursive = data.get("Recursive") or False
205                     return get_params_by_path_with_labels(
206                         path=path,
207                         param_filters=params_filters,
208                         labels_to_filter=labels,
209                         recursive=recursive,
210                     )
211             # send event notifications
212             if target in EVENT_BRIDGE_OPERATIONS:
213                 notify_event_subscribers(data, target)
214             # forward request
215             data = json.dumps(data)
216             if data != data_orig:
217                 return Request(data=data, headers=headers, method=method)
218 
219         return True
220 
221 
222 # instantiate listener
223 UPDATE_SSM = ProxyListenerSSM()
224
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/localstack/services/ssm/ssm_listener.py b/localstack/services/ssm/ssm_listener.py
--- a/localstack/services/ssm/ssm_listener.py
+++ b/localstack/services/ssm/ssm_listener.py
@@ -1,7 +1,6 @@
 import json
 import logging
 import time
-import traceback
 
 from requests.models import Request
 
@@ -90,57 +89,6 @@
     return result
 
 
-def get_params_by_path_with_labels(
-    path="", param_filters=None, labels_to_filter=None, recursive=False
-):
-    ssm_client = aws_stack.connect_to_service("ssm")
-    result = {"Parameters": []}
-    filters = [{"Key": "Path", "Values": [path]}]
-    filters.extend(param_filters)
-    if recursive:
-        filters[0]["Option"] = "Recursive"
-
-    def filter_by_label(param, labels):
-        for label in param["Labels"]:
-            if label in labels:
-                return param
-
-    try:
-        # Get all the params in the path
-        params_in_path = ssm_client.describe_parameters(ParameterFilters=filters)["Parameters"]
-
-        # Get parameter with all its labels (for all the parameters in params_in_path)
-        # Labels of the parameters can be obtained by calling get_parameter_history with parameter name
-        all_params = []
-        for params in params_in_path:
-            all_params.extend(ssm_client.get_parameter_history(Name=params["Name"])["Parameters"])
-
-        # Filter the params with matched labels
-        filtered_params = list(
-            filter(
-                lambda param: filter_by_label(param=param, labels=labels_to_filter),
-                all_params,
-            )
-        )
-
-        # Get details of the filtered params to return
-        # This step is needed because get_parameter_history doesn't return parameter's ARN
-        details_of_filtered_params = list(
-            map(
-                lambda param: ssm_client.get_parameter(Name=param["Name"])["Parameter"],
-                filtered_params,
-            )
-        )
-        result["Parameters"].extend(details_of_filtered_params)
-    except Exception as e:
-        LOG.info(
-            "Unable to get SSM parameters by path and filter by labels : %s %s"
-            % (e, traceback.format_exc())
-        )
-        raise e
-    return result
-
-
 def notify_event_subscribers(data, target_header):
     """Publish an EventBridge event to notify subscribers of changes."""
     if not is_api_enabled("events"):
@@ -192,22 +140,7 @@
                             secret = get_secrets_information(name, resource_name)
                             if secret is not None:
                                 return secret
-            elif target == ACTION_GET_PARAMS_BY_PATH and data.get("ParameterFilters"):
-                params_filters = data.get("ParameterFilters") or []
-                labels = []
-                for filter in params_filters:
-                    if filter["Key"] == "Label":
-                        labels = filter["Values"]
-                        params_filters.remove(filter)
-                if labels:
-                    path = data.get("Path")
-                    recursive = data.get("Recursive") or False
-                    return get_params_by_path_with_labels(
-                        path=path,
-                        param_filters=params_filters,
-                        labels_to_filter=labels,
-                        recursive=recursive,
-                    )
+
             # send event notifications
             if target in EVENT_BRIDGE_OPERATIONS:
                 notify_event_subscribers(data, target)

{"golden_diff": "diff --git a/localstack/services/ssm/ssm_listener.py b/localstack/services/ssm/ssm_listener.py\n--- a/localstack/services/ssm/ssm_listener.py\n+++ b/localstack/services/ssm/ssm_listener.py\n@@ -1,7 +1,6 @@\n import json\n import logging\n import time\n-import traceback\n \n from requests.models import Request\n \n@@ -90,57 +89,6 @@\n     return result\n \n \n-def get_params_by_path_with_labels(\n-    path=\"\", param_filters=None, labels_to_filter=None, recursive=False\n-):\n-    ssm_client = aws_stack.connect_to_service(\"ssm\")\n-    result = {\"Parameters\": []}\n-    filters = [{\"Key\": \"Path\", \"Values\": [path]}]\n-    filters.extend(param_filters)\n-    if recursive:\n-        filters[0][\"Option\"] = \"Recursive\"\n-\n-    def filter_by_label(param, labels):\n-        for label in param[\"Labels\"]:\n-            if label in labels:\n-                return param\n-\n-    try:\n-        # Get all the params in the path\n-        params_in_path = ssm_client.describe_parameters(ParameterFilters=filters)[\"Parameters\"]\n-\n-        # Get parameter with all its labels (for all the parameters in params_in_path)\n-        # Labels of the parameters can be obtained by calling get_parameter_history with parameter name\n-        all_params = []\n-        for params in params_in_path:\n-            all_params.extend(ssm_client.get_parameter_history(Name=params[\"Name\"])[\"Parameters\"])\n-\n-        # Filter the params with matched labels\n-        filtered_params = list(\n-            filter(\n-                lambda param: filter_by_label(param=param, labels=labels_to_filter),\n-                all_params,\n-            )\n-        )\n-\n-        # Get details of the filtered params to return\n-        # This step is needed because get_parameter_history doesn't return parameter's ARN\n-        details_of_filtered_params = list(\n-            map(\n-                lambda param: ssm_client.get_parameter(Name=param[\"Name\"])[\"Parameter\"],\n-                filtered_params,\n-            )\n-        )\n-        result[\"Parameters\"].extend(details_of_filtered_params)\n-    except Exception as e:\n-        LOG.info(\n-            \"Unable to get SSM parameters by path and filter by labels : %s %s\"\n-            % (e, traceback.format_exc())\n-        )\n-        raise e\n-    return result\n-\n-\n def notify_event_subscribers(data, target_header):\n     \"\"\"Publish an EventBridge event to notify subscribers of changes.\"\"\"\n     if not is_api_enabled(\"events\"):\n@@ -192,22 +140,7 @@\n                             secret = get_secrets_information(name, resource_name)\n                             if secret is not None:\n                                 return secret\n-            elif target == ACTION_GET_PARAMS_BY_PATH and data.get(\"ParameterFilters\"):\n-                params_filters = data.get(\"ParameterFilters\") or []\n-                labels = []\n-                for filter in params_filters:\n-                    if filter[\"Key\"] == \"Label\":\n-                        labels = filter[\"Values\"]\n-                        params_filters.remove(filter)\n-                if labels:\n-                    path = data.get(\"Path\")\n-                    recursive = data.get(\"Recursive\") or False\n-                    return get_params_by_path_with_labels(\n-                        path=path,\n-                        param_filters=params_filters,\n-                        labels_to_filter=labels,\n-                        recursive=recursive,\n-                    )\n+\n             # send event notifications\n             if target in EVENT_BRIDGE_OPERATIONS:\n                 notify_event_subscribers(data, target)\n", "issue": "SSM - labeling more than 10 parameters does not work right\n### Is there an existing issue for this?\r\n\r\n- [X] I have searched the existing issues\r\n\r\n### Current Behavior\r\n\r\nAdding and labeling more than 10 parameters only labels (or only returns) the first 10 labeled parameters.\r\n\r\n### Expected Behavior\r\n\r\nAdding and labeling more than 10 parameters should add & then return all the parameters.\r\n\r\n### How are you starting LocalStack?\r\n\r\nWith a docker-compose file\r\n\r\n### Steps To Reproduce\r\n\r\n#### How are you starting localstack (e.g., `bin/localstack` command, arguments, or `docker-compose.yml`)\r\n\r\ndocker-compose.yml\r\n\r\n#### Client commands (e.g., AWS SDK code snippet, or sequence of \"awslocal\" commands)\r\n\r\n```\r\nparams = [ ... ]  # create a list of **more** than 10 parameters ( Name + Value)\r\nfor param of params:\r\n       # add the parameter (returns 200)\r\n        res = ssm.put_parameter(Name=param[\"Name\"], Value=param[\"Value], Type='String')\r\n\r\n       # label the returned version with 'latest' (returns 200)\r\n        label_res = ssm.label_parameter_version(Name=path, ParameterVersion=res['Version'], Labels=['latest'])\r\n\r\n       # get the added parameter (returns the parameter successfully)\r\n        prm = ssm.get_parameter(Name=path)\r\n\r\n# get all parameters with the 'latest' label - this returns the first 10 parameters (although `MaxResults` is 100), and also doesn't return a `NextToken` property to iterate through the next batch of parameters.\r\nps = ssm.get_parameters_by_path(Path=base_path,\r\n                                        ParameterFilters=[  {  'Key': 'Label',  'Values': [  'latest'  ] } ],\r\n                                        MaxResults=100) \r\n\r\n```\r\n\r\n\r\n### Environment\r\n\r\n```markdown\r\n- OS: Windows 10\r\n- LocalStack: 0.12.17.5\r\n```\r\n\r\n\r\n### Anything else?\r\n\r\n_No response_\n", "before_files": [{"content": "import json\nimport logging\nimport time\nimport traceback\n\nfrom requests.models import Request\n\nfrom localstack.utils.aws import aws_stack\nfrom localstack.utils.bootstrap import is_api_enabled\nfrom localstack.utils.common import to_str\nfrom localstack.utils.persistence import PersistingProxyListener\n\n# logger\nLOG = logging.getLogger(__name__)\n\nACTION_PUT_PARAM = \"AmazonSSM.PutParameter\"\nACTION_GET_PARAM = \"AmazonSSM.GetParameter\"\nACTION_GET_PARAMS = \"AmazonSSM.GetParameters\"\nACTION_DELETE_PARAM = \"AmazonSSM.DeleteParameter\"\nACTION_GET_PARAMS_BY_PATH = \"AmazonSSM.GetParametersByPath\"\nACTION_LABEL_PARAM_VERSION = \"AmazonSSM.LabelParameterVersion\"\n\n# maps SSM target header names to operation names used in EventBridge event notifications\nEVENT_BRIDGE_OPERATIONS = {\n    ACTION_PUT_PARAM: \"Create\",\n    ACTION_DELETE_PARAM: \"Delete\",\n    ACTION_LABEL_PARAM_VERSION: \"LabelParameterVersion\",\n}\n\n\ndef normalize_name(param_name):\n    param_name = param_name.strip(\"/\")\n    param_name = param_name.replace(\"//\", \"/\")\n    if \"/\" in param_name:\n        param_name = \"/%s\" % param_name\n    return param_name\n\n\ndef get_secrets_information(name, resource_name):\n    client = aws_stack.connect_to_service(\"secretsmanager\")\n    try:\n        secret_info = client.get_secret_value(SecretId=resource_name)\n\n        del secret_info[\"ResponseMetadata\"]\n        created_date_timestamp = time.mktime(secret_info[\"CreatedDate\"].timetuple())\n        secret_info[\"CreatedDate\"] = created_date_timestamp\n        result = {\n            \"Parameter\": {\n                \"SourceResult\": json.dumps(secret_info, default=str),\n                \"Name\": name,\n                \"Value\": secret_info.get(\"SecretString\"),\n                \"Type\": \"SecureString\",\n                \"LastModifiedDate\": created_date_timestamp,\n            }\n        }\n        return result\n    except client.exceptions.ResourceNotFoundException:\n        return None\n\n\ndef has_secrets(names):\n    for name in names:\n        if name.startswith(\"/aws/reference/secretsmanager\"):\n            return True\n\n\ndef get_params_and_secrets(names):\n    ssm_client = aws_stack.connect_to_service(\"ssm\")\n    result = {\"Parameters\": [], \"InvalidParameters\": []}\n    secrets_prefix = \"/aws/reference/secretsmanager\"\n\n    for name in names:\n        if name.startswith(secrets_prefix):\n            secret = get_secrets_information(name, name[len(secrets_prefix) + 1 :])\n            if secret is not None:\n                secret = secret[\"Parameter\"]\n                result[\"Parameters\"].append(secret)\n            else:\n                result[\"InvalidParameters\"].append(name)\n        else:\n            try:\n                param = ssm_client.get_parameter(Name=name)\n                param[\"Parameter\"][\"LastModifiedDate\"] = time.mktime(\n                    param[\"Parameter\"][\"LastModifiedDate\"].timetuple()\n                )\n                result[\"Parameters\"].append(param[\"Parameter\"])\n            except ssm_client.exceptions.ParameterNotFound:\n                result[\"InvalidParameters\"].append(name)\n\n    return result\n\n\ndef get_params_by_path_with_labels(\n    path=\"\", param_filters=None, labels_to_filter=None, recursive=False\n):\n    ssm_client = aws_stack.connect_to_service(\"ssm\")\n    result = {\"Parameters\": []}\n    filters = [{\"Key\": \"Path\", \"Values\": [path]}]\n    filters.extend(param_filters)\n    if recursive:\n        filters[0][\"Option\"] = \"Recursive\"\n\n    def filter_by_label(param, labels):\n        for label in param[\"Labels\"]:\n            if label in labels:\n                return param\n\n    try:\n        # Get all the params in the path\n        params_in_path = ssm_client.describe_parameters(ParameterFilters=filters)[\"Parameters\"]\n\n        # Get parameter with all its labels (for all the parameters in params_in_path)\n        # Labels of the parameters can be obtained by calling get_parameter_history with parameter name\n        all_params = []\n        for params in params_in_path:\n            all_params.extend(ssm_client.get_parameter_history(Name=params[\"Name\"])[\"Parameters\"])\n\n        # Filter the params with matched labels\n        filtered_params = list(\n            filter(\n                lambda param: filter_by_label(param=param, labels=labels_to_filter),\n                all_params,\n            )\n        )\n\n        # Get details of the filtered params to return\n        # This step is needed because get_parameter_history doesn't return parameter's ARN\n        details_of_filtered_params = list(\n            map(\n                lambda param: ssm_client.get_parameter(Name=param[\"Name\"])[\"Parameter\"],\n                filtered_params,\n            )\n        )\n        result[\"Parameters\"].extend(details_of_filtered_params)\n    except Exception as e:\n        LOG.info(\n            \"Unable to get SSM parameters by path and filter by labels : %s %s\"\n            % (e, traceback.format_exc())\n        )\n        raise e\n    return result\n\n\ndef notify_event_subscribers(data, target_header):\n    \"\"\"Publish an EventBridge event to notify subscribers of changes.\"\"\"\n    if not is_api_enabled(\"events\"):\n        return\n    events = aws_stack.connect_to_service(\"events\")\n    operation = EVENT_BRIDGE_OPERATIONS.get(target_header)\n    if not operation:\n        LOG.warning(\n            \"Unexpected target header '%s' when sending EventBridge notification from SSM\",\n            target_header,\n        )\n    detail = {\"name\": data[\"Name\"], \"operation\": operation}\n    event = {\n        \"Source\": \"aws.ssm\",\n        \"Detail\": json.dumps(detail),\n        \"DetailType\": \"Parameter Store Change\",\n    }\n    events.put_events(Entries=[event])\n\n\nclass ProxyListenerSSM(PersistingProxyListener):\n    def api_name(self):\n        return \"ssm\"\n\n    def forward_request(self, method, path, data, headers):\n        if method == \"OPTIONS\":\n            return 200\n\n        target = headers.get(\"X-Amz-Target\")\n        data_orig = data\n        if method == \"POST\" and target:\n            data = json.loads(to_str(data))\n            if target == ACTION_GET_PARAMS:\n                names = data[\"Names\"] = data.get(\"Names\") or []\n                if has_secrets(names):\n                    return get_params_and_secrets(names)\n                else:\n                    for i in range(len(names)):\n                        names[i] = normalize_name(names[i])\n            elif target in [ACTION_PUT_PARAM, ACTION_GET_PARAM]:\n                name = data.get(\"Name\") or \"\"\n                data[\"Name\"] = normalize_name(name)\n                if target == ACTION_GET_PARAM:\n                    details = name.split(\"/\")\n                    if len(details) > 4:\n                        service = details[3]\n                        if service == \"secretsmanager\":\n                            resource_name = \"/\".join(details[4:])\n                            secret = get_secrets_information(name, resource_name)\n                            if secret is not None:\n                                return secret\n            elif target == ACTION_GET_PARAMS_BY_PATH and data.get(\"ParameterFilters\"):\n                params_filters = data.get(\"ParameterFilters\") or []\n                labels = []\n                for filter in params_filters:\n                    if filter[\"Key\"] == \"Label\":\n                        labels = filter[\"Values\"]\n                        params_filters.remove(filter)\n                if labels:\n                    path = data.get(\"Path\")\n                    recursive = data.get(\"Recursive\") or False\n                    return get_params_by_path_with_labels(\n                        path=path,\n                        param_filters=params_filters,\n                        labels_to_filter=labels,\n                        recursive=recursive,\n                    )\n            # send event notifications\n            if target in EVENT_BRIDGE_OPERATIONS:\n                notify_event_subscribers(data, target)\n            # forward request\n            data = json.dumps(data)\n            if data != data_orig:\n                return Request(data=data, headers=headers, method=method)\n\n        return True\n\n\n# instantiate listener\nUPDATE_SSM = ProxyListenerSSM()\n", "path": "localstack/services/ssm/ssm_listener.py"}], "after_files": [{"content": "import json\nimport logging\nimport time\n\nfrom requests.models import Request\n\nfrom localstack.utils.aws import aws_stack\nfrom localstack.utils.bootstrap import is_api_enabled\nfrom localstack.utils.common import to_str\nfrom localstack.utils.persistence import PersistingProxyListener\n\n# logger\nLOG = logging.getLogger(__name__)\n\nACTION_PUT_PARAM = \"AmazonSSM.PutParameter\"\nACTION_GET_PARAM = \"AmazonSSM.GetParameter\"\nACTION_GET_PARAMS = \"AmazonSSM.GetParameters\"\nACTION_DELETE_PARAM = \"AmazonSSM.DeleteParameter\"\nACTION_GET_PARAMS_BY_PATH = \"AmazonSSM.GetParametersByPath\"\nACTION_LABEL_PARAM_VERSION = \"AmazonSSM.LabelParameterVersion\"\n\n# maps SSM target header names to operation names used in EventBridge event notifications\nEVENT_BRIDGE_OPERATIONS = {\n    ACTION_PUT_PARAM: \"Create\",\n    ACTION_DELETE_PARAM: \"Delete\",\n    ACTION_LABEL_PARAM_VERSION: \"LabelParameterVersion\",\n}\n\n\ndef normalize_name(param_name):\n    param_name = param_name.strip(\"/\")\n    param_name = param_name.replace(\"//\", \"/\")\n    if \"/\" in param_name:\n        param_name = \"/%s\" % param_name\n    return param_name\n\n\ndef get_secrets_information(name, resource_name):\n    client = aws_stack.connect_to_service(\"secretsmanager\")\n    try:\n        secret_info = client.get_secret_value(SecretId=resource_name)\n\n        del secret_info[\"ResponseMetadata\"]\n        created_date_timestamp = time.mktime(secret_info[\"CreatedDate\"].timetuple())\n        secret_info[\"CreatedDate\"] = created_date_timestamp\n        result = {\n            \"Parameter\": {\n                \"SourceResult\": json.dumps(secret_info, default=str),\n                \"Name\": name,\n                \"Value\": secret_info.get(\"SecretString\"),\n                \"Type\": \"SecureString\",\n                \"LastModifiedDate\": created_date_timestamp,\n            }\n        }\n        return result\n    except client.exceptions.ResourceNotFoundException:\n        return None\n\n\ndef has_secrets(names):\n    for name in names:\n        if name.startswith(\"/aws/reference/secretsmanager\"):\n            return True\n\n\ndef get_params_and_secrets(names):\n    ssm_client = aws_stack.connect_to_service(\"ssm\")\n    result = {\"Parameters\": [], \"InvalidParameters\": []}\n    secrets_prefix = \"/aws/reference/secretsmanager\"\n\n    for name in names:\n        if name.startswith(secrets_prefix):\n            secret = get_secrets_information(name, name[len(secrets_prefix) + 1 :])\n            if secret is not None:\n                secret = secret[\"Parameter\"]\n                result[\"Parameters\"].append(secret)\n            else:\n                result[\"InvalidParameters\"].append(name)\n        else:\n            try:\n                param = ssm_client.get_parameter(Name=name)\n                param[\"Parameter\"][\"LastModifiedDate\"] = time.mktime(\n                    param[\"Parameter\"][\"LastModifiedDate\"].timetuple()\n                )\n                result[\"Parameters\"].append(param[\"Parameter\"])\n            except ssm_client.exceptions.ParameterNotFound:\n                result[\"InvalidParameters\"].append(name)\n\n    return result\n\n\ndef notify_event_subscribers(data, target_header):\n    \"\"\"Publish an EventBridge event to notify subscribers of changes.\"\"\"\n    if not is_api_enabled(\"events\"):\n        return\n    events = aws_stack.connect_to_service(\"events\")\n    operation = EVENT_BRIDGE_OPERATIONS.get(target_header)\n    if not operation:\n        LOG.warning(\n            \"Unexpected target header '%s' when sending EventBridge notification from SSM\",\n            target_header,\n        )\n    detail = {\"name\": data[\"Name\"], \"operation\": operation}\n    event = {\n        \"Source\": \"aws.ssm\",\n        \"Detail\": json.dumps(detail),\n        \"DetailType\": \"Parameter Store Change\",\n    }\n    events.put_events(Entries=[event])\n\n\nclass ProxyListenerSSM(PersistingProxyListener):\n    def api_name(self):\n        return \"ssm\"\n\n    def forward_request(self, method, path, data, headers):\n        if method == \"OPTIONS\":\n            return 200\n\n        target = headers.get(\"X-Amz-Target\")\n        data_orig = data\n        if method == \"POST\" and target:\n            data = json.loads(to_str(data))\n            if target == ACTION_GET_PARAMS:\n                names = data[\"Names\"] = data.get(\"Names\") or []\n                if has_secrets(names):\n                    return get_params_and_secrets(names)\n                else:\n                    for i in range(len(names)):\n                        names[i] = normalize_name(names[i])\n            elif target in [ACTION_PUT_PARAM, ACTION_GET_PARAM]:\n                name = data.get(\"Name\") or \"\"\n                data[\"Name\"] = normalize_name(name)\n                if target == ACTION_GET_PARAM:\n                    details = name.split(\"/\")\n                    if len(details) > 4:\n                        service = details[3]\n                        if service == \"secretsmanager\":\n                            resource_name = \"/\".join(details[4:])\n                            secret = get_secrets_information(name, resource_name)\n                            if secret is not None:\n                                return secret\n\n            # send event notifications\n            if target in EVENT_BRIDGE_OPERATIONS:\n                notify_event_subscribers(data, target)\n            # forward request\n            data = json.dumps(data)\n            if data != data_orig:\n                return Request(data=data, headers=headers, method=method)\n\n        return True\n\n\n# instantiate listener\nUPDATE_SSM = ProxyListenerSSM()\n", "path": "localstack/services/ssm/ssm_listener.py"}]}