diff --git a/CHANGELOG.md b/CHANGELOG.md index e1381441c2..b14b7eb083 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,6 +121,7 @@ - fix: remove redundant code related to cli loading @mike-hunhoff #3076 - fix: optimize all_zeros using fast bytes comparison @mike-hunhoff #3078 - fix: duplicate rule candidate evaluation in optimized matching engine @mike-hunhoff #3080 +- fix: capafmt corrupts rules whose namespace contains "features" @Makeph #3135 ### capa Explorer Web diff --git a/capa/rules/__init__.py b/capa/rules/__init__.py index ef4e372c70..b8a67a87a5 100644 --- a/capa/rules/__init__.py +++ b/capa/rules/__init__.py @@ -1374,7 +1374,7 @@ def move_to_end(m, k): # see #263 # only do this for the features section, so the meta description doesn't get reformatted # assumes features section always exists - features_offset = doc.find("features") + features_offset = doc.index("\n features:") + 1 doc = doc[:features_offset] + doc[features_offset:].replace(" description:", " description:") # for negative hex numbers, yaml dump outputs: diff --git a/tests/test_fmt.py b/tests/test_fmt.py index 05b1fafcd7..56e564f932 100644 --- a/tests/test_fmt.py +++ b/tests/test_fmt.py @@ -148,3 +148,24 @@ def test_rule_reformat_string_description(): rule = capa.rules.Rule.from_yaml(src) assert rule.to_yaml() == src + + +def test_rule_reformat_meta_description_with_features_namespace(): + src = textwrap.dedent(""" + rule: + meta: + name: test rule + namespace: impact/features + authors: + - user@domain.com + description: test description + scopes: + static: function + dynamic: process + features: + - number: 1 + """).lstrip() + + formatted = capa.rules.Rule.from_yaml(src).to_yaml() + capa.rules.Rule.from_yaml(formatted) + assert formatted == src