Skip to content

Commit 02000d8

Browse files
committed
enhance capability handling with new Capabilities dataclass and update related functions
Signed-off-by: vibhatsu <maulikbarot2915@gmail.com>
1 parent 751a755 commit 02000d8

File tree

2 files changed

+28
-27
lines changed

2 files changed

+28
-27
lines changed

capa/capabilities/common.py

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,33 @@ def find_file_capabilities(
5858
return FileCapabilities(features, matches, len(file_features))
5959

6060

61+
@dataclass
62+
class Capabilities:
63+
matches: MatchResults
64+
feature_counts: StaticFeatureCounts | DynamicFeatureCounts
65+
library_functions: Optional[tuple[LibraryFunction, ...]] = None
66+
67+
68+
def find_capabilities(ruleset: RuleSet, extractor: FeatureExtractor, disable_progress=None, **kwargs) -> Capabilities:
69+
from capa.capabilities.static import find_static_capabilities
70+
from capa.capabilities.dynamic import find_dynamic_capabilities
71+
72+
if isinstance(extractor, StaticFeatureExtractor):
73+
# for the time being, extractors are either static or dynamic.
74+
# Remove this assertion once that has changed
75+
assert not isinstance(extractor, DynamicFeatureExtractor)
76+
return find_static_capabilities(ruleset, extractor, disable_progress=disable_progress, **kwargs)
77+
if isinstance(extractor, DynamicFeatureExtractor):
78+
return find_dynamic_capabilities(ruleset, extractor, disable_progress=disable_progress, **kwargs)
79+
80+
raise ValueError(f"unexpected extractor type: {extractor.__class__.__name__}")
81+
82+
6183
def is_static_limitation_rule(r: Rule) -> bool:
6284
return r.meta.get("namespace", "") == "internal/limitation/static"
6385

6486

65-
def has_static_limitation(rules: RuleSet, capabilities: MatchResults, is_standalone=True) -> bool:
87+
def has_static_limitation(rules: RuleSet, capabilities: Capabilities | FileCapabilities, is_standalone=True) -> bool:
6688

6789
file_limitation_rules = list(filter(lambda r: is_static_limitation_rule(r), rules.rules.values()))
6890

@@ -73,16 +95,16 @@ def is_dynamic_limitation_rule(r: Rule) -> bool:
7395
return r.meta.get("namespace", "") == "internal/limitation/dynamic"
7496

7597

76-
def has_dynamic_limitation(rules: RuleSet, capabilities: MatchResults, is_standalone=True) -> bool:
98+
def has_dynamic_limitation(rules: RuleSet, capabilities: Capabilities | FileCapabilities, is_standalone=True) -> bool:
7799

78100
dynamic_limitation_rules = list(filter(lambda r: is_dynamic_limitation_rule(r), rules.rules.values()))
79101
return has_limitation(dynamic_limitation_rules, capabilities, is_standalone)
80102

81103

82-
def has_limitation(rules: list, capabilities: MatchResults, is_standalone: bool) -> bool:
104+
def has_limitation(rules: list, capabilities: Capabilities | FileCapabilities, is_standalone: bool) -> bool:
83105

84106
for rule in rules:
85-
if rule.name not in capabilities:
107+
if rule.name not in capabilities.matches:
86108
continue
87109
logger.warning("-" * 80)
88110
for line in rule.meta.get("description", "").split("\n"):
@@ -96,25 +118,3 @@ def has_limitation(rules: list, capabilities: MatchResults, is_standalone: bool)
96118
# bail on first file limitation
97119
return True
98120
return False
99-
100-
101-
@dataclass
102-
class Capabilities:
103-
matches: MatchResults
104-
feature_counts: StaticFeatureCounts | DynamicFeatureCounts
105-
library_functions: Optional[tuple[LibraryFunction, ...]] = None
106-
107-
108-
def find_capabilities(ruleset: RuleSet, extractor: FeatureExtractor, disable_progress=None, **kwargs) -> Capabilities:
109-
from capa.capabilities.static import find_static_capabilities
110-
from capa.capabilities.dynamic import find_dynamic_capabilities
111-
112-
if isinstance(extractor, StaticFeatureExtractor):
113-
# for the time being, extractors are either static or dynamic.
114-
# Remove this assertion once that has changed
115-
assert not isinstance(extractor, DynamicFeatureExtractor)
116-
return find_static_capabilities(ruleset, extractor, disable_progress=disable_progress, **kwargs)
117-
if isinstance(extractor, DynamicFeatureExtractor):
118-
return find_dynamic_capabilities(ruleset, extractor, disable_progress=disable_progress, **kwargs)
119-
120-
raise ValueError(f"unexpected extractor type: {extractor.__class__.__name__}")

capa/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
FORMAT_BINEXPORT2,
101101
)
102102
from capa.capabilities.common import (
103+
Capabilities,
103104
find_capabilities,
104105
has_static_limitation,
105106
find_file_capabilities,
@@ -797,7 +798,7 @@ def find_dynamic_limitations_from_cli(args, rules: RuleSet, file_extractors: lis
797798
"""
798799
found_dynamic_limitation = False
799800
for file_extractor in file_extractors:
800-
pure_dynamic_capabilities, _ = find_file_capabilities(rules, file_extractor, {})
801+
pure_dynamic_capabilities = find_file_capabilities(rules, file_extractor, {})
801802
found_dynamic_limitation = has_dynamic_limitation(rules, pure_dynamic_capabilities)
802803

803804
# file limitations that rely on non-file scope won't be detected here.

0 commit comments

Comments
 (0)