Skip to content

Commit 23630e9

Browse files
committed
feat(sdk): add scanner-specific help for argus scan <name> --help
argus scan gitleaks --help now shows gitleaks-specific information: - Scanner description (from class docstring) - Tool installation status (installed locally or not) - Install command (if not installed) - Container image reference - Usage examples specific to that scanner - Common options Unknown scanner names show the list of available scanners. Implemented by intercepting --help in main() before argparse exits, then introspecting the scanner module from SCANNER_REGISTRY.
1 parent ba4527e commit 23630e9

1 file changed

Lines changed: 64 additions & 0 deletions

File tree

argus/cli.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,8 +681,72 @@ def _get_version() -> str:
681681
return "argus (unknown version)"
682682

683683

684+
def _show_scanner_help(scanner_name: str) -> None:
685+
"""Print scanner-specific help by introspecting the scanner module."""
686+
try:
687+
from argus.scanners import SCANNER_REGISTRY
688+
cls = SCANNER_REGISTRY.get(scanner_name)
689+
if cls is None:
690+
print(f"Unknown scanner: {scanner_name}")
691+
print(f"Available scanners: {', '.join(sorted(SCANNER_REGISTRY))}")
692+
sys.exit(EXIT_ERROR)
693+
694+
scanner = cls()
695+
print(f"argus scan {scanner_name}")
696+
print(f"{'=' * (len(scanner_name) + 11)}")
697+
print()
698+
699+
# Description from docstring
700+
doc = (cls.__doc__ or "").strip()
701+
if doc:
702+
print(doc)
703+
print()
704+
705+
# Key info
706+
print(f" Tool: {scanner_name}")
707+
available = scanner.is_available()
708+
print(f" Installed: {'yes' if available else 'no'}")
709+
710+
install = scanner.install_command()
711+
if install and not available:
712+
print(f" Install: {install}")
713+
714+
image = getattr(scanner, "container_image", "")
715+
if image:
716+
print(f" Container: {image}")
717+
718+
print()
719+
print("Usage:")
720+
print(f" argus scan {scanner_name} # scan current directory")
721+
print(f" argus scan {scanner_name} --path src/ # scan specific path")
722+
print(f" argus scan {scanner_name} --config argus.yml # use config file")
723+
print(f" argus scan {scanner_name} --verbose # debug output")
724+
print()
725+
print("Common options:")
726+
print(" --path, -p PATH Path to scan (default: .)")
727+
print(" --config, -c FILE Path to argus.yml config")
728+
print(" --output-dir, -o DIR Output directory (default: ./argus-results)")
729+
print(" --severity-threshold, -s LEVEL Fail threshold (critical/high/medium/low/none)")
730+
print(" --format, -f FORMAT Output format (terminal/markdown/sarif/json)")
731+
print(" --verbose, -v Enable debug output")
732+
733+
except ImportError:
734+
print(f"Scanner '{scanner_name}' — unable to load scanner module")
735+
736+
sys.exit(EXIT_SUCCESS)
737+
738+
684739
def main(argv: list[str] | None = None) -> None:
685740
"""CLI entry point. Parse arguments and dispatch to the appropriate subcommand."""
741+
# Intercept `argus scan <name> --help` before argparse exits
742+
raw_args = argv if argv is not None else sys.argv[1:]
743+
if (len(raw_args) >= 3
744+
and raw_args[0] == "scan"
745+
and raw_args[-1] in ("--help", "-h")
746+
and raw_args[1] not in ("--help", "-h", "--list")):
747+
scanner_name = raw_args[1]
748+
_show_scanner_help(scanner_name)
749+
686750
parser = build_parser()
687751
args = parser.parse_args(argv)
688752

0 commit comments

Comments
 (0)