Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use pre-commit to invoke linters #1591

Merged
merged 28 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
25a6d78
ruff: update config
williballenthin Jul 6, 2023
6f0d1f7
add pre-commit config
williballenthin Jul 6, 2023
75a76b4
setup: add pre-commit dev dependency
williballenthin Jul 6, 2023
691ef1c
remove old linter configs
williballenthin Jul 6, 2023
f17edb3
ci: use pre-commit to invoke linters
williballenthin Jul 6, 2023
adbfb8d
doc: installation: document pre-commit
williballenthin Jul 6, 2023
47074fd
fix ruff issues
williballenthin Jul 6, 2023
9441da4
isort
williballenthin Jul 6, 2023
90e607f
flake8
williballenthin Jul 6, 2023
511aa0f
doc: installation: more details on pre-commit
williballenthin Jul 6, 2023
e675bef
ci: invoke linter directly
williballenthin Jul 6, 2023
a43d2c1
tests: fix fixture imports
williballenthin Jul 6, 2023
982dc46
add flake8-bugbear linter
williballenthin Jul 6, 2023
9f6165f
doc: installation: better enumerate current linters
williballenthin Jul 6, 2023
3ad4de7
gitignore
williballenthin Jul 6, 2023
ff47270
add flake8-encoding plugin
williballenthin Jul 6, 2023
13a8e25
introduce flake8-comprehensions
williballenthin Jul 6, 2023
3ca233e
Merge branch 'master' into fix/issue-1579
williballenthin Jul 7, 2023
8c86011
changelog
williballenthin Jul 6, 2023
54203f3
introduce flake8-logging-format linter
williballenthin Jul 9, 2023
7fe738e
introduce flake8-no-implicit-concat linter
williballenthin Jul 9, 2023
106b12e
move flake8 config to its own config file
williballenthin Jul 9, 2023
4a49543
introduce flake8-print linter
williballenthin Jul 9, 2023
ae10a2e
introduce flake8-todos linter
williballenthin Jul 9, 2023
118b955
features: fix circular import
williballenthin Jul 9, 2023
430f9da
Merge branch 'master' into fix/issue-1579
williballenthin Jul 10, 2023
d89dd49
add issue links for TODOs
williballenthin Jul 9, 2023
f983307
Merge branch 'master' into fix/issue-1579
williballenthin Jul 10, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 49 additions & 6 deletions .github/ruff.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,53 @@
# Enable pycodestyle (`E`) codes
select = ["E"]
# Enable the pycodestyle (`E`) and Pyflakes (`F`) rules by default.
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
# McCabe complexity (`C901`) by default.
select = ["E", "F"]

# Allow autofix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []

# E402 module level import not at top of file
# E722 do not use bare 'except'
ignore = ["E402", "E722"]
exclude = ["*_pb2.py", "*_pb2.pyi"]
# E501 line too long
ignore = ["E402", "E722", "E501"]

line-length = 120

exclude = [
# Exclude a variety of commonly ignored directories.
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".mypy_cache",
".nox",
".pants.d",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"venv",
# protobuf generated files
"*_pb2.py",
"*_pb2.pyi"
]

# Same as pycodestyle.
line-length = 180
[per-file-ignores]
# until we address #1592 and move test fixtures into conftest.py
# then we need to ignore imports done to enable pytest fixtures.
#
# F401: `foo` imported but unused
# F811 Redefinition of unused `foo`
"tests/test_main.py" = ["F401", "F811"]
"tests/test_freeze.py" = ["F401", "F811"]
"tests/test_function_id.py" = ["F401", "F811"]
10 changes: 0 additions & 10 deletions .github/tox.ini

This file was deleted.

14 changes: 7 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ jobs:
- name: Install dependencies
run: pip install -e .[dev]
- name: Lint with ruff
run: ruff check --config .github/ruff.toml .
run: pre-commit run ruff
- name: Lint with isort
run: isort --profile black --length-sort --line-width 120 --skip-glob "*_pb2.py" -c .
run: pre-commit run isort
- name: Lint with black
run: black -l 120 --extend-exclude ".*_pb2.py" --check .
- name: Lint with pycodestyle
run: pycodestyle --exclude="*_pb2.py" --show-source capa/ scripts/ tests/
run: pre-commit run black
- name: Lint with flake8
run: pre-commit run flake8
- name: Check types with mypy
run: mypy --config-file .github/mypy/mypy.ini --check-untyped-defs capa/ scripts/ tests/
run: pre-commit run mypy

rule_linter:
runs-on: ubuntu-20.04
Expand All @@ -56,7 +56,7 @@ jobs:
with:
python-version: "3.8"
- name: Install capa
run: pip install -e .
run: pip install -e .[dev]
- name: Run rule linter
run: python scripts/lint.py rules/

