diff --git a/.github/check_file_permissions.py b/.github/check_file_permissions.py new file mode 100644 index 0000000..3667b58 --- /dev/null +++ b/.github/check_file_permissions.py @@ -0,0 +1,73 @@ +# Copyright 2026 Google LLC +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# 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. +""" +Check testfiles data directory for non-executable permissions. +""" + +import sys +import logging +import argparse +import subprocess +from pathlib import Path + +logger = logging.getLogger("capa.tests.data") + + +def main(argv=None): + if argv is None: + argv = sys.argv[1:] + + parser = argparse.ArgumentParser() + parser.add_argument("testfiles", type=str, help="Path to tests/data repository root") + args = parser.parse_args(args=argv) + + test_failed = check_permissions(Path(args.testfiles)) + if test_failed: + return 1 + else: + logger.info("test file permissions look good!") + return 0 + + +def check_permissions(testfiles_path: Path) -> bool: + """ + Ensure all files in the testfiles repository are tracked in Git as non-executable (100644). + """ + test_failed = False + try: + output = subprocess.check_output( + ["git", "ls-files", "-s"], + cwd=testfiles_path, + text=True, + ) + for line in output.splitlines(): + if not line: + continue + + # Git format: \t + header, _, filename = line.partition("\t") + mode = header.split(" ", 1)[0] + + if mode == "100755": + logger.error("file tracked as executable (100755): %s", filename.strip('"')) + test_failed = True + except (subprocess.SubprocessError, FileNotFoundError) as e: + logger.warning("could not verify git file modes: %s", e) + + return test_failed + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + sys.exit(main()) diff --git a/.github/check_runtimes.py b/.github/check_runtimes.py index fa610c3..106fd0f 100644 --- a/.github/check_runtimes.py +++ b/.github/check_runtimes.py @@ -22,6 +22,7 @@ from pathlib import Path import capa.main +from capa.main import E_FILE_LIMITATION logger = logging.getLogger("capa.tests.data") @@ -49,19 +50,22 @@ def main(argv=None): continue time0 = time.time() - capa_ret = capa.main.main(["-q", "-v", "-d", str(file)]) - diff = time.time() - time0 + try: + capa_ret = capa.main.main(["-q", "-v", "-d", str(file)]) + diff = time.time() - time0 - if capa_ret: - logger.info("capa failed on file %s", file) + if capa_ret not in (0, E_FILE_LIMITATION): + logger.error("capa failed on file %s with return code %s", file, capa_ret) + test_failed = True + elif diff > THRESHOLD: + logger.error("capa ran for %s seconds on %s, please provide a different sample so we can test more quickly", diff, file) + test_failed = True + else: + logger.info("all good, capa ran for %.2f seconds on %s", diff, file) + except Exception as e: + logger.error("capa encountered an exception on file %s: %s", file, e, exc_info=True) test_failed = True - if diff > THRESHOLD: - logger.info("capa ran for %s seconds, please provide a different sample so we can test more quickly", diff) - test_failed = True - else: - logger.info("all good, capa ran for %s seconds", diff) - if test_failed: return 1 else: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ce7dd3e..9b25baf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,6 +22,18 @@ jobs: python-version: '3.10' - name: Test repository files run: python .github/check_sample_filenames.py . + # file permission consistency + test_permissions: + runs-on: ubuntu-latest + steps: + - name: Checkout testfiles repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Set up Python 3.10 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.10' + - name: Test repository file permissions + run: python .github/check_file_permissions.py . # to allow quicker tests, capa should run less than THRESHOLD seconds on added/modified test files test_runtime: runs-on: ubuntu-latest diff --git a/055da8e6ccfe5a9380231ea04b850e18.elf_ b/055da8e6ccfe5a9380231ea04b850e18.elf_ old mode 100755 new mode 100644 diff --git a/2055994ff75b4309eee3a49c5749d306.exe_ b/2055994ff75b4309eee3a49c5749d306.exe_ old mode 100755 new mode 100644 diff --git a/22d0a2e4c9c2163b2bf5f0e41a2e1762.exe_ b/22d0a2e4c9c2163b2bf5f0e41a2e1762.exe_ old mode 100755 new mode 100644 diff --git a/276f691a3df25481f59d79781799e35f.exe_ b/276f691a3df25481f59d79781799e35f.exe_ old mode 100755 new mode 100644 diff --git a/2855ba06b90e7c64d9bce888e47baf6d.exe_ b/2855ba06b90e7c64d9bce888e47baf6d.exe_ old mode 100755 new mode 100644 diff --git a/2f9ff544d5cc945b453356f9b20c07d8.exe_ b/2f9ff544d5cc945b453356f9b20c07d8.exe_ old mode 100755 new mode 100644 diff --git a/32b3678f8c29437e9ea10eab10194f66.exe_ b/32b3678f8c29437e9ea10eab10194f66.exe_ old mode 100755 new mode 100644 diff --git a/3446b3889a52d81119d8c482a2a282b9.exe_ b/3446b3889a52d81119d8c482a2a282b9.exe_ old mode 100755 new mode 100644 diff --git a/35f9cfe5110471a82e330d904c97466a.dll_ b/35f9cfe5110471a82e330d904c97466a.dll_ old mode 100755 new mode 100644 diff --git a/368239d36d221d8877a07ab6799e643a.elf_ b/368239d36d221d8877a07ab6799e643a.elf_ old mode 100755 new mode 100644 diff --git a/3da7c2c70a2d93ac4643f20339d5c7d61388bddd77a4a5fd732311efad78e535.elf_ b/3da7c2c70a2d93ac4643f20339d5c7d61388bddd77a4a5fd732311efad78e535.elf_ old mode 100755 new mode 100644 diff --git a/44461306a604d2cd9883c2bb623af276.dll_ b/44461306a604d2cd9883c2bb623af276.dll_ old mode 100755 new mode 100644 diff --git a/4b9efd882c49ef7525370ffb5197ad86.raw64 b/4b9efd882c49ef7525370ffb5197ad86.raw64 old mode 100755 new mode 100644 diff --git a/4e9c546a54e40d0da89bb4616dd7f8c4.exe_ b/4e9c546a54e40d0da89bb4616dd7f8c4.exe_ old mode 100755 new mode 100644 diff --git a/559efe9f3d4864910d5c5edbaadd3972c6dfc3ba887c48aa6728b0093898563f.dll_ b/559efe9f3d4864910d5c5edbaadd3972c6dfc3ba887c48aa6728b0093898563f.dll_ old mode 100755 new mode 100644 diff --git a/5b99fa01c72cebc53a76cc72e9581189.dll_ b/5b99fa01c72cebc53a76cc72e9581189.dll_ old mode 100755 new mode 100644 diff --git a/7f15b1a47bbe031334e23653879e9661f4b8cde80c307548328fdd3aed87ca46.exe_ b/7f15b1a47bbe031334e23653879e9661f4b8cde80c307548328fdd3aed87ca46.exe_ old mode 100755 new mode 100644 diff --git a/7fd2e2e3c88675d877190abaa3002b55.dll_ b/7fd2e2e3c88675d877190abaa3002b55.dll_ old mode 100755 new mode 100644 diff --git a/91b08896fbda9edb8b6f93a6bc811ec6.dll_ b/91b08896fbda9edb8b6f93a6bc811ec6.dll_ old mode 100755 new mode 100644 diff --git a/92d8ea10ea30e8b534334a1c9857a455.exe_ b/92d8ea10ea30e8b534334a1c9857a455.exe_ old mode 100755 new mode 100644 diff --git a/9e4d06759f278255073f9ac7b31a115a.dll_ b/9e4d06759f278255073f9ac7b31a115a.dll_ old mode 100755 new mode 100644 diff --git a/README.md b/README.md index 0cc1966..4de3147 100644 --- a/README.md +++ b/README.md @@ -26,3 +26,7 @@ We use the following conventions to organize the capa test data. - `/dotnet`: .NET test binaries - `/sigs`: test signatures - `/source`: source language test files e.g. C# and Python + +## File permissions +All files in this repository must be tracked in Git with non-executable permissions (`100644`). +Do not set the executable bit (`+x` / `100755`) on any test files or test scripts. diff --git a/a1451e3108e85769302ad25c74757180.exe_ b/a1451e3108e85769302ad25c74757180.exe_ old mode 100755 new mode 100644 diff --git a/a563c50c5fa0fd541248acaf72cc4e7d.exe_ b/a563c50c5fa0fd541248acaf72cc4e7d.exe_ old mode 100755 new mode 100644 diff --git a/b5f0524e69b3a3cf636c7ac366ca57bf5e3a8fdc8a9f01caf196c611a7918a87.elf_ b/b5f0524e69b3a3cf636c7ac366ca57bf5e3a8fdc8a9f01caf196c611a7918a87.elf_ old mode 100755 new mode 100644 diff --git a/bf7a9c8bdfa6d47e01ad2b056264acc3fd90cf43fe0ed8deec93ab46b47d76cb.elf_ b/bf7a9c8bdfa6d47e01ad2b056264acc3fd90cf43fe0ed8deec93ab46b47d76cb.elf_ old mode 100755 new mode 100644 diff --git a/c3699d0c7bd1276184249a487c1f0d7f.exe_ b/c3699d0c7bd1276184249a487c1f0d7f.exe_ old mode 100755 new mode 100644 diff --git a/c66172b12971a329f8d5ff01665f204b.exe_ b/c66172b12971a329f8d5ff01665f204b.exe_ old mode 100755 new mode 100644 diff --git a/dotnet/1ee70f829fa4f21b97fea53412383b4c83be1aaf8bab2f4b692549f8ceb4388f.dll_ b/dotnet/1ee70f829fa4f21b97fea53412383b4c83be1aaf8bab2f4b692549f8ceb4388f.dll_ old mode 100755 new mode 100644 diff --git a/dotnet/692f7fd6d198e804d6af98eb9e390d61.exe_ b/dotnet/692f7fd6d198e804d6af98eb9e390d61.exe_ old mode 100755 new mode 100644 diff --git a/e4c33ac3638eef68311f8ac0d72483c7.exe_ b/e4c33ac3638eef68311f8ac0d72483c7.exe_ old mode 100755 new mode 100644 diff --git a/e5e8c139772efe47f738f4788ae9b3dc97960b1c006bc6a406715cab69f27cfc.elf_ b/e5e8c139772efe47f738f4788ae9b3dc97960b1c006bc6a406715cab69f27cfc.elf_ old mode 100755 new mode 100644 diff --git a/ea2876e9175410b6f6719f80ee44b9553960758c7d0f7bed73c0fe9a78d8e669.dll_ b/ea2876e9175410b6f6719f80ee44b9553960758c7d0f7bed73c0fe9a78d8e669.dll_ old mode 100755 new mode 100644 diff --git a/ffeae4a391a1d5203bd04b4161557227.exe_ b/ffeae4a391a1d5203bd04b4161557227.exe_ old mode 100755 new mode 100644