Skip to content

Enhance CLI help output with usage examples#1446

Open
pandeysudarshan16-ctrl wants to merge 8 commits intoOWASP:masterfrom
pandeysudarshan16-ctrl:feature-cli-help-examples
Open

Enhance CLI help output with usage examples#1446
pandeysudarshan16-ctrl wants to merge 8 commits intoOWASP:masterfrom
pandeysudarshan16-ctrl:feature-cli-help-examples

Conversation

@pandeysudarshan16-ctrl
Copy link
Copy Markdown

Proposed Change

Improved CLI usability by enhancing the help output with clear descriptions and practical usage examples.

Why this change is needed

Currently, the CLI help output lacks examples, making it harder for new users to understand how to use the tool effectively.

What is added

  • Added descriptive CLI overview
  • Added real-world usage examples
  • Improved help readability using formatter

Type of change

  • Other improvement (usability / UX)

Checklist

  • I have followed the contributing guidelines
  • I have tested the feature locally
  • No breaking changes introduced

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 24, 2026

Summary by CodeRabbit

  • Documentation

    • Updated README to clarify flexible target handling.
  • Improvements

    • Enhanced CLI help with richer usage examples and clearer formatting.
    • Improved handling of unrecognized command-line options: clearer error messages with helpful suggestions and immediate exit on unknown arguments.

Walkthrough

Updated README wording for the "Flexible targets" bullet. Enhanced the CLI argument parser: added description/epilog and RawTextHelpFormatter, switched to parse_known_args(), implemented explicit unknown-argument detection with stderr error messages, fuzzy "Did you mean" suggestions via difflib, and exit-on-error behavior.

Changes

Cohort / File(s) Summary
Documentation
README.md
Reworded and reformatted the "Flexible targets" bullet; removed the inline explanation about mixing targets and -l/--targets-list, replaced with a concise compatibility statement.
Core Argument Parsing
nettacker/core/arg_parser.py
Initialized ArgumentParser with description, multi-line epilog, and RawTextHelpFormatter; changed parsing to parse_known_args() when appropriate; added logic to collect registered option strings, report unknown/ unexpected arguments to stderr, offer closest-match suggestions via difflib.get_close_matches, and call sys.exit(1) on unknowns; downstream validation now uses known_args.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Enhance CLI help output with usage examples' directly and specifically describes the main changes: adding help output enhancements and usage examples as implemented in arg_parser.py.
Description check ✅ Passed The description is clearly related to the changeset, explaining the motivation for improving CLI help output, what was added (descriptive overview, examples, improved readability), and the type of change.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves OWASP Nettacker’s CLI usability by enhancing the --help output with a high-level description, usage examples, and more user-friendly handling of unknown CLI arguments (including “did you mean …” suggestions). It also updates the README’s “Flexible targets” feature text.

Changes:

  • Added CLI description + epilog usage examples and switched to RawTextHelpFormatter for help rendering.
  • Updated argument parsing to detect unknown args and suggest close-matching valid flags.
  • Tweaked README “Key Features” text around flexible targets.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
nettacker/core/arg_parser.py Adds richer help text (description/examples) and custom unknown-argument messaging with difflib suggestions.
README.md Adjusts “Flexible targets” documentation text in the feature list.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +552 to +565
for arg in unknown_args:
if arg.startswith("--") and len(arg) > 1:
suggestion = difflib.get_close_matches(arg, valid_flags, n=1)
if suggestion:
print(
f"Error: Unknown argument '{arg}'. Did you mean '{suggestion[0]}'?",
file=sys.stderr,
)
else:
print(f"Error: Unknown argument '{arg}'", file=sys.stderr)
else:
print(f"Error: Unexpected argument '{arg}'", file=sys.stderr)

sys.exit(1)
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown short options like -Z currently fall into the "Unexpected argument" branch, which is misleading (they’re still unknown options). Consider treating any token starting with - as an unknown option (and optionally suggesting close matches for short flags too). Also, using die_failure(...) (or self.error(...)) instead of print/sys.exit would keep error handling consistent with the rest of the CLI (logging + color reset).