Expand Down
119 changes: 119 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# install the pre-commit hooks:
#
# ❯ pre-commit install --hook-type pre-commit
# pre-commit installed at .git/hooks/pre-commit
#
# ❯ pre-commit install --hook-type pre-push
# pre-commit installed at .git/hooks/pre-push
#
# run all linters liks:
#
# ❯ pre-commit run --all-files
# isort....................................................................Passed
# black....................................................................Passed
# ruff.....................................................................Passed
# flake8...................................................................Passed
# mypy.....................................................................Passed
#
# run a single linter like:
#
# ❯ pre-commit run --all-files isort
# isort....................................................................Passed

repos:
- repo: local
hooks:
- id: isort
name: isort
stages: [commit, push]
language: system
entry: isort
args:
- "--length-sort"
- "--profile"
- "black"
- "--line-length=120"
- "--skip-glob"
- "*_pb2.py"
- "capa/"
- "scripts/"
- "tests/"
always_run: true
pass_filenames: false

- repo: local
hooks:
- id: black
name: black
stages: [commit, push]
language: system
entry: black
args:
- "--line-length=120"
- "--extend-exclude"
- ".*_pb2.py"
- "capa/"
- "scripts/"
- "tests/"
always_run: true
pass_filenames: false

- repo: local
hooks:
- id: ruff
name: ruff
# ruff is fast, so run during commit
stages: [commit, push]
language: system
entry: ruff
args:
- "check"
- "--config"
- ".github/ruff.toml"
- "capa/"
- "scripts/"
- "tests/"
always_run: true
pass_filenames: false

- repo: local
hooks:
- id: flake8
name: flake8
# flake8 is kinda slow, so only run upon push, or like:
#
# pre-commit run flake8 --hook-stage push
stages: [commit, push]
language: system
entry: flake8
args:
- "--max-line-length=120"
# E203: whitespace before ':' (black does this)
# F401: `foo` imported but unused (prefer ruff)
# F811 Redefinition of unused `foo` (prefer ruff)
# E501 line too long (prefer black)
- "--extend-ignore=E203,F401,F811,E501"
- "--extend-exclude"
- "capa/render/proto/capa_pb2.py"
- "capa/"
- "scripts/"
- "tests/"
always_run: true
pass_filenames: false

- repo: local
hooks:
- id: mypy
name: mypy
stages: [commit, push]
language: system
entry: mypy
args:
- "--check-untyped-defs"
- "--ignore-missing-imports"
- "--config-file=.github/mypy/mypy.ini"
- "capa/"
- "scripts/"
- "tests/"
always_run: true
pass_filenames: false
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
### New Features
- 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

### 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
Expand Down
2 changes: 1 addition & 1 deletion capa/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import copy
import collections
from typing import TYPE_CHECKING, Set, Dict, List, Tuple, Union, Mapping, Iterable, Iterator, cast
from typing import TYPE_CHECKING, Set, Dict, List, Tuple, Union, Mapping, Iterable, Iterator

import capa.perf
import capa.features.common
Expand Down
3 changes: 1 addition & 2 deletions capa/features/extractors/binja/basicblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from binaryninja import BasicBlock as BinjaBasicBlock
from binaryninja import (
BinaryView,
DataBuffer,
SymbolType,
RegisterValueType,
VariableSourceType,
Expand All @@ -26,7 +25,7 @@
)

from capa.features.common import Feature, Characteristic
from capa.features.address import Address, AbsoluteVirtualAddress
from capa.features.address import Address
from capa.features.basicblock import BasicBlock
from capa.features.extractors.helpers import MIN_STACKSTRING_LEN
from capa.features.extractors.base_extractor import BBHandle, FunctionHandle
Expand Down
2 changes: 1 addition & 1 deletion capa/features/extractors/binja/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import struct
from typing import Tuple, Iterator

from binaryninja import Symbol, Segment, BinaryView, SymbolType, SymbolBinding
from binaryninja import Segment, BinaryView, SymbolType, SymbolBinding

import capa.features.extractors.common
import capa.features.extractors.helpers
Expand Down
1 change: 0 additions & 1 deletion capa/features/extractors/binja/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
def extract_function_calls_to(fh: FunctionHandle):
"""extract callers to a function"""
func: Function = fh.inner
bv: BinaryView = func.view

for caller in func.caller_sites:
# Everything that is a code reference to the current function is considered a caller, which actually includes
Expand Down
2 changes: 0 additions & 2 deletions capa/features/extractors/binja/global_.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import logging
import contextlib
from typing import Tuple, Iterator

from binaryninja import BinaryView

import capa.features.extractors.elf
from capa.features.common import OS, OS_MACOS, ARCH_I386, ARCH_AMD64, OS_WINDOWS, Arch, Feature
from capa.features.address import NO_ADDRESS, Address

Expand Down
18 changes: 2 additions & 16 deletions capa/features/extractors/binja/insn.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# 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 sys
from typing import Any, Dict, List, Tuple, Iterator, Optional
from typing import Any, List, Tuple, Iterator, Optional

