Implement basic status filter for StepFunctions list-executions
diff --git a/localstack/services/stepfunctions/provider.py b/localstack/services/stepfunctions/provider.py
index 838dcf35f2781..e27df1d9ddbb1 100644
--- a/localstack/services/stepfunctions/provider.py
+++ b/localstack/services/stepfunctions/provider.py
@@ -5,7 +5,7 @@
 import re
 from typing import Final, Optional
 
-from localstack.aws.api import RequestContext
+from localstack.aws.api import CommonServiceException, RequestContext
 from localstack.aws.api.stepfunctions import (
     Arn,
     ConflictException,
@@ -422,6 +422,17 @@ def describe_execution(
         execution: Execution = self._get_execution(context=context, execution_arn=execution_arn)
         return execution.to_describe_output()
 
+    @staticmethod
+    def _list_execution_filter(
+        ex: Execution, state_machine_arn: str | None, status_filter: str | None
+    ) -> bool:
+        if state_machine_arn and ex.state_machine.arn != state_machine_arn:
+            return False
+
+        if not status_filter:
+            return True
+        return ex.exec_status == status_filter
+
     def list_executions(
         self,
         context: RequestContext,
@@ -439,11 +450,38 @@ def list_executions(
         if state_machine is None:
             self._raise_state_machine_does_not_exist(state_machine_arn)
 
-        # TODO: add support for paging and filtering.
+        # TODO: add support for paging
+
+        allowed_execution_status = [
+            ExecutionStatus.SUCCEEDED,
+            ExecutionStatus.TIMED_OUT,
+            ExecutionStatus.PENDING_REDRIVE,
+            ExecutionStatus.ABORTED,
+            ExecutionStatus.FAILED,
+            ExecutionStatus.RUNNING,
+        ]
+
+        validation_errors = []
+
+        if status_filter and status_filter not in allowed_execution_status:
+            validation_errors.append(
+                f"Value '{status_filter}' at 'statusFilter' failed to satisfy constraint: Member must satisfy enum value set: [{', '.join(allowed_execution_status)}]"
+            )
+
+        if not state_machine_arn and not map_run_arn:
+            validation_errors.append("Must provide a StateMachine ARN or MapRun ARN")
+
+        if validation_errors:
+            errors_message = "; ".join(validation_errors)
+            message = f"{len(validation_errors)} validation {'errors' if len(validation_errors) > 1 else 'error'} detected: {errors_message}"
+            raise CommonServiceException(message=message, code="ValidationException")
+
         executions: ExecutionList = [
             execution.to_execution_list_item()
             for execution in self.get_store(context).executions.values()
-            if execution.state_machine.arn == state_machine_arn
+            if self._list_execution_filter(
+                execution, state_machine_arn=state_machine_arn, status_filter=status_filter
+            )
         ]
         return ListExecutionsOutput(executions=executions)
 
diff --git a/tests/aws/services/stepfunctions/utils.py b/tests/aws/services/stepfunctions/utils.py
index 48ae7096700da..40c245ee948de 100644
--- a/tests/aws/services/stepfunctions/utils.py
+++ b/tests/aws/services/stepfunctions/utils.py
@@ -155,6 +155,28 @@ def _check_last_is_success(events: HistoryEventList) -> bool:
     )
 
 
+def await_list_execution_status(
+    stepfunctions_client, state_machine_arn: str, execution_arn: str, status: str
+):
+    """required as there is some eventual consistency in list_executions vs describe_execution and get_execution_history"""
+
+    def _run_check():
+        list_resp = stepfunctions_client.list_executions(
+            stateMachineArn=state_machine_arn, statusFilter=status
+        )
+        for execution in list_resp.get("executions", []):
+            if execution["executionArn"] != execution_arn or execution["status"] != status:
+                continue
+            return True
+        return False
+
+    success = poll_condition(condition=_run_check, timeout=120, interval=1)
+    if not success:
+        LOG.warning(
+            f"Timed out whilst awaiting for execution status {status} to satisfy condition for execution '{execution_arn}'."
+        )
+
+
 def await_execution_terminated(stepfunctions_client, execution_arn: str):
     def _check_last_is_terminal(events: HistoryEventList) -> bool:
         if len(events) > 0:
diff --git a/tests/aws/services/stepfunctions/v2/test_sfn_api.py b/tests/aws/services/stepfunctions/v2/test_sfn_api.py
index 7125592742bb8..fd696d1bb42cc 100644
--- a/tests/aws/services/stepfunctions/v2/test_sfn_api.py
+++ b/tests/aws/services/stepfunctions/v2/test_sfn_api.py
@@ -2,6 +2,7 @@
 
 import pytest
 import yaml
+from botocore.exceptions import ClientError
 from localstack_snapshot.snapshots.transformer import RegexTransformer
 
 from localstack.aws.api.lambda_ import Runtime
@@ -14,6 +15,7 @@
     await_execution_started,
     await_execution_success,
     await_execution_terminated,
+    await_list_execution_status,
     await_state_machine_listed,
     await_state_machine_not_listed,
 )
@@ -1003,3 +1005,55 @@ def test_get_execution_history_invalid_arn(self, sfn_snapshot, aws_client):
         sfn_snapshot.match(
             "exception", {"exception_typename": exc.typename, "exception_value": exc.value}
         )
+
+    @markers.snapshot.skip_snapshot_verify(paths=["$..redriveCount"])
+    @markers.aws.validated
+    def test_state_machine_status_filter(
+        self, create_iam_role_for_sfn, create_state_machine, sfn_snapshot, aws_client
+    ):
+        snf_role_arn = create_iam_role_for_sfn()
+        sfn_snapshot.add_transformer(RegexTransformer(snf_role_arn, "snf_role_arn"))
+
+        sm_name = f"statemachine_{short_uid()}"
+        definition = BaseTemplate.load_sfn_template(BaseTemplate.BASE_PASS_RESULT)
+        definition_str = json.dumps(definition)
+
+        creation_resp = create_state_machine(
+            name=sm_name, definition=definition_str, roleArn=snf_role_arn
+        )
+        sfn_snapshot.add_transformer(sfn_snapshot.transform.sfn_sm_create_arn(creation_resp, 0))
+        sfn_snapshot.match("creation_resp", creation_resp)
+        state_machine_arn = creation_resp["stateMachineArn"]
+
+        list_response = aws_client.stepfunctions.list_executions(
+            stateMachineArn=state_machine_arn, statusFilter="SUCCEEDED"
+        )
+        sfn_snapshot.match("list_before_execution", list_response)
+
+        exec_resp = aws_client.stepfunctions.start_execution(stateMachineArn=state_machine_arn)
+        sfn_snapshot.add_transformer(sfn_snapshot.transform.sfn_sm_exec_arn(exec_resp, 0))
+        sfn_snapshot.match("exec_resp", exec_resp)
+        execution_arn = exec_resp["executionArn"]
+
+        await_list_execution_status(
+            stepfunctions_client=aws_client.stepfunctions,
+            state_machine_arn=state_machine_arn,
+            execution_arn=execution_arn,
+            status="SUCCEEDED",
+        )
+
+        list_response = aws_client.stepfunctions.list_executions(
+            stateMachineArn=state_machine_arn, statusFilter="SUCCEEDED"
+        )
+        sfn_snapshot.match("list_succeeded_when_complete", list_response)
+
+        list_response = aws_client.stepfunctions.list_executions(
+            stateMachineArn=state_machine_arn, statusFilter="RUNNING"
+        )
+        sfn_snapshot.match("list_running_when_complete", list_response)
+
+        with pytest.raises(ClientError) as e:
+            aws_client.stepfunctions.list_executions(
+                stateMachineArn=state_machine_arn, statusFilter="succeeded"
+            )
+        sfn_snapshot.match("list_executions_filter_exc", e.value.response)
diff --git a/tests/aws/services/stepfunctions/v2/test_sfn_api.snapshot.json b/tests/aws/services/stepfunctions/v2/test_sfn_api.snapshot.json
index d2a0023b2eacd..10c0db34669b4 100644
--- a/tests/aws/services/stepfunctions/v2/test_sfn_api.snapshot.json
+++ b/tests/aws/services/stepfunctions/v2/test_sfn_api.snapshot.json
@@ -1614,5 +1614,68 @@
         "exception_value": "An error occurred (InvalidArn) when calling the DescribeExecution operation: Invalid Arn: 'Invalid ARN prefix: invalid_state_machine_arn'"
       }
     }
