diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d70c674b..302987d7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -39,7 +39,7 @@ jobs: rule_linter: runs-on: ubuntu-20.04 steps: - - name: Checkout capa with rules submodule + - name: Checkout capa with submodules uses: actions/checkout@v2 with: submodules: true @@ -83,4 +83,4 @@ jobs: - name: Install capa run: pip install -e .[dev] - name: Run tests - run: pytest tests/ + run: pytest -v tests/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 377242ab..505f0065 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -145,7 +145,8 @@ It includes many new rules, including all new techniques introduced in MITRE ATT - ci, changelog: update `New Rules` section in CHANGELOG automatically https://github.com/fireeye/capa-rules/pull/374 #549 #604 @Ana06 - ci, changelog: support multiple author in sync GH https://github.com/fireeye/capa-rules/pull/378 @Ana06 - ci, lint: check statements for single child statements #563 @mr-tz -- ci: reject PRs without CHANGELOG update to ensure CHANGELOG is kept up-to-date. #584 @Ana06 +- ci: reject PRs without CHANGELOG update to ensure CHANGELOG is kept up-to-date #584 @Ana06 +- ci: test that scripts run #660 @mr-tz ### Raw diffs diff --git a/capa/main.py b/capa/main.py index 639c3884..32ef811d 100644 --- a/capa/main.py +++ b/capa/main.py @@ -433,7 +433,7 @@ class UnsupportedRuntimeError(RuntimeError): def get_extractor( - path: str, format: str, backend: str, sigpaths: List[str], should_save_workspace, disable_progress=False + path: str, format: str, backend: str, sigpaths: List[str], should_save_workspace=False, disable_progress=False ) -> FeatureExtractor: """ raises: diff --git a/scripts/show-features.py b/scripts/show-features.py index 78d3b370..3090a471 100644 --- a/scripts/show-features.py +++ b/scripts/show-features.py @@ -64,6 +64,7 @@ Example:: insn: 0x10001027: mnemonic(shl) ... """ +import os import sys import logging import os.path @@ -106,8 +107,11 @@ def main(argv=None): with open(args.sample, "rb") as f: extractor = capa.features.freeze.load(f.read()) else: + should_save_workspace = os.environ.get("CAPA_SAVE_WORKSPACE") not in ("0", "no", "NO", "n", None) try: - extractor = capa.main.get_extractor(args.sample, args.format, capa.main.BACKEND_VIV, sigpaths=sig_paths) + extractor = capa.main.get_extractor( + args.sample, args.format, capa.main.BACKEND_VIV, sig_paths, should_save_workspace + ) except capa.main.UnsupportedFormatError: logger.error("-" * 80) logger.error(" Input file does not appear to be a PE file.") diff --git a/tests/test_scripts.py b/tests/test_scripts.py new file mode 100644 index 00000000..13f39201 --- /dev/null +++ b/tests/test_scripts.py @@ -0,0 +1,57 @@ +# Copyright (C) 2020 FireEye, Inc. All Rights Reserved. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: [package root]/LICENSE.txt +# Unless required by applicable law or agreed to in writing, software distributed under the License +# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and limitations under the License. + +import os +import sys +import subprocess + +import pytest +from fixtures import CD, get_extractor, get_data_path_by_name + + +def get_script_path(s): + return os.path.join(CD, "..", "scripts", s) + + +def get_file_path(): + return get_extractor(get_data_path_by_name("9324d...")).path + + +def get_rules_path(): + return os.path.join(CD, "..", "rules") + + +def get_rule_path(): + return os.path.join(get_rules_path(), "lib", "allocate-memory.yml") + + +@pytest.mark.parametrize( + "script,args", + [ + pytest.param( + "show-features.py", + [get_file_path()], + ), + pytest.param("bulk-process.py", [get_file_path()]), + pytest.param("capa2yara.py", [get_rules_path()]), + pytest.param("capafmt.py", [get_rule_path()]), + # not testing lint.py as it runs regularly anyway + pytest.param("match-function-id.py", [get_file_path()]), + pytest.param("show-capabilities-by-function.py", [get_file_path()]), + pytest.param("show-features.py", [get_file_path()]), + pytest.param("show-features.py", ["-F", "0x407970", get_file_path()]), + ], +) +def test_scripts(script, args): + script_path = get_script_path(script) + p = run_program(script_path, args) + assert p.returncode == 0 + + +def run_program(script_path, args): + return subprocess.run([sys.executable] + [script_path] + args)