Skip to content

Step Functions State Machine: Add reachability check for all states#4465

Open
r-heimann wants to merge 1 commit into
aws-cloudformation:mainfrom
r-heimann:main
Open

Step Functions State Machine: Add reachability check for all states#4465
r-heimann wants to merge 1 commit into
aws-cloudformation:mainfrom
r-heimann:main

Conversation

@r-heimann

Copy link
Copy Markdown
Contributor

Issue #, if available:
fixes #4073

Description of changes:
Adds reachability checks for all states and updates the State Machine tests.

An LLM was used as help in the creation of this PR. In my tests i didn't find any regressions but i cannot rule out that something might have slipped through.

@tyukei would you be so kind to review this PR?

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@r-heimann

Copy link
Copy Markdown
Contributor Author

@kddejong Could you please trigger the pipeline?

@r-heimann
r-heimann marked this pull request as ready for review April 28, 2026 12:52
Comment thread src/cfnlint/rules/resources/stepfunctions/StateMachineDefinition.py
Comment thread src/cfnlint/rules/resources/stepfunctions/StateMachineDefinition.py Outdated
@r-heimann
r-heimann force-pushed the main branch 4 times, most recently from af3e1d7 to 1faef33 Compare May 5, 2026 06:28
@r-heimann
r-heimann marked this pull request as draft May 8, 2026 08:52
@r-heimann
r-heimann marked this pull request as ready for review June 2, 2026 10:23
@r-heimann

Copy link
Copy Markdown
Contributor Author

@kddejong Would you be so kind to trigger the pipeline? (Not ready for merge yet)

@r-heimann

Copy link
Copy Markdown
Contributor Author

@kddejong Would you be so kind to trigger once more the pipeline?

@r-heimann

Copy link
Copy Markdown
Contributor Author

I was wondering why Tests unrelated to Step Functions are failing and did a rebase to fix #4550, but (locally) more tests are failing now:

