diff --git a/setup.py b/setup.py index 332f8fc183..f5435b1eb9 100644 --- a/setup.py +++ b/setup.py @@ -21,6 +21,7 @@ "eth-abi>=4.0.0", "eth-typing>=3.0.0", "eth-utils>=2.1.0", + "shtab>=1.6.5", ], extras_require={ "lint": [ diff --git a/slither/__main__.py b/slither/__main__.py index d1b36d951b..3c127a4a10 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -18,6 +18,7 @@ from crytic_compile.platform.standard import generate_standard_export from crytic_compile.platform.etherscan import SUPPORTED_NETWORK from crytic_compile import compile_all, is_supported +import shtab from slither.detectors import all_detectors from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification @@ -290,7 +291,9 @@ def parse_args( usage=usage, ) - parser.add_argument("filename", help=argparse.SUPPRESS) + shtab.add_argument_to(parser) + + parser.add_argument("filename", help=argparse.SUPPRESS).complete = shtab.FILE cryticparser.init(parser) @@ -465,28 +468,28 @@ def parse_args( help='Export the results as a JSON file ("--json -" to export to stdout)', action="store", default=defaults_flag_in_config["json"], - ) + ).complete = shtab.FILE group_misc.add_argument( "--sarif", help='Export the results as a SARIF JSON file ("--sarif -" to export to stdout)', action="store", default=defaults_flag_in_config["sarif"], - ) + ).complete = shtab.FILE group_misc.add_argument( "--sarif-input", help="Sarif input (beta)", action="store", default=defaults_flag_in_config["sarif_input"], - ) + ).complete = shtab.FILE group_misc.add_argument( "--sarif-triage", help="Sarif triage (beta)", action="store", default=defaults_flag_in_config["sarif_triage"], - ) + ).complete = shtab.FILE group_misc.add_argument( "--json-types", @@ -502,13 +505,14 @@ def parse_args( help="Export the results as a zipped JSON file", action="store", default=defaults_flag_in_config["zip"], - ) + ).complete = shtab.FILE group_misc.add_argument( "--zip-type", help=f'Zip compression type. One of {",".join(ZIP_TYPES_ACCEPTED.keys())}. Default lzma', action="store", default=defaults_flag_in_config["zip_type"], + choices=list(ZIP_TYPES_ACCEPTED.keys()), ) group_misc.add_argument( @@ -540,7 +544,7 @@ def parse_args( action="store", dest="config_file", default=None, - ) + ).complete = shtab.FILE group_misc.add_argument( "--change-line-prefix", diff --git a/slither/tools/doctor/__main__.py b/slither/tools/doctor/__main__.py index f401781a77..570f370e46 100644 --- a/slither/tools/doctor/__main__.py +++ b/slither/tools/doctor/__main__.py @@ -3,6 +3,7 @@ import sys from crytic_compile import cryticparser +import shtab from slither.tools.doctor.utils import report_section from slither.tools.doctor.checks import ALL_CHECKS @@ -18,7 +19,9 @@ def parse_args() -> argparse.Namespace: usage="slither-doctor project", ) - parser.add_argument("project", help="The codebase to be tested.") + shtab.add_argument_to(parser) + + parser.add_argument("project", help="The codebase to be tested.").complete = shtab.FILE # Add default arguments from crytic-compile cryticparser.init(parser) diff --git a/slither/tools/documentation/__main__.py b/slither/tools/documentation/__main__.py index 0244dd6c67..30a0bdda1d 100644 --- a/slither/tools/documentation/__main__.py +++ b/slither/tools/documentation/__main__.py @@ -3,6 +3,7 @@ import uuid from typing import Optional, Dict, List from crytic_compile import cryticparser +import shtab from slither import Slither from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.declarations import Function @@ -26,7 +27,9 @@ def parse_args() -> argparse.Namespace: usage="slither-documentation filename", ) - parser.add_argument("project", help="The target directory/Solidity file.") + shtab.add_argument_to(parser) + + parser.add_argument("project", help="The target directory/Solidity file.").complete = shtab.FILE parser.add_argument( "--overwrite", help="Overwrite the files (be careful).", action="store_true", default=False diff --git a/slither/tools/erc_conformance/__main__.py b/slither/tools/erc_conformance/__main__.py index 1c9224eacb..fc3025893b 100644 --- a/slither/tools/erc_conformance/__main__.py +++ b/slither/tools/erc_conformance/__main__.py @@ -4,6 +4,7 @@ from typing import Any, Dict, List, Callable from crytic_compile import cryticparser +import shtab from slither import Slither from slither.core.declarations import Contract @@ -42,7 +43,9 @@ def parse_args() -> argparse.Namespace: usage="slither-check-erc project contractName", ) - parser.add_argument("project", help="The codebase to be tested.") + shtab.add_argument_to(parser) + + parser.add_argument("project", help="The codebase to be tested.").complete = shtab.FILE parser.add_argument( "contract_name", @@ -61,7 +64,7 @@ def parse_args() -> argparse.Namespace: help='Export the results as a JSON file ("--json -" to export to stdout)', action="store", default=False, - ) + ).complete = shtab.FILE # Add default arguments from crytic-compile cryticparser.init(parser) diff --git a/slither/tools/flattening/__main__.py b/slither/tools/flattening/__main__.py index bf9856fe84..06b3caed5e 100644 --- a/slither/tools/flattening/__main__.py +++ b/slither/tools/flattening/__main__.py @@ -4,6 +4,7 @@ from crytic_compile import cryticparser from crytic_compile.utils.zip import ZIP_TYPES_ACCEPTED +import shtab from slither import Slither from slither.tools.flattening.flattening import ( @@ -28,7 +29,11 @@ def parse_args() -> argparse.Namespace: usage="slither-flat filename", ) - parser.add_argument("filename", help="The filename of the contract or project to analyze.") + shtab.add_argument_to(parser) + + parser.add_argument( + "filename", help="The filename of the contract or project to analyze." + ).complete = shtab.FILE parser.add_argument("--contract", help="Flatten one contract.", default=None) @@ -44,27 +49,28 @@ def parse_args() -> argparse.Namespace: "--dir", help=f"Export directory (default: {DEFAULT_EXPORT_PATH}).", default=None, - ) + ).complete = shtab.DIRECTORY group_export.add_argument( "--json", help='Export the results as a JSON file ("--json -" to export to stdout)', action="store", default=None, - ) + ).complete = shtab.FILE parser.add_argument( "--zip", help="Export all the files to a zip file", action="store", default=None, - ) + ).complete = shtab.FILE parser.add_argument( "--zip-type", help=f"Zip compression type. One of {','.join(ZIP_TYPES_ACCEPTED.keys())}. Default lzma", action="store", default=None, + choices=list(ZIP_TYPES_ACCEPTED.keys()), ) group_patching = parser.add_argument_group("Patching options") diff --git a/slither/tools/interface/__main__.py b/slither/tools/interface/__main__.py index 0705f0373a..f2c525ca99 100644 --- a/slither/tools/interface/__main__.py +++ b/slither/tools/interface/__main__.py @@ -3,6 +3,7 @@ from pathlib import Path from crytic_compile import cryticparser +import shtab from slither import Slither from slither.utils.code_generation import generate_interface @@ -22,11 +23,13 @@ def parse_args() -> argparse.Namespace: usage=("slither-interface "), ) + shtab.add_argument_to(parser) + parser.add_argument( "contract_source", help="The name of the contract (case sensitive) followed by the deployed contract address if verified on etherscan or project directory/filename for local contracts.", nargs="+", - ) + ).complete = shtab.FILE parser.add_argument( "--unroll-structs", diff --git a/slither/tools/kspec_coverage/__main__.py b/slither/tools/kspec_coverage/__main__.py index 19933e0feb..c2ee993234 100644 --- a/slither/tools/kspec_coverage/__main__.py +++ b/slither/tools/kspec_coverage/__main__.py @@ -2,6 +2,7 @@ import logging import argparse from crytic_compile import cryticparser +import shtab from slither.tools.kspec_coverage.kspec_coverage import kspec_coverage logging.basicConfig() @@ -26,9 +27,11 @@ def parse_args() -> argparse.Namespace: usage="slither-kspec-coverage contract.sol kspec.md", ) + shtab.add_argument_to(parser) + parser.add_argument( "contract", help="The filename of the contract or truffle directory to analyze." - ) + ).complete = shtab.FILE parser.add_argument( "kspec", help="The filename of the Klab spec markdown for the analyzed contract(s)", @@ -45,7 +48,7 @@ def parse_args() -> argparse.Namespace: help='Export the results as a JSON file ("--json -" to export to stdout)', action="store", default=False, - ) + ).complete = shtab.FILE cryticparser.init(parser) diff --git a/slither/tools/mutator/__main__.py b/slither/tools/mutator/__main__.py index 5c13d7aeae..0fc4863fc1 100644 --- a/slither/tools/mutator/__main__.py +++ b/slither/tools/mutator/__main__.py @@ -6,6 +6,7 @@ import shutil from typing import Type, List, Any, Optional from crytic_compile import cryticparser +import shtab from slither import Slither from slither.tools.mutator.mutators import all_mutators from slither.utils.colors import yellow, magenta @@ -38,6 +39,8 @@ def parse_args() -> argparse.Namespace: usage="slither-mutate --test-cmd ", ) + shtab.add_argument_to(parser) + parser.add_argument("codebase", help="Codebase to analyze (.sol file, project directory, ...)") parser.add_argument( @@ -63,7 +66,7 @@ def parse_args() -> argparse.Namespace: # output directory argument parser.add_argument( "--output-dir", help="Name of output directory (by default 'mutation_campaign')" - ) + ).complete = shtab.DIRECTORY # to print just all the mutants parser.add_argument( diff --git a/slither/tools/properties/__main__.py b/slither/tools/properties/__main__.py index b5e5c911a3..a4d69de7ad 100644 --- a/slither/tools/properties/__main__.py +++ b/slither/tools/properties/__main__.py @@ -4,6 +4,7 @@ from typing import Any from crytic_compile import cryticparser +import shtab from slither import Slither from slither.tools.properties.properties.erc20 import generate_erc20, ERC20_PROPERTIES @@ -73,9 +74,11 @@ def parse_args() -> argparse.Namespace: formatter_class=argparse.RawDescriptionHelpFormatter, ) + shtab.add_argument_to(parser) + parser.add_argument( "filename", help="The filename of the contract or project directory to analyze." - ) + ).complete = shtab.FILE parser.add_argument("--contract", help="The targeted contract.") diff --git a/slither/tools/read_storage/__main__.py b/slither/tools/read_storage/__main__.py index 3baa5d351a..5001ab792b 100644 --- a/slither/tools/read_storage/__main__.py +++ b/slither/tools/read_storage/__main__.py @@ -5,6 +5,7 @@ import argparse from crytic_compile import cryticparser +import shtab from slither import Slither from slither.exceptions import SlitherError @@ -29,6 +30,8 @@ def parse_args() -> argparse.Namespace: ), ) + shtab.add_argument_to(parser) + parser.add_argument( "contract_source", help="The deployed contract address if verified on etherscan. Prepend project directory for unverified contracts.", @@ -77,7 +80,7 @@ def parse_args() -> argparse.Namespace: "--json", action="store", help="Save the result in a JSON file.", - ) + ).complete = shtab.FILE parser.add_argument( "--value", diff --git a/slither/tools/similarity/__main__.py b/slither/tools/similarity/__main__.py index 86673fccd4..da596ce495 100755 --- a/slither/tools/similarity/__main__.py +++ b/slither/tools/similarity/__main__.py @@ -5,6 +5,7 @@ import sys from crytic_compile import cryticparser +import shtab from slither.tools.similarity.info import info from slither.tools.similarity.test import test @@ -22,11 +23,15 @@ def parse_args() -> argparse.Namespace: description="Code similarity detection tool. For usage, see https://github.com/crytic/slither/wiki/Code-Similarity-detector" ) + shtab.add_argument_to(parser) + parser.add_argument("mode", help="|".join(modes)) - parser.add_argument("model", help="model.bin") + parser.add_argument("model", help="model.bin").complete = shtab.FILE - parser.add_argument("--filename", action="store", dest="filename", help="contract.sol") + parser.add_argument( + "--filename", action="store", dest="filename", help="contract.sol" + ).complete = shtab.FILE parser.add_argument("--fname", action="store", dest="fname", help="Target function") @@ -51,7 +56,7 @@ def parse_args() -> argparse.Namespace: parser.add_argument( "--input", action="store", dest="input", help="File or directory used as input" - ) + ).complete = shtab.FILE parser.add_argument( "--version", diff --git a/slither/tools/slither_format/__main__.py b/slither/tools/slither_format/__main__.py index 85c0a3917f..f09e1ec5bf 100644 --- a/slither/tools/slither_format/__main__.py +++ b/slither/tools/slither_format/__main__.py @@ -2,6 +2,7 @@ import argparse import logging from crytic_compile import cryticparser +import shtab from slither import Slither from slither.utils.command_line import read_config_file from slither.tools.slither_format.slither_format import slither_format @@ -30,9 +31,11 @@ def parse_args() -> argparse.Namespace: """ parser = argparse.ArgumentParser(description="slither_format", usage="slither_format filename") + shtab.add_argument_to(parser) + parser.add_argument( "filename", help="The filename of the contract or truffle directory to analyze." - ) + ).complete = shtab.FILE parser.add_argument( "--verbose-test", "-v", @@ -60,7 +63,7 @@ def parse_args() -> argparse.Namespace: action="store", dest="config_file", default="slither.config.json", - ) + ).complete = shtab.FILE group_detector = parser.add_argument_group("Detectors") group_detector.add_argument( diff --git a/slither/tools/upgradeability/__main__.py b/slither/tools/upgradeability/__main__.py index 56b838b9c1..0a545b2b2c 100644 --- a/slither/tools/upgradeability/__main__.py +++ b/slither/tools/upgradeability/__main__.py @@ -6,6 +6,7 @@ from typing import List, Any, Type, Dict, Tuple, Union, Sequence, Optional from crytic_compile import cryticparser +import shtab from slither import Slither @@ -36,9 +37,11 @@ def parse_args(check_classes: List[Type[AbstractCheck]]) -> argparse.Namespace: usage="slither-check-upgradeability contract.sol ContractName", ) + shtab.add_argument_to(parser) + group_checks = parser.add_argument_group("Checks") - parser.add_argument("contract.sol", help="Codebase to analyze") + parser.add_argument("contract.sol", help="Codebase to analyze").complete = shtab.FILE parser.add_argument("ContractName", help="Contract name (logic contract)") parser.add_argument("--proxy-name", help="Proxy name") @@ -47,14 +50,14 @@ def parse_args(check_classes: List[Type[AbstractCheck]]) -> argparse.Namespace: parser.add_argument("--new-contract-name", help="New contract name (if changed)") parser.add_argument( "--new-contract-filename", help="New implementation filename (if different)" - ) + ).complete = shtab.FILE parser.add_argument( "--json", help='Export the results as a JSON file ("--json -" to export to stdout)', action="store", default=False, - ) + ).complete = shtab.FILE group_checks.add_argument( "--detect",