From 39bc993debb639df23aa2e059a9b27e8a238776d Mon Sep 17 00:00:00 2001 From: cats2101 Date: Fri, 24 Apr 2026 00:05:04 +0000 Subject: [PATCH] feat: honor slither.config.json in slither-check-upgradeability Closes #1260 --- slither/tools/upgradeability/__main__.py | 10 ++++ tests/unit/tools/test_upgradeability_cli.py | 51 +++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 tests/unit/tools/test_upgradeability_cli.py diff --git a/slither/tools/upgradeability/__main__.py b/slither/tools/upgradeability/__main__.py index f0031eff7c..be7e0b57a2 100644 --- a/slither/tools/upgradeability/__main__.py +++ b/slither/tools/upgradeability/__main__.py @@ -13,6 +13,7 @@ from slither.core.declarations import Contract from slither.exceptions import SlitherException from slither.utils.colors import red +from slither.utils.command_line import read_config_file from slither.utils.output import output_to_json from slither.tools.upgradeability.checks import all_checks from slither.tools.upgradeability.checks.abstract_checks import ( @@ -117,6 +118,14 @@ def parse_args(check_classes: list[type[AbstractCheck]]) -> argparse.Namespace: default="", ) + parser.add_argument( + "--config-file", + help="Provide a config file (default: slither.config.json or slither.conf.json)", + action="store", + dest="config_file", + default=None, + ) + parser.add_argument( "--wiki-detectors", help=argparse.SUPPRESS, action=OutputWiki, default=False ) @@ -286,6 +295,7 @@ def main() -> None: detectors = _get_checks() args = parse_args(detectors) + read_config_file(args) detectors_to_run = choose_checks(args, detectors) v1_filename = vars(args)["contract.sol"] number_detectors_run = 0 diff --git a/tests/unit/tools/test_upgradeability_cli.py b/tests/unit/tools/test_upgradeability_cli.py new file mode 100644 index 0000000000..6a01ebc9ab --- /dev/null +++ b/tests/unit/tools/test_upgradeability_cli.py @@ -0,0 +1,51 @@ +"""Tests for slither-check-upgradeability CLI wiring.""" + +import json +import sys + +import pytest + +from slither.tools.upgradeability.__main__ import _get_checks, parse_args +from slither.utils.command_line import read_config_file + + +@pytest.fixture +def in_tmp_cwd(tmp_path, monkeypatch): + monkeypatch.chdir(tmp_path) + return tmp_path + + +def _invoke_parse_args(monkeypatch, argv): + monkeypatch.setattr(sys, "argv", argv) + return parse_args(_get_checks()) + + +def test_parser_exposes_config_file(monkeypatch): + args = _invoke_parse_args( + monkeypatch, + ["slither-check-upgradeability", "x.sol", "Foo", "--config-file", "custom.json"], + ) + assert args.config_file == "custom.json" + + +def test_parser_config_file_defaults_to_none(monkeypatch): + args = _invoke_parse_args(monkeypatch, ["slither-check-upgradeability", "x.sol", "Foo"]) + assert args.config_file is None + + +def test_read_config_file_autodetects_default(in_tmp_cwd, monkeypatch): + (in_tmp_cwd / "slither.config.json").write_text(json.dumps({"exclude_low": True})) + args = _invoke_parse_args(monkeypatch, ["slither-check-upgradeability", "x.sol", "Foo"]) + assert args.exclude_low is False + read_config_file(args) + assert args.config_file == "slither.config.json" + assert args.exclude_low is True + + +def test_read_config_file_applies_solc_remaps(in_tmp_cwd, monkeypatch): + (in_tmp_cwd / "slither.config.json").write_text( + json.dumps({"solc_remaps": "@openzeppelin=node_modules/@openzeppelin"}) + ) + args = _invoke_parse_args(monkeypatch, ["slither-check-upgradeability", "x.sol", "Foo"]) + read_config_file(args) + assert args.solc_remaps == "@openzeppelin=node_modules/@openzeppelin"