Skip to content

Commit

Permalink
Merge branch 'master' into dependabot/pip/black-24.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
psantos-consensys authored Jun 19, 2024
2 parents 8094d8e + 1274004 commit 43f1199
Show file tree
Hide file tree
Showing 67 changed files with 19,102 additions and 334 deletions.
29 changes: 24 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,26 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
python-version: [ "3.7", "3.8", "3.9", "3.10", "3.11", "pypy3.7", "pypy3.8", "pypy3.9" ]
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12", "pypy3.8", "pypy3.9", "pypy3.10" ]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install Python dependencies
uses: py-actions/py-dependency-install@v4
with:
path: "requirements_dev.txt"
- name: Setup tox for GH actions
run: pip install tox-gh-actions
- name: Test with tox
run: make test
test_windows:
runs-on: windows-latest
strategy:
matrix:
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12", "pypy3.8", "pypy3.9", "pypy3.10" ]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -25,26 +44,26 @@ jobs:

deploy:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
needs: test
needs: [test, test_windows]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.11"
- name: Install Python dependencies
uses: py-actions/py-dependency-install@v4
with:
path: "requirements_dev.txt"
path: "requirements_deploy.txt"
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: make release

notify-slack:
needs: test
needs: [test, test_windows]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'
steps:
Expand Down
29 changes: 29 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
# History

0.13.3 (2024-06-17)
--------------------
- Fix hardhat artifacts collection

0.13.2 (2024-06-17)
--------------------
- Fix hardhat artifacts collection

0.13.1 (2024-06-11)
--------------------
- Fix hardhat artifacts collection
- Add `output` option to `fuzz run --dry-run` command

0.13.0 (2024-06-04)
--------------------
- Add Windows support
- Drop support for Python 3.7
- Add support for Python 3.12

0.12.3 (2024-05-23)
--------------------
- Unlinked libraries detection for Foundry and Hardhat project
- Update checks for fuzzing cli. Now fuzzing cli will check for new versions and notify the user if a new version is available

0.12.2 (2024-04-23)
--------------------
- Fix hardhat artifacts collection
- Ignore library contracts by default

0.12.1 (2024-03-07)
--------------------
- Change `fuzz run` command behavior on contract targets absence (now it will emit warning instead of an error)
Expand Down
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ Table of Contents
- [Product Analytics Collection](#product-analytics-collection)

## Installing
The Diligence Fuzzing CLI runs on Python 3.7+, including PyPy.

The Diligence Fuzzing CLI runs on Python 3.8+, including PyPy.
### Linux and macOS
To get started, simply run

```console
Expand All @@ -45,6 +45,25 @@ $ python3 setup.py install
```
> Don't forget to add the directory containing the `fuzz` executable to your system's PATH environment variable.
### Windows
> We recommend using Windows Subsystem for Linux (WSL) for a better experience
1. Install [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) for CLI's dependencies compilation
2. Run the following command to install the CLI
```console
$ pip3 install diligence-fuzzing
```

Alternatively, clone the repository and run

```console
$ pip3 install .
```
Or directly through Python's :code:`setuptools`:
```console
$ python3 setup.py install
```
> Don't forget to add the directory containing the `fuzz` executable to your system's PATH environment variable.
# Basic Usage
Fuzz is a command-line tool for smart contract fuzzing. It provides several modes of fuzzing, including smart mode, manual mode, and Foundry tests fuzzing.

Expand Down
50 changes: 26 additions & 24 deletions docs/configuration.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion fuzzing_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

__author__ = """Dominik Muhs"""
__email__ = "dominik.muhs@consensys.net"
__version__ = "0.12.1"
__version__ = "0.13.3"
5 changes: 5 additions & 0 deletions fuzzing_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@

from fuzzing_cli import __version__
from fuzzing_cli.fuzz.arm import fuzz_arm
from fuzzing_cli.fuzz.config import AdditionalOptions
from fuzzing_cli.fuzz.disarm import fuzz_disarm
from fuzzing_cli.fuzz.foundry_tests import cli as foundry_test
from fuzzing_cli.fuzz.fuzz_config import cli as fuzz_config
from fuzzing_cli.fuzz.fuzzing_lessons import cli as fuzz_lesson
from fuzzing_cli.fuzz.quickcheck import fuzz_auto
from fuzzing_cli.fuzz.run import fuzz_run
from fuzzing_cli.fuzz.utils import check_latest_version
from fuzzing_cli.fuzz.version import fuzz_version

LOGGER = logging.getLogger("fuzzing-cli")
Expand Down Expand Up @@ -71,6 +73,9 @@ def cli(ctx, debug: bool, config: str) -> None:

LOGGER.debug(f"Initializing tool name middleware with {__version__}")

options = AdditionalOptions()
check_latest_version(options)


LOGGER.debug("Registering main commands")

Expand Down
22 changes: 10 additions & 12 deletions fuzzing_cli/fuzz/arm.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import logging
from pathlib import Path
from typing import List, Optional, Tuple

import click
from click import ClickException, style

from fuzzing_cli.fuzz.analytics import trace
from fuzzing_cli.fuzz.config import AnalyzeOptions, FuzzingOptions, omit_none
from fuzzing_cli.fuzz.exceptions import ScribbleError
from fuzzing_cli.fuzz.scribble import ScribbleMixin
from fuzzing_cli.fuzz.utils import detect_ide
from fuzzing_cli.util import sol_files_by_directory
Expand All @@ -20,13 +22,13 @@ def handle_validation_errors(
fuzzing_options: FuzzingOptions,
prompt: bool = True,
smart_mode: bool = False,
) -> List[str]:
) -> List[Path]:
if len(targets) > 0:
return targets
return [Path(t) for t in targets]