from binaryninja import Function
from binaryninja import BasicBlock as BinjaBasicBlock
Expand All @@ -18,12 +18,11 @@
RegisterValueType,
LowLevelILOperation,
LowLevelILInstruction,
InstructionTextTokenType,
)

import capa.features.extractors.helpers
from capa.features.insn import API, MAX_STRUCTURE_SIZE, Number, Offset, Mnemonic, OperandNumber, OperandOffset
from capa.features.common import MAX_BYTES_FEATURE_SIZE, THUNK_CHAIN_DEPTH_DELTA, Bytes, String, Feature, Characteristic
from capa.features.common import MAX_BYTES_FEATURE_SIZE, Bytes, String, Feature, Characteristic
from capa.features.address import Address, AbsoluteVirtualAddress
from capa.features.extractors.binja.helpers import DisassemblyInstruction, visit_llil_exprs
from capa.features.extractors.base_extractor import BBHandle, InsnHandle, FunctionHandle
Expand Down Expand Up @@ -73,7 +72,6 @@ def extract_insn_api_features(fh: FunctionHandle, bbh: BBHandle, ih: InsnHandle)
example:
call dword [0x00473038]
"""
insn: DisassemblyInstruction = ih.inner
func: Function = fh.inner
bv: BinaryView = func.view

Expand Down Expand Up @@ -128,12 +126,9 @@ def extract_insn_number_features(
example:
push 3136B0h ; dwControlCode
"""
insn: DisassemblyInstruction = ih.inner
func: Function = fh.inner
bv: BinaryView = func.view

results: List[Tuple[Any[Number, OperandNumber], Address]] = []
address_size = func.view.arch.address_size * 8

def llil_checker(il: LowLevelILInstruction, parent: LowLevelILInstruction, index: int) -> bool:
if il.operation == LowLevelILOperation.LLIL_LOAD:
Expand Down Expand Up @@ -171,7 +166,6 @@ def extract_insn_bytes_features(fh: FunctionHandle, bbh: BBHandle, ih: InsnHandl
example:
push offset iid_004118d4_IShellLinkA ; riid
"""
insn: DisassemblyInstruction = ih.inner
func: Function = fh.inner
bv: BinaryView = func.view

Expand Down Expand Up @@ -220,7 +214,6 @@ def extract_insn_string_features(
example:
push offset aAcr ; "ACR > "
"""
insn: DisassemblyInstruction = ih.inner
func: Function = fh.inner
bv: BinaryView = func.view

Expand Down Expand Up @@ -278,7 +271,6 @@ def extract_insn_offset_features(
example:
.text:0040112F cmp [esi+4], ebx
"""
insn: DisassemblyInstruction = ih.inner
func: Function = fh.inner

results: List[Tuple[Any[Offset, OperandOffset], Address]] = []
Expand Down Expand Up @@ -364,7 +356,6 @@ def extract_insn_nzxor_characteristic_features(
parse instruction non-zeroing XOR instruction
ignore expected non-zeroing XORs, e.g. security cookies
"""
insn: DisassemblyInstruction = ih.inner
func: Function = fh.inner

results = []
Expand Down Expand Up @@ -414,7 +405,6 @@ def extract_insn_peb_access_characteristic_features(

fs:[0x30] on x86, gs:[0x60] on x64
"""
insn: DisassemblyInstruction = ih.inner
func: Function = fh.inner

results = []
Expand Down Expand Up @@ -456,7 +446,6 @@ def extract_insn_segment_access_features(
fh: FunctionHandle, bbh: BBHandle, ih: InsnHandle
) -> Iterator[Tuple[Feature, Address]]:
"""parse instruction fs or gs access"""
insn: DisassemblyInstruction = ih.inner
func: Function = fh.inner

results = []
Expand Down Expand Up @@ -485,7 +474,6 @@ def extract_insn_cross_section_cflow(
fh: FunctionHandle, bbh: BBHandle, ih: InsnHandle
) -> Iterator[Tuple[Feature, Address]]:
"""inspect the instruction for a CALL or JMP that crosses section boundaries"""
insn: DisassemblyInstruction = ih.inner
func: Function = fh.inner
bv: BinaryView = func.view

Expand All @@ -509,7 +497,6 @@ def extract_function_calls_from(fh: FunctionHandle, bbh: BBHandle, ih: InsnHandl

most relevant at the function scope, however, its most efficient to extract at the instruction scope
"""
insn: DisassemblyInstruction = ih.inner
func: Function = fh.inner
bv: BinaryView = func.view

Expand Down Expand Up @@ -555,7 +542,6 @@ def extract_function_indirect_call_characteristic_features(
most relevant at the function or basic block scope;
however, its most efficient to extract at the instruction scope
"""
insn: DisassemblyInstruction = ih.inner
func: Function = fh.inner

llil = func.get_llil_at(ih.address)
Expand Down
Loading