Suggested change
for arg in unknown_args:
if arg.startswith("--") and len(arg) > 1:
suggestion = difflib.get_close_matches(arg, valid_flags, n=1)
if suggestion:
print(
f"Error: Unknown argument '{arg}'. Did you mean '{suggestion[0]}'?",
file=sys.stderr,
)
else:
print(f"Error: Unknown argument '{arg}'", file=sys.stderr)
else:
print(f"Error: Unexpected argument '{arg}'", file=sys.stderr)
sys.exit(1)
error_messages = []
for arg in unknown_args:
if arg.startswith("-") and len(arg) > 1:
suggestion = difflib.get_close_matches(arg, valid_flags, n=1)
if suggestion:
error_messages.append(
f"Error: Unknown option '{arg}'. Did you mean '{suggestion[0]}'?"
)
else:
error_messages.append(f"Error: Unknown option '{arg}'")
else:
error_messages.append(f"Error: Unexpected argument '{arg}'")
die_failure("\n".join(error_messages))

Copilot uses AI. Check for mistakes.
Comment thread README.md
Comment on lines +30 to +31
- **Flexible targets**: Accepts single IPv4s, IP ranges, CIDR blocks, domain names, and full HTTP/HTTPS URLs.
These methods ensure full compatibility and avoid runtime errors
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This addition breaks the bullet list formatting and reads as an unsupported/vague claim. Consider keeping it as part of the Flexible targets bullet (with a period) or removing it; also the previous text documented the -l/--targets-list flag, which is useful to keep in the README.

Suggested change
- **Flexible targets**: Accepts single IPv4s, IP ranges, CIDR blocks, domain names, and full HTTP/HTTPS URLs.
These methods ensure full compatibility and avoid runtime errors
- **Flexible targets**: Accepts single IPv4s, IP ranges, CIDR blocks, domain names, and full HTTP/HTTPS URLs, helping avoid target-parsing errors across different input formats.

Copilot uses AI. Check for mistakes.
Comment on lines +37 to +46
python nettacker.py -i 192.168.1.1

Scan multiple targets:
python nettacker.py -l targets.txt

Run specific module:
python nettacker.py -i example.com -m port_scan

Show all modules:
python nettacker.py --show-all-modules
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The epilog examples hard-code python nettacker.py ..., but this project also installs a nettacker console script (see pyproject.toml [tool.poetry.scripts]). Consider using nettacker ... (or showing both forms) to avoid confusing users who installed the package rather than running from the repo checkout.