cfn-lint> pip3 install -e .
cfn-lint> tox -e py313
...
=============================================== short test summary info ===============================================
FAILED test/integration/test_deployment_files.py::test_deployment_files[Correctly configured deployment file-deployment_files0-expected0]
FAILED test/integration/test_deployment_files.py::test_deployment_files[Incorrectly configured deployment file-deployment_files1-expected1]
FAILED test/integration/test_deployment_files.py::test_deployment_files[Multiple deployment files-deployment_files2-expected2]
FAILED test/integration/test_directives.py::TestDirectives::test_templates - AssertionError: 2 != 0 : Expected 0 exit...
FAILED test/integration/test_good_templates.py::TestQuickStartTemplates::test_module_integration - AssertionError: Ex...
FAILED test/integration/test_good_templates.py::TestQuickStartTemplates::test_templates - AssertionError: 2 != 0 : Ex...
FAILED test/integration/test_integration_templates.py::TestQuickStartTemplates::test_templates - AssertionError: Expe...
FAILED test/integration/test_mandatory_checks.py::TestDirectives::test_templates_explicit - AssertionError: Element c...
FAILED test/integration/test_mandatory_checks.py::TestDirectives::test_templates_prefixed - AssertionError: Element c...
FAILED test/integration/test_parameter_files.py::test_parameter_files[Correctly configured deployment file-parameter_files0-templates0-expected0]
FAILED test/integration/test_parameter_files.py::test_parameter_files[Incorrectly configured deployment file-parameter_files1-templates1-expected1]
FAILED test/integration/test_parameter_files.py::test_parameter_files[Multiple deployment files-parameter_files2-templates2-expected2]
FAILED test/integration/test_quickstart_templates.py::TestQuickStartTemplates::test_templates - AssertionError: Lists...
FAILED test/integration/test_quickstart_templates_non_strict.py::TestQuickStartTemplates::test_module_integration - A...
FAILED test/integration/test_quickstart_templates_non_strict.py::TestQuickStartTemplates::test_templates - AssertionE...
FAILED test/integration/test_template_parameters.py::test_parameters[Correctly configured deployment file-parameters0-test/fixtures/templates/integration/deployment-file-template.yaml-expected0]
FAILED test/integration/test_template_parameters.py::test_parameters[Incorrectly configured deployment file-parameters1-test/fixtures/templates/integration/deployment-file-template.yaml-expected1]
FAILED test/integration/test_template_parameters.py::test_parameters[Multiple deployment files-parameters2-test/fixtures/templates/integration/deployment-file-template.yaml-expected2]
FAILED test/unit/module/cfn_json/test_cfn_json.py::TestCfnJson::test_success_parse - AssertionError: Expected 5 failu...
FAILED test/unit/module/cfn_json/test_cfn_json.py::TestCfnJson::test_success_parse_stdin - AssertionError: Expected 5...
FAILED test/unit/module/cfn_yaml/test_yaml.py::TestYamlParse::test_success_parse - AssertionError: Expected 1 failure...
FAILED test/unit/module/cfn_yaml/test_yaml.py::TestYamlParse::test_success_parse_stdin - AssertionError: Expected 1 f...
FAILED test/unit/module/context/test_resource.py::test_resource[Valid resource-instance0-expected_ref0] - cfnlint.sch...
FAILED test/unit/module/context/test_resource.py::test_nested_stacks[Nested stack with no Properties-instance0-foo/bar.yaml-None-expected_getatts0]
FAILED test/unit/module/context/test_resource.py::test_nested_stacks[Nested stack with template URL-instance1-foo/bar.yaml-None-expected_getatts1]
FAILED test/unit/module/context/test_resource.py::test_nested_stacks[Nested stack with a None filename-instance2-None-None-expected_getatts2]
FAILED test/unit/module/context/test_resource.py::test_nested_stacks[Nested stack with a local file but match error-instance5-foo/bar.yaml-decode_results5-expected_getatts5]
FAILED test/unit/module/override/test_complete.py::TestComplete::test_fail_run - AssertionError: 3 != 5 : [[E3006: Va...
FAILED test/unit/module/override/test_complete.py::TestComplete::test_success_run - AssertionError: Lists differ: [] ...
FAILED test/unit/module/override/test_exclude.py::TestExclude::test_fail_run - AssertionError: 2 != 3
FAILED test/unit/module/override/test_exclude.py::TestExclude::test_success_run - AssertionError: Lists differ: [] !=...
FAILED test/unit/module/override/test_include.py::TestInclude::test_fail_run - AssertionError: 2 != 4
FAILED test/unit/module/override/test_required.py::TestOverrideRequired::test_fail_run - AssertionError: 1 != 0 : []
FAILED test/unit/module/override/test_required.py::TestOverrideRequired::test_success_run - AssertionError: Lists dif...
FAILED test/unit/module/runner/template/test_template_runner.py::TestRunner::test_runner - AssertionError: 5 != 4 : G...
FAILED test/unit/module/runner/template/test_template_runner.py::TestRunner::test_runner_mandatory_rules - AssertionE...
FAILED test/unit/module/runner/test_cli.py::TestCli::test_templates_with_stdin - AssertionError: 2 != 0
FAILED test/unit/module/schema/test_manager.py::TestManagerGetResourceSchema::test_getting_cached_schema - cfnlint.sc...
FAILED test/unit/module/schema/test_manager.py::TestManagerGetResourceSchema::test_getting_us_east_1_schema_in_iso - ...
FAILED test/unit/module/template/test_getatts.py::TestGetAtts::test_getatt_resource_with_list - ValueError: Attribute...
FAILED test/unit/module/test_api.py::TestLint::test_issues_template - AssertionError: Lists differ: ['E1020'] != ['E3...
FAILED test/unit/module/test_api.py::TestLint::test_noecho_yaml_template - AssertionError: Lists differ: ['W2010', 'W...
FAILED test/unit/module/test_api.py::TestLint::test_noecho_yaml_template_warnings_ignored - AssertionError: Lists dif...
FAILED test/unit/module/test_api.py::TestLint::test_sam_template - AssertionError: Lists differ: [] != [[E3006: Valid...
FAILED test/unit/module/test_api.py::TestV0Usage::test_issues_template - AssertionError: Lists differ: ['E1020'] != [...
FAILED test/unit/module/test_api.py::TestV0Usage::test_noecho_yaml_template - AssertionError: Lists differ: ['W2010',...
FAILED test/unit/module/test_api.py::TestV0Usage::test_noecho_yaml_template_warnings_ignored - AssertionError: Lists ...
FAILED test/unit/module/test_api.py::TestV0Usage::test_sam_template - AssertionError: Lists differ: [] != [[E3006: Va...
FAILED test/unit/module/test_api.py::TestLintFile::test_good_template - AssertionError: Lists differ: [] != [[E3006: ...
FAILED test/unit/module/test_api.py::TestLintFile::test_issues_template - AssertionError: Lists differ: ['E1020'] != ...
FAILED test/unit/module/test_api.py::TestLintFile::test_noecho_yaml_template - AssertionError: Lists differ: ['W2010'...
FAILED test/unit/module/test_api.py::TestLintFile::test_noecho_yaml_template_warnings_ignored - AssertionError: Lists...
FAILED test/unit/module/test_api.py::TestLintFile::test_sam_template - AssertionError: Lists differ: [] != [[E3006: V...
FAILED test/unit/module/test_rules_collections.py::TestRulesCollection::test_fail_run - AssertionError: Expected 41 f...
FAILED test/unit/module/test_rules_collections.py::TestRulesCollection::test_success_run - AssertionError: assert [[E...
FAILED test/unit/rules/functions/test_getatt.py::test_validate[Invalid GetAtt with bad attribute-instance1-schema1-template1-child_rules1-expected1]
FAILED test/unit/rules/functions/test_getatt.py::test_validate[Invalid GetAtt with a bad response type-instance4-schema4-template4-child_rules4-expected4]
FAILED test/unit/rules/functions/test_getatt.py::test_validate[Invalid GetAtt with a bad response type and multiple types-instance5-schema5-template5-child_rules5-expected5]
FAILED test/unit/rules/functions/test_getatt.py::test_validate[Invalid Ref in GetAtt for attribute-instance11-schema11-template11-child_rules11-expected11]
FAILED test/unit/rules/functions/test_getatt_format.py::test_validate[Invalid GetAtt with a bad format-instance6-schema6-expected6]
FAILED test/unit/rules/functions/test_getatt_format.py::test_validate[Invalid GetAtt with a getatt and no format-instance7-schema7-expected7]
FAILED test/unit/rules/functions/test_ref_format.py::test_validate[Invalid Ref with a bad format-MyVpc-schema2-expected2]
FAILED test/unit/rules/functions/test_ref_format.py::test_validate[Invalid Ref with a resource with no format-MyBucket-schema3-expected3]
FAILED test/unit/rules/functions/test_sub.py::test_validate[Invalid Fn::Sub with a GetAtt and a bad attribute-instance19-schema19-expected19]
FAILED test/unit/rules/functions/test_sub.py::test_validate[Invalid Fn::Sub with a GetAtt to an array of attributes-instance21-schema21-expected21]
FAILED test/unit/rules/functions/test_sub.py::test_validate[Invalid Fn::Sub with a GetAtt to an integer-instance22-schema22-expected22]
FAILED test/unit/rules/resources/sns/test_subscription_endpoint_protocol.py::test_validate[template2-start_path2-validators2-1]
FAILED test/unit/rules/resources/sns/test_subscription_endpoint_protocol.py::test_validate[template3-start_path3-validators3-1]
FAILED test/unit/rules/resources/test_primary_identifiers.py::TestPrimaryIdentifiers::test_file_negative_alias - Asse...
FAILED test/unit/rules/resources/test_type.py::TestType::test_property_names - AssertionError: Lists differ: [<Valida...
============================== 70 failed, 2552 passed, 3 deselected in 198.97s (0:03:18) ==============================

@kddejong I'm not entirely sure if i am doing something wrong on my side, but are there issues with Tests on the main branch?

@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.23077% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.40%. Comparing base (8f9ba99) to head (b005376).
⚠️ Report is 11 commits behind head on main.

Files with missing lines Patch % Lines
.../resources/stepfunctions/StateMachineDefinition.py 89.23% 2 Missing and 5 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4465      +/-   ##
==========================================
- Coverage   94.42%   94.40%   -0.03%     
==========================================
  Files         430      430              
  Lines       15099    15126      +27     
  Branches     2924     2937      +13     
==========================================
+ Hits        14257    14279      +22     
- Misses        461      462       +1     
- Partials      381      385       +4     
Flag Coverage Δ
unittests 94.40% <89.23%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@kddejong

Copy link
Copy Markdown
Contributor

Should be better. I've been working on separating out the schema work into its own repository. Testing is a lot more clean now if you do another re-base or merge with main.

@r-heimann
r-heimann force-pushed the main branch 3 times, most recently from 4702183 to 5cdb3d8 Compare June 28, 2026 07:12
@r-heimann

Copy link
Copy Markdown
Contributor Author

@kddejong Thank you, i have rebased my branch and done

pip install -e ".[full]"
cfn-lint -u
tox -e py313
tox -e style

and the tests are passing, would you be so kind to trigger the pipeline once more?


yield ValidationError(message, path=error_path, rule=self)
while to_visit:
current = to_visit.pop(0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to_visit.pop(0) is O(n) per pop since it shifts all elements. collections.deque is already imported — switch to deque with popleft() for O(1).

to_visit.append(target)
state_type = state.get("Type")

if state_type == "Parallel":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old code iterated all states to find nested Parallel/Map sub-state-machines. The new code only recurses into nested state machines within reachable states. Is this intentional? It means nested validation errors inside unreachable states won't surface until reachability is fixed. Seems reasonable — just confirming it's deliberate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: AWS::StepFunctions::StateMachine - Recognize if state is unreachable

2 participants