fix: correct capa/subscope-rule key in RuleMetadata.from_capa

`RuleMetadata.from_capa` used `rule.meta.get("capa/subscope", False)` and
`Field(False, alias="capa/subscope")`, but the actual key set by
`_extract_subscope_rules_rec` is `"capa/subscope-rule"`. This caused
`is_subscope_rule` to always be `False` in every `RuleMetadata` instance,
making downstream filters in `render/utils.py`, `render/vverbose.py`, and
`scripts/import-to-ida.py` ineffective (though subscope rules are already
excluded from `ResultDocument` before reaching those callers).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Willi Ballenthin
2026-04-22 17:29:38 +03:00
co-authored by Claude Sonnet 4.6
parent 099c9d41b7
commit 47760269f8
3 changed files with 32 additions and 2 deletions
+1
View File
@@ -11,6 +11,7 @@
-
### Bug Fixes
- fix: correct capa/subscope-rule key in RuleMetadata so is_subscope_rule is no longer always False @williballenthin
- fix: remove unreachable backports.functools_lru_cache fallback and dead dependency @williballenthin
- fix: add missing ELF branch in get_format_from_extension for .elf_ files @williballenthin #3031
- fix: Scopes.from_dict uses cls instead of self so subclasses return the correct type @williballenthin
+2 -2
View File
@@ -658,7 +658,7 @@ class RuleMetadata(FrozenModel):
description: str
lib: bool = Field(False, alias="lib")
is_subscope_rule: bool = Field(False, alias="capa/subscope")
is_subscope_rule: bool = Field(False, alias="capa/subscope-rule")
maec: MaecMetadata
@classmethod
@@ -674,7 +674,7 @@ class RuleMetadata(FrozenModel):
examples=rule.meta.get("examples", []),
description=rule.meta.get("description", ""),
lib=rule.meta.get("lib", False),
is_subscope_rule=rule.meta.get("capa/subscope", False),
is_subscope_rule=rule.meta.get("capa/subscope-rule", False),
maec=MaecMetadata(
analysis_conclusion=rule.meta.get("maec/analysis-conclusion"),
analysis_conclusion_ov=rule.meta.get("maec/analysis-conclusion-ov"),
+29
View File
@@ -13,11 +13,13 @@
# limitations under the License.
import copy
import textwrap
import pytest
import fixtures
import capa
import capa.rules
import capa.engine as ceng
import capa.render.result_document as rdoc
import capa.features.freeze.features as frzf
@@ -291,3 +293,30 @@ def test_rdoc_to_capa():
meta, capabilites = rd.to_capa()
assert isinstance(meta, rdoc.Metadata)
assert isinstance(capabilites, Capabilities)
def test_rule_metadata_is_subscope_rule_alias():
rule = capa.rules.Rule.from_yaml(
textwrap.dedent("""
rule:
meta:
name: test rule
scopes:
static: function
dynamic: process
authors:
- test
features:
- api: CreateFile
""")
)
meta = rdoc.RuleMetadata.from_capa(rule)
assert meta.is_subscope_rule is False
raw = meta.model_dump(by_alias=True)
assert "capa/subscope-rule" in raw
assert raw["capa/subscope-rule"] is False
raw["capa/subscope-rule"] = True
meta_true = rdoc.RuleMetadata.model_validate(raw)
assert meta_true.is_subscope_rule is True