Suggested change
python nettacker.py -i 192.168.1.1
Scan multiple targets:
python nettacker.py -l targets.txt
Run specific module:
python nettacker.py -i example.com -m port_scan
Show all modules:
python nettacker.py --show-all-modules
nettacker -i 192.168.1.1
Scan multiple targets:
nettacker -l targets.txt
Run specific module:
nettacker -i example.com -m port_scan
Show all modules:
nettacker --show-all-modules

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +49
Show all modules:
python nettacker.py --show-all-modules
""",
formatter_class=RawTextHelpFormatter,
add_help=False
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because RawTextHelpFormatter preserves all whitespace, the current triple-quoted epilog will render with the leading indentation shown in the source (and the example headings aren’t consistently aligned). Using a dedented string (e.g., via textwrap.dedent) and consistent indentation will make the help output cleaner.

Copilot uses AI. Check for mistakes.
Comment on lines +552 to +556
for arg in unknown_args:
if arg.startswith("--") and len(arg) > 1:
suggestion = difflib.get_close_matches(arg, valid_flags, n=1)
if suggestion:
print(
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parse_known_args() returns any values following an unknown option in unknown_args as separate tokens (e.g., --bad value => ['--bad','value']), so iterating and erroring per-token can produce misleading extra "Unexpected argument" messages. Consider detecting unknown option/value pairs (or delegating to ArgumentParser.error() after computing a suggestion) so the user gets a single accurate error for the unknown flag.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@nettacker/core/arg_parser.py`:
- Around line 547-565: Unknown option tokens and their following values are
reported as two errors; update the unknown_args handling so when you see an
unknown flag token (arg.startswith("--") and len(arg) > 1) you treat a non-flag
next token as its value and skip it, emitting a single error message (use the
same stderr message and path currently used, then sys.exit(1) or the parser's
normal failure mechanism). Concretely, in the block that iterates unknown_args
(and uses self._actions and difflib.get_close_matches) check the next element in
unknown_args: if it exists and does not start with "-" treat it as the value for
the current unknown flag and advance the loop one extra step so only one
diagnostic is printed for the pair. Ensure suggestion logic
(difflib.get_close_matches) still applies to the flag token only.
- Around line 32-48: The new hardcoded English strings assigned to the
ArgumentParser's description and epilog should be localized like the other
option help text; wrap the description and the multi-line epilog string with the
translation function _() (and ensure _ is imported/available in this module) so
the call that constructs the ArgumentParser (the arguments named description and
epilog, and the use of RawTextHelpFormatter) emits translated text on localized
installs; keep the epilog as a single multi-line string passed into _() to
preserve formatting.

In `@README.md`:
- Around line 30-31: The continuation text for the "Flexible targets" bullet is
on its own line and not indented, so GitHub renders it as a separate paragraph;
update the README so the continuation is part of the same list item by either
appending the sentence to the same line as "**Flexible targets**: Accepts ..."
or indenting the following line by two spaces (or adding a trailing two-space
line break on the previous line) so the sentence remains inside the bullet;
locate the "**Flexible targets**" list item in README.md and adjust the
following line accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 04e772c8-2c71-482c-aef7-10c1d430bac4

📥 Commits

Reviewing files that changed from the base of the PR and between 74d89e2 and 753f5a8.

📒 Files selected for processing (2)
  • README.md
  • nettacker/core/arg_parser.py

Comment thread nettacker/core/arg_parser.py Outdated
Comment on lines +32 to +48
description="OWASP Nettacker - Automated Penetration Testing Framework",
epilog="""
Examples:

Scan a target:
python nettacker.py -i 192.168.1.1

Scan multiple targets:
python nettacker.py -l targets.txt

Run specific module:
python nettacker.py -i example.com -m port_scan