+  },
+  "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_state_machine_status_filter": {
+    "recorded-date": "14-03-2024, 21:58:24",
+    "recorded-content": {
+      "creation_resp": {
+        "creationDate": "datetime",
+        "stateMachineArn": "arn:aws:states:<region>:111111111111:stateMachine:<ArnPart_0idx>",
+        "ResponseMetadata": {
+          "HTTPHeaders": {},
+          "HTTPStatusCode": 200
+        }
+      },
+      "list_before_execution": {
+        "executions": [],
+        "ResponseMetadata": {
+          "HTTPHeaders": {},
+          "HTTPStatusCode": 200
+        }
+      },
+      "exec_resp": {
+        "executionArn": "arn:aws:states:<region>:111111111111:execution:<ArnPart_0idx>:<ExecArnPart_0idx>",
+        "startDate": "datetime",
+        "ResponseMetadata": {
+          "HTTPHeaders": {},
+          "HTTPStatusCode": 200
+        }
+      },
+      "list_succeeded_when_complete": {
+        "executions": [
+          {
+            "executionArn": "arn:aws:states:<region>:111111111111:execution:<ArnPart_0idx>:<ExecArnPart_0idx>",
+            "name": "<ExecArnPart_0idx>",
+            "redriveCount": 0,
+            "startDate": "datetime",
+            "stateMachineArn": "arn:aws:states:<region>:111111111111:stateMachine:<ArnPart_0idx>",
+            "status": "SUCCEEDED",
+            "stopDate": "datetime"
+          }
+        ],
+        "ResponseMetadata": {
+          "HTTPHeaders": {},
+          "HTTPStatusCode": 200
+        }
+      },
+      "list_running_when_complete": {
+        "executions": [],
+        "ResponseMetadata": {
+          "HTTPHeaders": {},
+          "HTTPStatusCode": 200
+        }
+      },
+      "list_executions_filter_exc": {
+        "Error": {
+          "Code": "ValidationException",
+          "Message": "1 validation error detected: Value 'succeeded' at 'statusFilter' failed to satisfy constraint: Member must satisfy enum value set: [SUCCEEDED, TIMED_OUT, PENDING_REDRIVE, ABORTED, FAILED, RUNNING]"
+        },
+        "message": "1 validation error detected: Value 'succeeded' at 'statusFilter' failed to satisfy constraint: Member must satisfy enum value set: [SUCCEEDED, TIMED_OUT, PENDING_REDRIVE, ABORTED, FAILED, RUNNING]",
+        "ResponseMetadata": {
+          "HTTPHeaders": {},
+          "HTTPStatusCode": 400
+        }
+      }
+    }
   }
 }
diff --git a/tests/aws/services/stepfunctions/v2/test_sfn_api.validation.json b/tests/aws/services/stepfunctions/v2/test_sfn_api.validation.json
index a0c73197d33ba..586bd546dacdd 100644
--- a/tests/aws/services/stepfunctions/v2/test_sfn_api.validation.json
+++ b/tests/aws/services/stepfunctions/v2/test_sfn_api.validation.json
@@ -89,6 +89,9 @@
   "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_start_execution": {
     "last_validated_date": "2023-06-22T11:52:39+00:00"
   },
+  "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_state_machine_status_filter": {
+    "last_validated_date": "2024-03-14T21:59:25+00:00"
+  },
   "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_stop_execution": {
     "last_validated_date": "2023-06-22T11:53:24+00:00"
   }

## Motivation

v2 stepfunctions provider `list-executions` should support `statusFilter`  ... not yet implmented


## Changes
* added basic statusFilter to  localstack/services/stepfunctions/provider.py
* new test `tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_state_machine_status_filter`

## Testing

basic coverage `tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_state_machine_status_filter`


