Repository: mandiant/capa
File: capa/capabilities/common.py (Python)

Code before:


def find_capabilities(ruleset: RuleSet, extractor: FeatureExtractor, disable_progress=None, **kwargs) -> Capabilities:
    from capa.capabilities.static import find_static_capabilities
    from capa.capabilities.dynamic import find_dynamic_capabilities

    if isinstance(extractor, StaticFeatureExtractor):
        # for the time being, extractors are either static or dynamic.
        # Remove this assertion once that has changed
        assert not isinstance(extractor, DynamicFeatureExtractor)
        return find_static_capabilities(ruleset, extractor, disable_progress=disable_progress, **kwargs)
    if isinstance(extractor, DynamicFeatureExtractor):
        return find_dynamic_capabilities(ruleset, extractor, disable_progress=disable_progress, **kwargs)

    raise ValueError(f"unexpected extractor type: {extractor.__class__.__name__}")


def is_static_limitation_rule(r: Rule) -> bool:
    return r.meta.get("namespace", "") == "internal/limitation/static"


def has_static_limitation(rules: RuleSet, capabilities: Capabilities | FileCapabilities, is_standalone=True) -> bool:

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

    return has_limitation(file_limitation_rules, capabilities, is_standalone)


def is_dynamic_limitation_rule(r: Rule) -> bool:
    return r.meta.get("namespace", "") == "internal/limitation/dynamic"


def has_dynamic_limitation(rules: RuleSet, capabilities: Capabilities | FileCapabilities, is_standalone=True) -> bool:

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


def has_limitation(rules: list, capabilities: Capabilities | FileCapabilities, is_standalone: bool) -> bool:

    for rule in rules:
        if rule.name not in capabilities.matches:
            continue
        logger.warning("-" * 80)
        for line in rule.meta.get("description", "").split("\n"):
            logger.warning(" %s", line)
        logger.warning(" Identified via rule: %s", rule.name)
        if is_standalone:
            logger.warning(" ")
            logger.warning(" Use -v or -vv if you really want to see the capabilities identified by capa.")
        logger.warning("-" * 80)

Review comment (suggestion):
```suggestion
def has_static_limitation(rules: RuleSet, capabilities: Capabilities | FileCapabilities, is_standalone=True) -> bool:
    file_limitation_rules = list(filter(lambda r: is_static_limitation_rule(r), rules.rules.values()))
    return has_limitation(file_limitation_rules, capabilities, is_standalone)
```

Code after:


def find_capabilities(ruleset: RuleSet, extractor: FeatureExtractor, disable_progress=None, **kwargs) -> Capabilities:
    from capa.capabilities.static import find_static_capabilities
    from capa.capabilities.dynamic import find_dynamic_capabilities

    if isinstance(extractor, StaticFeatureExtractor):
        # for the time being, extractors are either static or dynamic.
        # Remove this assertion once that has changed
        assert not isinstance(extractor, DynamicFeatureExtractor)
        return find_static_capabilities(ruleset, extractor, disable_progress=disable_progress, **kwargs)
    if isinstance(extractor, DynamicFeatureExtractor):
        return find_dynamic_capabilities(ruleset, extractor, disable_progress=disable_progress, **kwargs)

    raise ValueError(f"unexpected extractor type: {extractor.__class__.__name__}")


def has_limitation(rules: list, capabilities: Capabilities | FileCapabilities, is_standalone: bool) -> bool:

    for rule in rules:
        if rule.name not in capabilities.matches:
            continue
        logger.warning("-" * 80)
        for line in rule.meta.get("description", "").split("\n"):
            logger.warning(" %s", line)
        logger.warning(" Identified via rule: %s", rule.name)
        if is_standalone:
            logger.warning(" ")
            logger.warning(" Use -v or -vv if you really want to see the capabilities identified by capa.")
        logger.warning("-" * 80)

        # bail on first file limitation
        return True
    return False


def is_static_limitation_rule(r: Rule) -> bool:
    return r.meta.get("namespace", "") == "internal/limitation/static"


def has_static_limitation(rules: RuleSet, capabilities: Capabilities | FileCapabilities, is_standalone=True) -> bool:
    file_limitation_rules = list(filter(lambda r: is_static_limitation_rule(r), rules.rules.values()))
    return has_limitation(file_limitation_rules, capabilities, is_standalone)


def is_dynamic_limitation_rule(r: Rule) -> bool:
    return r.meta.get("namespace", "") == "internal/limitation/dynamic"


def has_dynamic_limitation(rules: RuleSet, capabilities: Capabilities | FileCapabilities, is_standalone=True) -> bool:
    dynamic_limitation_rules = list(filter(lambda r: is_dynamic_limitation_rule(r), rules.rules.values()))