_IDEClass = detect_ide(fuzzing_options)
suggested_targets = sorted(
sol_files_by_directory(str(_IDEClass.get_default_sources_dir()))
sol_files_by_directory(_IDEClass.get_default_sources_dir())
)

data = "\n".join([f" ◦ {file_name}" for file_name in suggested_targets])
Expand All @@ -37,7 +39,7 @@ def handle_validation_errors(
):
return suggested_targets
click.secho(error_message)
return targets
return [Path(t) for t in targets]


@click.command("arm")
Expand All @@ -46,7 +48,7 @@ def handle_validation_errors(
"--scribble-path",
type=click.Path(),
default=None,
help="Path to a custom scribble executable (beta)",
help="Path to a custom scribble executable",
)
@click.option(
"--remap-import",
Expand Down Expand Up @@ -142,11 +144,7 @@ def fuzz_arm(
raise ClickException(
f"ScribbleError:\nThere was an error instrumenting your contracts with scribble:\n{err}"
)
except FileNotFoundError:
raise click.exceptions.UsageError(
f'Scribble not found at path "{options.scribble_path}". '
f"Please provide scribble path using either `--scribble-path` option to `fuzz arm` command "
f"or set one in config"
)
except Exception as e:
except ClickException:
raise
except Exception as e:
raise ScribbleError(e)
27 changes: 13 additions & 14 deletions fuzzing_cli/fuzz/config/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ def determine_smart_mode(confirm: bool = False) -> bool:
return use_smart_mode


def __select_targets(targets: List[str]) -> List[str]:
def __select_targets(targets: List[Path]) -> List[Path]:
files = []
files_in_dirs = []
for target in targets:
if Path(target).is_dir():
if target.is_dir():
files_in_dirs.extend(sorted(sol_files_by_directory(target)))
else:
files.append(target)
Expand All @@ -86,30 +86,30 @@ def __select_targets(targets: List[str]) -> List[str]:
click.secho(
"⚠️ No targets are selected, please configure them manually in a config file"
)
targets = answers.get("targets", []) + files
targets = [Path(t) for t in answers.get("targets", [])] + files
return targets


def __prompt_targets() -> List[str]:
def __prompt_targets() -> List[Path]:
target = click.prompt(
f"{QM} Specify folder(s) or smart-contract(s) (comma-separated) to fuzz"
)
targets = [
t.strip()
Path(t.strip())
if Path(t.strip()).is_absolute()
else str(Path.cwd().absolute().joinpath(t.strip()))
else Path.cwd().absolute().joinpath(t.strip())
for t in target.split(",")
]
return targets


def determine_targets(ide: str) -> List[str]:
def determine_targets(ide: str) -> List[Path]:
repo = IDERepository.get_instance()
_IDEArtifactsClass = repo.get_ide(ide)
target = _IDEArtifactsClass.get_default_sources_dir()
ts = style(target, fg="yellow")

targets = [str(target)]
targets = [target]

if target.exists() and target.is_dir():
if not click.confirm(
Expand Down Expand Up @@ -188,17 +188,17 @@ def determine_campaign_name() -> str:
return name


def determine_sources_dir(targets: List[str]) -> Optional[str]:
def determine_sources_dir(targets: List[Path]) -> Optional[Path]:
if len(targets) == 0:
return None
if len(targets) == 1:
if Path(targets[0]).is_dir():
if targets[0].is_dir():
# looks like contracts directory
return targets[0]
# return parent folder of the contract file
return str(Path(targets[0]).parent)
return targets[0].parent
# return common parent of target files
return commonpath(targets)
return Path(commonpath(targets))


def recreate_config(config_file: str):
Expand Down Expand Up @@ -240,8 +240,7 @@ def recreate_config(config_file: str):
click.echo(
f"⚡️ Alright! Generating config at {style(config_path, fg='yellow', italic=True)}"
)

with config_path.open("w") as f:
with config_path.open("w", encoding="utf-8") as f:
f.write(
generate_yaml(
{
Expand Down
12 changes: 10 additions & 2 deletions fuzzing_cli/fuzz/config/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@ def yaml_config_settings_source(key="fuzz"):
def loader(_) -> Dict[str, Any]:
# this env variable is set by -c option in the cli (e.g. fuzz -c .fuzz-test.yaml run,
# or FUZZ_CONFIG_FILE=.fuzz-test.yaml)
config_path = os.environ.get("FUZZ_CONFIG_FILE", ".fuzz.yml")
if Path(config_path).is_file():
config_path = Path(os.environ.get("FUZZ_CONFIG_FILE", ".fuzz.yml"))
if config_path.is_file():
LOGGER.debug(f"Parsing config at {config_path}")
with open(config_path) as config_f:
parsed_config = yaml.safe_load(config_f.read())
if not parsed_config:
return {}
return parsed_config.get(key, {}) or {}
return {}

Expand Down Expand Up @@ -104,8 +106,13 @@ class FuzzingOptions(BaseSettings):
target_contracts: Optional[Dict[str, Set[str]]] = None

dry_run: bool = False
dry_run_output: Optional[str] = Field(None, exclude=True)
smart_mode: bool = False

include_library_contracts: bool = False

check_updates: bool = True

ci_mode: bool = Field(False)

no_build_directory: bool = Field(False, exclude=True)
Expand Down Expand Up @@ -326,6 +333,7 @@ class AdditionalOptions(BaseSettings):
ci_mode: bool = Field(False)
report_crashes: bool = Field(True)
allow_analytics: bool = Field(True)
check_updates: bool = Field(True)

def __init__(self, *args, **data: Any):
try:
Expand Down
Loading

0 comments on commit 43f1199

Please sign in to comment.