Repository: aws-cloudformation/cfn-lint

Issue:
State Machine types missing Map type
The [current list](https://github.com/aws-cloudformation/cfn-python-lint/blob/master/src/cfnlint/rules/resources/stepfunctions/StateMachine.py#L53) of valid types for state machine tasks is missing the recently-announced [`Map`](https://aws.amazon.com/blogs/aws/new-step-functions-support-for-dynamic-parallelism/) type


Discussion:

Resolving patch:
diff --git a/src/cfnlint/rules/resources/stepfunctions/StateMachine.py b/src/cfnlint/rules/resources/stepfunctions/StateMachine.py
--- a/src/cfnlint/rules/resources/stepfunctions/StateMachine.py
+++ b/src/cfnlint/rules/resources/stepfunctions/StateMachine.py
@@ -52,7 +52,10 @@ def _check_state_json(self, def_json, state_name, path):
         ]
         state_key_types = {
             'Pass': ['Result', 'ResultPath', 'Parameters'],
-            'Task': ['Resource', 'ResultPath', 'Retry', 'Catch', 'TimeoutSeconds', 'Parameters', 'HeartbeatSeconds'],
+            'Task': ['Resource', 'ResultPath', 'Retry', 'Catch',
+                     'TimeoutSeconds', 'Parameters', 'HeartbeatSeconds'],
+            'Map': ['MaxConcurrency', 'Iterator', 'ItemsPath', 'ResultPath',
+                    'Retry', 'Catch'],
             'Choice': ['Choices', 'Default'],
             'Wait': ['Seconds', 'Timestamp', 'SecondsPath', 'TimestampPath'],
             'Succeed': [],
@@ -71,7 +74,8 @@ def _check_state_json(self, def_json, state_name, path):
 
         for req_key in common_state_required_keys:
             if req_key not in def_json:
-                message = 'State Machine Definition required key (%s) for State (%s) is missing' % (req_key, state_name)
+                message = 'State Machine Definition required key (%s) for State (%s) is missing' % (
+                    req_key, state_name)
                 matches.append(RuleMatch(path, message))
                 return matches
 
@@ -80,11 +84,13 @@ def _check_state_json(self, def_json, state_name, path):
         if state_type in state_key_types:
             for state_key, _ in def_json.items():
                 if state_key not in common_state_keys + state_key_types.get(state_type, []):
-                    message = 'State Machine Definition key (%s) for State (%s) of Type (%s) is not valid' % (state_key, state_name, state_type)
+                    message = 'State Machine Definition key (%s) for State (%s) of Type (%s) is not valid' % (
+                        state_key, state_name, state_type)
                     matches.append(RuleMatch(path, message))
             for req_key in common_state_required_keys + state_required_types.get(state_type, []):
                 if req_key not in def_json:
-                    message = 'State Machine Definition required key (%s) for State (%s) of Type (%s) is missing' % (req_key, state_name, state_type)
+                    message = 'State Machine Definition required key (%s) for State (%s) of Type (%s) is missing' % (
+                        req_key, state_name, state_type)
                     matches.append(RuleMatch(path, message))
                     return matches
         else:


Test patch:
diff --git a/test/fixtures/templates/good/resources/stepfunctions/state_machine.yaml b/test/fixtures/templates/good/resources/stepfunctions/state_machine.yaml
--- a/test/fixtures/templates/good/resources/stepfunctions/state_machine.yaml
+++ b/test/fixtures/templates/good/resources/stepfunctions/state_machine.yaml
@@ -83,3 +83,83 @@ Resources:
           }
         - TestParam: !Ref timeout
       RoleArn: arn:aws:iam::111122223333:role/service-role/StatesExecutionRole-us-east-1
+  MyStateMachineNewTypes:
+    Type: AWS::StepFunctions::StateMachine
+    Properties:
+      StateMachineName: HelloWorld-StateMachine
+      DefinitionString: |-
+        {
+          "StartAt": "ValidatePayment",
+          "States": {
+            "ValidatePayment": {
+              "Type": "Task",
+              "Resource": "arn:aws:lambda:us-west-2:123456789012:function:validatePayment",
+              "Next": "CheckPayment"
+            },
+            "CheckPayment": {
+              "Type": "Choice",
+              "Choices": [
+                {
+                  "Not": {
+                    "Variable": "$.payment",
+                    "StringEquals": "Ok"
+                  },
+                  "Next": "PaymentFailed"
+                }
+              ],
+              "Default": "ProcessAllItems"
+            },
+            "PaymentFailed": {
+              "Type": "Task",
+              "Resource": "arn:aws:lambda:us-west-2:123456789012:function:paymentFailed",
+              "End": true
+            },
+            "ProcessAllItems": {
+              "Type": "Map",
+              "InputPath": "$.detail",
+              "ItemsPath": "$.items",
+              "MaxConcurrency": 3,
+              "Iterator": {
+                "StartAt": "CheckAvailability",
+                "States": {
+                  "CheckAvailability": {
+                    "Type": "Task",
+                    "Resource": "arn:aws:lambda:us-west-2:123456789012:function:checkAvailability",
+                    "Retry": [
+                      {
+                        "ErrorEquals": [
+                          "TimeOut"
+                        ],
+                        "IntervalSeconds": 1,
+                        "BackoffRate": 2,
+                        "MaxAttempts": 3
+                      }
+                    ],
+                    "Next": "PrepareForDelivery"
+                  },
+                  "PrepareForDelivery": {
+                    "Type": "Task",
+                    "Resource": "arn:aws:lambda:us-west-2:123456789012:function:prepareForDelivery",
+                    "Next": "StartDelivery"
+                  },
+                  "StartDelivery": {
+                    "Type": "Task",
+                    "Resource": "arn:aws:lambda:us-west-2:123456789012:function:startDelivery",
+                    "End": true
+                  }
+                }
+              },
+              "ResultPath": "$.detail.processedItems",
+              "Next": "SendOrderSummary"
+            },
+            "SendOrderSummary": {
+              "Type": "Task",
+              "InputPath": "$.detail.processedItems",
+              "Resource": "arn:aws:lambda:us-west-2:123456789012:function:sendOrderSummary",
+              "ResultPath": "$.detail.summary",
+              "End": true
+            }
+          }
+        }
+      RoleArn: arn:aws:iam::111122223333:role/service-role/StatesExecutionRole-us-east-1
+