Show all modules:
python nettacker.py --show-all-modules
""",
formatter_class=RawTextHelpFormatter,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Localize the new overview and examples.

The per-option help strings in this file already go through _(), but the new description and epilog are hardcoded English. On localized installs, the help output will now be partly translated and partly English.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nettacker/core/arg_parser.py` around lines 32 - 48, The new hardcoded English
strings assigned to the ArgumentParser's description and epilog should be
localized like the other option help text; wrap the description and the
multi-line epilog string with the translation function _() (and ensure _ is
imported/available in this module) so the call that constructs the
ArgumentParser (the arguments named description and epilog, and the use of
RawTextHelpFormatter) emits translated text on localized installs; keep the
epilog as a single multi-line string passed into _() to preserve formatting.

Comment on lines +547 to +565
if unknown_args:
valid_flags = []
for action in self._actions:
valid_flags.extend(action.option_strings)

for arg in unknown_args:
if arg.startswith("--") and len(arg) > 1:
suggestion = difflib.get_close_matches(arg, valid_flags, n=1)
if suggestion:
print(
f"Error: Unknown argument '{arg}'. Did you mean '{suggestion[0]}'?",
file=sys.stderr,
)
else:
print(f"Error: Unknown argument '{arg}'", file=sys.stderr)
else:
print(f"Error: Unexpected argument '{arg}'", file=sys.stderr)

sys.exit(1)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Treat an unknown option and its value as one error.

A typo on an option that takes a value currently produces two diagnostics: one for the bad flag and a second Unexpected argument ... for its value. That makes a single parse mistake look like multiple failures. Please collapse those tokens into one error and send it through the normal CLI failure path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nettacker/core/arg_parser.py` around lines 547 - 565, Unknown option tokens
and their following values are reported as two errors; update the unknown_args
handling so when you see an unknown flag token (arg.startswith("--") and
len(arg) > 1) you treat a non-flag next token as its value and skip it, emitting
a single error message (use the same stderr message and path currently used,
then sys.exit(1) or the parser's normal failure mechanism). Concretely, in the
block that iterates unknown_args (and uses self._actions and
difflib.get_close_matches) check the next element in unknown_args: if it exists
and does not start with "-" treat it as the value for the current unknown flag
and advance the loop one extra step so only one diagnostic is printed for the
pair. Ensure suggestion logic (difflib.get_close_matches) still applies to the
flag token only.

Comment thread README.md
Comment on lines +30 to +31
- **Flexible targets**: Accepts single IPv4s, IP ranges, CIDR blocks, domain names, and full HTTP/HTTPS URLs.
These methods ensure full compatibility and avoid runtime errors
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Keep the explanation inside the list item.

Line 31 is not indented as a continuation of the bullet, so GitHub renders it as a separate paragraph instead of part of Flexible targets.

📝 Suggested fix
 - **Flexible targets**: Accepts single IPv4s, IP ranges, CIDR blocks, domain names, and full HTTP/HTTPS URLs.
-These methods ensure full compatibility and avoid runtime errors 
+  These methods ensure full compatibility and avoid runtime errors.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **Flexible targets**: Accepts single IPv4s, IP ranges, CIDR blocks, domain names, and full HTTP/HTTPS URLs.
These methods ensure full compatibility and avoid runtime errors
- **Flexible targets**: Accepts single IPv4s, IP ranges, CIDR blocks, domain names, and full HTTP/HTTPS URLs.
These methods ensure full compatibility and avoid runtime errors.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 30 - 31, The continuation text for the "Flexible
targets" bullet is on its own line and not indented, so GitHub renders it as a
separate paragraph; update the README so the continuation is part of the same
list item by either appending the sentence to the same line as "**Flexible
targets**: Accepts ..." or indenting the following line by two spaces (or adding
a trailing two-space line break on the previous line) so the sentence remains
inside the bullet; locate the "**Flexible targets**" list item in README.md and
adjust the following line accordingly.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
nettacker/core/arg_parser.py (2)

33-47: ⚠️ Potential issue | 🟡 Minor

Localize the epilog examples too.

description now goes through _(), but the new examples are still a hardcoded English block. Localized installs will end up with mixed-language help unless the whole multi-line epilog is translated as one string so RawTextHelpFormatter keeps the layout.

Suggested fix
-            epilog=("""
+            epilog=_(
+                """
         Examples:
 
           Scan a target:
             python nettacker.py -i 192.168.1.1
 
           Scan multiple targets:
             python nettacker.py -l targets.txt
 
            Run specific module:
             python nettacker.py -i example.com -m port_scan
 
            Show all modules:
              python nettacker.py --show-all-modules
-        """),
+        """
+            ),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nettacker/core/arg_parser.py` around lines 33 - 47, The epilog multi-line
string in arg_parser (the epilog argument passed to ArgumentParser / parser
creation) is hardcoded in English; wrap the entire multi-line epilog in the
translation function _(…) so the RawTextHelpFormatter preserves layout while
allowing localization. Update the epilog value (the epilog passed into the
ArgumentParser call in nettacker/core/arg_parser.py) to call _() around the
triple-quoted string and ensure any surrounding RawTextHelpFormatter usage
remains unchanged so formatting is preserved.

547-565: ⚠️ Potential issue | 🟡 Minor

Treat an unknown long option and its value as one error.

--targtes 192.168.1.1 still emits two diagnostics because the loop advances one token at a time. Walk unknown_args by index and skip the following non-flag token when it belongs to the bad option.

Suggested fix
-                for arg in unknown_args:
+                index = 0
+                while index < len(unknown_args):
+                    arg = unknown_args[index]
                     if arg.startswith("--") and len(arg) > 1:
                         suggestion = difflib.get_close_matches(arg, valid_flags, n=1)
                         if suggestion:
                             print(
                                 f"Error: Unknown argument '{arg}'. Did you mean '{suggestion[0]}'?",
                                 file=sys.stderr,
                             )
                         else:
                             print(f"Error: Unknown argument '{arg}'", file=sys.stderr)
+                        if (
+                            "=" not in arg
+                            and index + 1 < len(unknown_args)
+                            and not unknown_args[index + 1].startswith("-")
+                        ):
+                            index += 1
                     else:
                         print(f"Error: Unexpected argument '{arg}'", file=sys.stderr)
+                    index += 1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nettacker/core/arg_parser.py` around lines 547 - 565, The loop over
unknown_args currently iterates token-by-token and flags an unknown long option
and its attached value as two separate errors; update the handling in the block
that checks unknown_args (referencing unknown_args and self._actions) to iterate
by index (i = 0..len-1) and when you encounter a token starting with "--" treat
the next token as its value if it exists and does not start with "-" (i+1 < len
and not unknown_args[i+1].startswith("-")), produce a single error/suggestion
for the option (using difflib.get_close_matches as before) and increment the
index to skip the value token so it is not reported separately; keep other
branches (short flags and unexpected args) unchanged and still exit with
sys.exit(1).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@nettacker/core/arg_parser.py`:
- Around line 33-47: The epilog multi-line string in arg_parser (the epilog
argument passed to ArgumentParser / parser creation) is hardcoded in English;
wrap the entire multi-line epilog in the translation function _(…) so the
RawTextHelpFormatter preserves layout while allowing localization. Update the
epilog value (the epilog passed into the ArgumentParser call in
nettacker/core/arg_parser.py) to call _() around the triple-quoted string and
ensure any surrounding RawTextHelpFormatter usage remains unchanged so
formatting is preserved.
- Around line 547-565: The loop over unknown_args currently iterates
token-by-token and flags an unknown long option and its attached value as two
separate errors; update the handling in the block that checks unknown_args
(referencing unknown_args and self._actions) to iterate by index (i = 0..len-1)
and when you encounter a token starting with "--" treat the next token as its
value if it exists and does not start with "-" (i+1 < len and not
unknown_args[i+1].startswith("-")), produce a single error/suggestion for the
option (using difflib.get_close_matches as before) and increment the index to
skip the value token so it is not reported separately; keep other branches
(short flags and unexpected args) unchanged and still exit with sys.exit(1).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dc182602-cbb6-464c-a5c5-4139575c409b

📥 Commits

Reviewing files that changed from the base of the PR and between 753f5a8 and 1274969.

📒 Files selected for processing (1)
  • nettacker/core/arg_parser.py

"""
# Checking Requirements
options = self.api_arguments or self.parse_args()
if self.api_arguments:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated to what you're trying to do. Please remove this as this is not needed as well, argparser handles all the below.

@pUrGe12
Copy link
Copy Markdown
Contributor

pUrGe12 commented Mar 26, 2026

@pandeysudarshan16-ctrl Please verify your commits.

Comment thread README.md
- **CLI, REST API & Web UI** - Offers both programmatic integration and a user-friendly web interface for defining scans and viewing results.
- **Evasion techniques** - Enables configurable delays, proxy support, and randomized user-agents to reduce detection by firewalls or IDS systems.
- **Flexible targets** - Accepts single IPv4s, IP ranges, CIDR blocks, domain names, and full HTTP/HTTPS URLs. Targets can be mixed in a single command or loaded from a file using the `-l/--targets-list` flag.
- **Flexible targets**: Accepts single IPv4s, IP ranges, CIDR blocks, domain names, and full HTTP/HTTPS URLs.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are you deleting a perfectly valid documentation line to squeeze in an advertisement for your proposal?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants