From dd2bbc9a48368f603a369d128df910f7134cf56c Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Mon, 10 Jul 2023 01:44:38 +0200 Subject: [PATCH 1/5] migrate to pyproject.toml closes #1301 --- .github/workflows/publish.yml | 9 ++- pyproject.toml | 109 +++++++++++++++++++++++++++++++ setup.cfg | 28 -------- setup.py | 119 ---------------------------------- 4 files changed, 115 insertions(+), 150 deletions(-) create mode 100644 pyproject.toml delete mode 100644 setup.cfg delete mode 100644 setup.py diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 002a7095..9dacd323 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -19,11 +19,14 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install setuptools wheel twine - - name: Build and publish + pip install twine + pip install -e .[build] + - name: build package + run: | + python -m build + - name: publish package env: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | - python setup.py sdist bdist_wheel twine upload --skip-existing dist/* diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..f994243a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,109 @@ +# Copyright (C) 2023 Mandiant, 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. + +[build-system] +requires = ["setuptools", "setuptools-scm"] +build-backend = "setuptools.build_meta" + +[project] +name = "flare-capa" +authors = [ + {name = "Willi Ballenthin", email = "william.ballenthin@mandiant.com"}, + {name = "Moritz Raabe", email = "moritz.raabe@mandiant.com"}, + {name = "Mike Hunhoff", email = "michael.hunhoff@mandiant.com"}, +] +description = "The FLARE team's open-source tool to identify capabilities in executable files." +license = {file = "LICENSE.txt"} +requires-python = ">=3.8" +keywords = ["malware analysis", "reverse engineering", "capability detection", "software behaviors", "capa", "FLARE"] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: Information Technology", + "License :: OSI Approved :: Apache Software License", + "Natural Language :: English", + "Programming Language :: Python :: 3", + "Topic :: Security", +] +dependencies = [ + "tqdm==4.65.0", + "pyyaml==6.0", + "tabulate==0.9.0", + "colorama==0.4.6", + "termcolor==2.3.0", + "wcwidth==0.2.6", + "ida-settings==2.1.0", + "viv-utils[flirt]==0.7.9", + "halo==0.0.31", + "networkx==3.1", + "ruamel.yaml==0.17.32", + "vivisect==1.1.1", + "pefile==2023.2.7", + "pyelftools==0.29", + "dnfile==0.13.0", + "dncil==1.0.2", + "pydantic==1.10.9", + "protobuf==4.23.2", +] +dynamic = ["version", "readme"] + +[tool.setuptools.dynamic] +version = {attr = "capa.version.__version__"} +readme = {file = "README.md"} + +[tool.setuptools] +packages = ["capa"] + +[project.optional-dependencies] +dev = [ + "pre-commit==3.3.3", + "pytest==7.4.0", + "pytest-sugar==0.9.7", + "pytest-instafail==0.5.0", + "pytest-cov==4.1.0", + "flake8==6.0.0", + "flake8-bugbear==23.6.5", + "flake8-encodings==0.5.0.post1", + "flake8-comprehensions==3.13.0", + "flake8-logging-format==0.9.0", + "flake8-no-implicit-concat==0.3.4", + "flake8-print==5.0.0", + "flake8-todos==0.3.0", + "ruff==0.0.275", + "black==23.3.0", + "isort==5.11.4", + "mypy==1.4.1", + "psutil==5.9.2", + "stix2==3.0.1", + "requests==2.31.0", + "mypy-protobuf==3.4.0", + # type stubs for mypy + "types-backports==0.1.3", + "types-colorama==0.4.15.11", + "types-PyYAML==6.0.8", + "types-tabulate==0.9.0.1", + "types-termcolor==1.1.4", + "types-psutil==5.8.23", + "types_requests==2.31.0.1", + "types-protobuf==4.23.0.1", +] +build = [ + "pyinstaller==5.10.1", + "setuptools==68.0.0", + "build==0.10.0" +] + +[project.urls] +Homepage = "https://github.com/mandiant/capa" +Repository = "https://github.com/mandiant/capa.git" +Documentation = "https://github.com/mandiant/capa/tree/master/doc" +Rules = "https://github.com/mandiant/capa-rules" +"Rules Documentation" = "https://github.com/mandiant/capa-rules/tree/master/doc" + +[project.scripts] +capa = "capa.main:main" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 87eef850..00000000 --- a/setup.cfg +++ /dev/null @@ -1,28 +0,0 @@ -[bdist_wheel] -universal = 1 - -[aliases] -test = pytest - -[pycodestyle] -# the following suppress lints that conflict with the project's style: -# -# E203 Whitespace before : -# E302 expected 2 blank lines, found 1 -# E402 module level import not at top of file -# E501 line too long (209 > 180 characters) -# E712 comparison to False should be 'if cond is False:' or 'if not cond:' -# E722 do not use bare 'except' -# E731 do not assign a lambda expression, use a def -# W291 trailing whitespace -# W503 line break before binary operator -ignore = E203, E302, E402, E501, E712, E722, E731, W291, W503 -max-line-length = 180 -statistics = True - - -[pylint.FORMAT] -max-line-length = 180 - -[pylint] -disable = missing-docstring,invalid-name,import-outside-toplevel,redefined-outer-name,consider-using-f-string \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100644 index 284266a5..00000000 --- a/setup.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright (C) 2020 Mandiant, 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 setuptools - -requirements = [ - "tqdm==4.65.0", - "pyyaml==6.0", - "tabulate==0.9.0", - "colorama==0.4.6", - "termcolor==2.3.0", - "wcwidth==0.2.6", - "ida-settings==2.1.0", - "viv-utils[flirt]==0.7.9", - "halo==0.0.31", - "networkx==3.1", - "ruamel.yaml==0.17.32", - "vivisect==1.1.1", - "pefile==2023.2.7", - "pyelftools==0.29", - "dnfile==0.13.0", - "dncil==1.0.2", - "pydantic==1.10.9", - "protobuf==4.23.2", -] - -# this sets __version__ -# via: http://stackoverflow.com/a/7071358/87207 -# and: http://stackoverflow.com/a/2073599/87207 -with open(os.path.join("capa", "version.py"), "r") as f: - exec(f.read()) - - -# via: https://packaging.python.org/guides/making-a-pypi-friendly-readme/ -this_directory = os.path.abspath(os.path.dirname(__file__)) -with open(os.path.join(this_directory, "README.md"), "r") as f: - long_description = f.read() - - -setuptools.setup( - name="flare-capa", - version=__version__, - description="The FLARE team's open-source tool to identify capabilities in executable files.", - long_description=long_description, - long_description_content_type="text/markdown", - author="Willi Ballenthin, Moritz Raabe", - author_email="william.ballenthin@mandiant.com, moritz.raabe@mandiant.com", - url="https://www.github.com/mandiant/capa", - project_urls={ - "Documentation": "https://github.com/mandiant/capa/tree/master/doc", - "Rules": "https://github.com/mandiant/capa-rules", - "Rules Documentation": "https://github.com/mandiant/capa-rules/tree/master/doc", - }, - packages=setuptools.find_packages(exclude=["tests"]), - package_dir={"capa": "capa"}, - entry_points={ - "console_scripts": [ - "capa=capa.main:main", - ] - }, - include_package_data=True, - install_requires=requirements, - extras_require={ - "dev": [ - "pre-commit==3.3.3", - "pytest==7.4.0", - "pytest-sugar==0.9.7", - "pytest-instafail==0.5.0", - "pytest-cov==4.1.0", - "flake8==6.0.0", - "flake8-bugbear==23.6.5", - "flake8-encodings==0.5.0.post1", - "flake8-comprehensions==3.13.0", - "flake8-logging-format==0.9.0", - "flake8-no-implicit-concat==0.3.4", - "flake8-print==5.0.0", - "flake8-todos==0.3.0", - "ruff==0.0.275", - "black==23.3.0", - "isort==5.11.4", - "mypy==1.4.1", - "psutil==5.9.2", - "stix2==3.0.1", - "requests==2.31.0", - "mypy-protobuf==3.4.0", - # type stubs for mypy - "types-backports==0.1.3", - "types-colorama==0.4.15.11", - "types-PyYAML==6.0.8", - "types-tabulate==0.9.0.1", - "types-termcolor==1.1.4", - "types-psutil==5.8.23", - "types_requests==2.31.0.1", - "types-protobuf==4.23.0.1", - ], - "build": [ - "pyinstaller==5.10.1", - ], - }, - zip_safe=False, - keywords="capa malware analysis capability detection FLARE", - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "Intended Audience :: Information Technology", - "License :: OSI Approved :: Apache Software License", - "Natural Language :: English", - "Programming Language :: Python :: 3", - "Topic :: Security", - ], - python_requires=">=3.8", -) From fb176196eb04cde75e724a125a6c667d83ada943 Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Mon, 10 Jul 2023 01:46:06 +0200 Subject: [PATCH 2/5] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36f522f8..41525dfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Utility script to detect feature overlap between new and existing CAPA rules [#1451](https://github.com/mandiant/capa/issues/1451) [@Aayush-Goel-04](https://github.com/aayush-goel-04) - use fancy box drawing characters for default output #1586 @williballenthin - use [pre-commit](https://pre-commit.com/) to invoke linters #1579 @williballenthin +- migrate to pyproject.toml #1301 @williballenthin ### Breaking Changes - Update Metadata type in capa main [#1411](https://github.com/mandiant/capa/issues/1411) [@Aayush-Goel-04](https://github.com/aayush-goel-04) @manasghandat From cb289e3fc52d782595235c17f12b51f6bc63c0d9 Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Mon, 10 Jul 2023 01:57:42 +0200 Subject: [PATCH 3/5] ci: publish: use trusted publishing --- .github/workflows/publish.yml | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 002a7095..69b1c68b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,6 +1,5 @@ -# This workflows will upload a Python Package using Twine when a release is created -# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries - +# use PyPI trusted publishing, as described here: +# https://blog.trailofbits.com/2023/05/23/trusted-publishing-a-new-benchmark-for-packaging-security/ name: publish to pypi on: @@ -8,8 +7,12 @@ on: types: [published] jobs: - deploy: - runs-on: ubuntu-20.04 + pypi-publish: + runs-on: ubuntu-latest + environment: + name: release + permissions: + id-token: write steps: - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 - name: Set up Python @@ -19,11 +22,9 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install setuptools wheel twine - - name: Build and publish - env: - TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} - TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + pip install setuptools wheel + - name: build package run: | python setup.py sdist bdist_wheel - twine upload --skip-existing dist/* + - name: publish package + uses: pypa/gh-action-pypi-publish@release/v1 From 81b964386f1fc01a54b8022ea10cb566908023e4 Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Mon, 10 Jul 2023 02:06:06 +0200 Subject: [PATCH 4/5] ci: publish to PyPI using trusted publishing closes #1491 --- .github/workflows/publish.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 69b1c68b..e49acf80 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -26,5 +26,20 @@ jobs: - name: build package run: | python setup.py sdist bdist_wheel + - name: upload package artifacts + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + with: + name: ${{ matrix.asset_name }} + path: dist/* + - name: upload package to GH Release + uses: svenstaro/upload-release-action@2728235f7dc9ff598bd86ce3c274b74f802d2208 # v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN}} + file: dist/* + tag: ${{ github.ref }} - name: publish package - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@f5622bde02b04381239da3573277701ceca8f6a0 # release/v1 + with: + skip-existing: true + verbose: true + print-hash: true From 1f8aa7cfe19e2c405e13700ff5ab358ef6f6ecf1 Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Mon, 10 Jul 2023 02:07:19 +0200 Subject: [PATCH 5/5] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36f522f8..1a7ce69e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Utility script to detect feature overlap between new and existing CAPA rules [#1451](https://github.com/mandiant/capa/issues/1451) [@Aayush-Goel-04](https://github.com/aayush-goel-04) - use fancy box drawing characters for default output #1586 @williballenthin - use [pre-commit](https://pre-commit.com/) to invoke linters #1579 @williballenthin +- publish via PyPI trusted publishing #1491 @williballenthin ### Breaking Changes - Update Metadata type in capa main [#1411](https://github.com/mandiant/capa/issues/1411) [@Aayush-Goel-04](https://github.com/aayush-goel-04) @manasghandat