Skip to content

Conversation

@Aarush289
Copy link
Contributor

Proposed change

This PR adds an optional target validation step before running any scans.
When -C (or --validate-before-scan) is used, Nettacker resolves each target first and filters out invalid or unreachable ones.

This improves performance and reduces unnecessary resource usage by skipping modules for targets that cannot be resolved.
If -C is not used, behavior remains unchanged and all targets are scanned as before.

No breaking changes.

Type of change

  • New core framework functionality

Checklist


… not and changes are done accordingly in app.py to drop buggy target names . e.g. 465.54.543.35 , google , ajkbfdsv etc.
Signed-off-by: Aarush289 <[email protected]>
Signed-off-by: Aarush289 <[email protected]>
Signed-off-by: Aarush289 <[email protected]>
Signed-off-by: Aarush289 <[email protected]>
Signed-off-by: Aarush289 <[email protected]>
Signed-off-by: Aarush289 <[email protected]>
Signed-off-by: Aarush289 <[email protected]>
Signed-off-by: Aarush289 <[email protected]>
Signed-off-by: Aarush289 <[email protected]>
Signed-off-by: Aarush289 <[email protected]>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 30, 2025

Summary by CodeRabbit

  • New Features

    • Added --validate-before-scan command-line option to pre-validate target connectivity before scanning begins; unreachable targets are automatically skipped.
  • Chores

    • Updated gitignore entries.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

This change introduces a pre-scan target validation feature that validates hostname syntax and DNS reachability before scanning. A new configuration flag, command-line option, DNS resolution utility module, and parallel target filtering mechanism are added to enable conditional validation of targets with concurrent processing support.

Changes

Cohort / File(s) Summary
Configuration & Interface
nettacker/config.py, nettacker/core/arg_parser.py, nettacker/locale/en.yaml, .gitignore
Added validate_before_scan default config attribute (False), new CLI option --validate-before-scan, localization entry for the feature, and three ignore patterns (Public_sign, Public_sign.pub, cks_proxy)
Target Validation Utilities
nettacker/core/hostcheck.py
New module implementing RFC 1123-compliant hostname validation and concurrent DNS resolution with configurable timeout, fallback strategies, and error handling
Scan Engine Integration
nettacker/core/app.py
Added filter_valid_targets() method using ThreadPoolExecutor for parallel target resolution; scan_target_group now conditionally validates targets when feature enabled and SOCKS proxy not in use
Test Artifact
test.txt
Added file containing test string

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • nettacker/core/hostcheck.py: Review DNS resolution logic, thread-based timeout mechanism, RFC 1123 hostname validation compliance, and error handling across resolve_quick() and valid_hostname() functions
  • nettacker/core/app.py: Verify ThreadPoolExecutor usage patterns, handling of None values from failed resolutions, deduplication logic, and conditional validation flow when SOCKS proxy is active
  • Integration points: Confirm feature flag correctly flows from config through argument parser to runtime control of target filtering
  • Edge cases: Validate behavior with empty target lists, malformed inputs, and timeout scenarios

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.53% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main feature being added: target validation before scanning with the -C flag.
Description check ✅ Passed The description is directly related to the changeset, explaining the target validation feature, its benefits, and that behavior remains unchanged when not used.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c8c4b5b and 4eafc71.

📒 Files selected for processing (1)
  • test.txt (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • test.txt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Test Docker 27.5.0-1ubuntu.24.04noble image build
  • GitHub Check: Test Docker 26.0.0-1ubuntu.24.04noble image build
  • GitHub Check: Test Docker 26.1.4-1ubuntu.24.04noble image build
  • GitHub Check: Build package
  • GitHub Check: Test Docker image

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.

@pUrGe12
Copy link
Contributor

pUrGe12 commented Oct 30, 2025

LGTM!

Copy link
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: 2

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d3f39c and b004b4c.

📒 Files selected for processing (6)
  • .gitignore (1 hunks)
  • nettacker/config.py (1 hunks)
  • nettacker/core/app.py (3 hunks)
  • nettacker/core/arg_parser.py (1 hunks)
  • nettacker/core/hostcheck.py (1 hunks)
  • nettacker/locale/en.yaml (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use 4-space indents in Python code
Limit lines to 99 characters (ruff/ruff-format/isort profile=black)
Module and file names should use lower_snake_case
Function and variable names should use lower_snake_case
Class names should use PascalCase
Constants should use UPPER_SNAKE_CASE
Keep functions small and add type hints where practical

Files:

  • nettacker/config.py
  • nettacker/core/hostcheck.py
  • nettacker/core/arg_parser.py
  • nettacker/core/app.py
nettacker/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Add docstrings for public APIs in the nettacker package

Files:

  • nettacker/config.py
  • nettacker/core/hostcheck.py
  • nettacker/core/arg_parser.py
  • nettacker/core/app.py
nettacker/config.py

📄 CodeRabbit inference engine (AGENTS.md)

Manage defaults (API key, DB path, paths) in nettacker/config.py and review sensitive headers list before logging

Files:

  • nettacker/config.py
nettacker/core/**

📄 CodeRabbit inference engine (AGENTS.md)

Place core libraries under nettacker/core/

Files:

  • nettacker/core/hostcheck.py
  • nettacker/core/arg_parser.py
  • nettacker/core/app.py
🧠 Learnings (4)
📚 Learning: 2025-09-07T19:20:58.332Z
Learnt from: CR
Repo: OWASP/Nettacker PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-07T19:20:58.332Z
Learning: Applies to nettacker/config.py : Manage defaults (API key, DB path, paths) in nettacker/config.py and review sensitive headers list before logging

Applied to files:

  • nettacker/config.py
📚 Learning: 2025-09-07T19:20:58.332Z
Learnt from: CR
Repo: OWASP/Nettacker PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-07T19:20:58.332Z
Learning: Applies to nettacker/**/*.py : Add docstrings for public APIs in the nettacker package

Applied to files:

  • nettacker/config.py
📚 Learning: 2025-10-25T11:31:26.498Z
Learnt from: Aarush289
Repo: OWASP/Nettacker PR: 1155
File: nettacker/core/hostcheck.py:121-122
Timestamp: 2025-10-25T11:31:26.498Z
Learning: In nettacker/core/hostcheck.py, the resolve_quick() function intentionally applies timeout_sec per resolution pass (not cumulatively), allowing up to 2× timeout_sec total execution time across both AI_ADDRCONFIG passes by design.

Applied to files:

  • nettacker/core/hostcheck.py
  • nettacker/core/app.py
📚 Learning: 2025-09-07T19:20:58.332Z
Learnt from: CR
Repo: OWASP/Nettacker PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-07T19:20:58.332Z
Learning: Applies to nettacker.py : Repository provides nettacker.py as an entry script (use as Python entry point)

Applied to files:

  • nettacker/core/app.py
🧬 Code graph analysis (3)
nettacker/core/hostcheck.py (1)
nettacker/core/ip.py (2)
  • is_single_ipv4 (51-61)
  • is_single_ipv6 (88-98)
nettacker/core/arg_parser.py (1)
nettacker/config.py (1)
  • Config (184-188)
nettacker/core/app.py (1)
nettacker/core/hostcheck.py (1)
  • resolve_quick (54-92)
🪛 Ruff (0.14.2)
nettacker/core/app.py

302-302: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


302-302: Avoid specifying long messages outside the exception class

(TRY003)


323-323: Use logging.exception instead of logging.error

Replace with exception

(TRY400)

🔇 Additional comments (1)
.gitignore (1)

34-36: Clarify the relationship between these artifacts and the target validation feature.

The three new entries (Public_sign, Public_sign.pub, and cks_proxy) are unclear in their connection to the stated PR objective (pre-scan target validation with DNS resolution). Additionally, best practices suggest that public key files (.pub) should not typically be gitignored—only private keys should be.

Please clarify:

  1. What role do these artifacts play in the target validation workflow?
  2. Is Public_sign the private key and Public_sign.pub the public counterpart? If so, only Public_sign should be gitignored.
  3. What is cks_proxy used for?

@Aarush289
Copy link
Contributor Author

Hi @securestep9 , gentle nudge for a review whenever you get a chance. Happy to address any feedback. Thanks!

Copy link
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: 15

🧹 Nitpick comments (5)
nettacker/core/parser.py (5)

58-87: Consider fixing PEP 8 spacing issues.

Multiple spacing inconsistencies throughout the function:

  • Line 59: line=line.strip() should be line = line.strip()
  • Lines 62, 71: if( should be if (
  • Lines 74, 81: else : should be else:

100-103: Use singular variable name for clarity.

The loop variable ports on line 102 represents a single port number, so it should be named port for clarity.

-            for ports in range (int(start),int(end)+1):
-                final_list.append(ports)
+            for port in range(int(start), int(end) + 1):
+                final_list.append(port)

236-243: Use consistent snake_case naming.

Variable Ignore_case on line 237 uses inconsistent capitalization. Per coding guidelines, variables should use snake_case.

Based on coding guidelines: "Function and variable names should use lower_snake_case."

Apply this diff:

                 new_line_specifier=False
-                Ignore_case = False
+                ignore_case = False
                 
                 for c in options:
                     if c == 's':
                         new_line_specifier=True
                     if c == 'i':
-                        Ignore_case = True
+                        ignore_case = True
                 sig={
                     "type":sig_type,
                     "service":service,
                     "regex":regex,
-                    "Ignore_case":Ignore_case,
-                    "New_line_specifier":new_line_specifier,
+                    "ignore_case":ignore_case,
+                    "new_line_specifier":new_line_specifier,

Also applies to: 312-313


128-335: Consider breaking down the complex function.

This 207-line function handles multiple parsing responsibilities. Consider extracting helper functions like _parse_probe_header(), _parse_signature(), and _parse_version_fields() to improve testability and maintainability.


347-351: Consider adding command-line argument support.

The __main__ block uses hardcoded filenames and has no error handling. For better usability and robustness, consider using argparse to accept file paths as arguments and wrap the calls in try-except blocks.

Example:

if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser(description="Parse nmap-service-probes file")
    parser.add_argument("input", help="Input probe file path")
    parser.add_argument("output", help="Output YAML file path")
    args = parser.parse_args()
    
    try:
        probes, excluded_ports = parse_probe_file(args.input)
        write_yaml(probes, excluded_ports, args.output)
        print(f"Successfully wrote {len(probes)} probes to {args.output}")
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b004b4c and c8c4b5b.

📒 Files selected for processing (1)
  • nettacker/core/parser.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use 4-space indents in Python code
Limit lines to 99 characters (ruff/ruff-format/isort profile=black)
Module and file names should use lower_snake_case
Function and variable names should use lower_snake_case
Class names should use PascalCase
Constants should use UPPER_SNAKE_CASE
Keep functions small and add type hints where practical

Files:

  • nettacker/core/parser.py
nettacker/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Add docstrings for public APIs in the nettacker package

Files:

  • nettacker/core/parser.py
nettacker/core/**

📄 CodeRabbit inference engine (AGENTS.md)

Place core libraries under nettacker/core/

Files:

  • nettacker/core/parser.py
🧬 Code graph analysis (1)
nettacker/core/parser.py (1)
tests/core/test_exclude_ports.py (1)
  • options (18-19)
🪛 Ruff (0.14.8)
nettacker/core/parser.py

161-161: Found useless expression. Either assign it to a variable or remove it.

(B018)

🔇 Additional comments (1)
nettacker/core/parser.py (1)

145-146: Verify handling of multiple Exclude directives in probe files.

Line 146 assigns the result of parse_excluded(line) to excluded_ports, which will overwrite any previously parsed exclusions. If the probe file format allows multiple Exclude directives, they should be merged rather than replaced. Confirm the intended behavior by checking: (1) whether probe files can contain multiple Exclude lines, (2) the data structure returned by parse_excluded(), and (3) how excluded_ports is used after being assigned.

Comment on lines 1 to 53
"""
Format:

Excluded Ports:
- TCP : 3454,2345,3455-3453
UDP : 3443-2453,34
Universal : 23,53,6-345
probe:
- name : "NULL"
protocol : TCP/UDP
totalwaits: xxx
tcpwrappedms:
rarity : 1-9
ports: [23,24,35-654]
sslports:
fallbacks: ["s1" , "s2" ,,]
probe_payload: ""
payload:
signatures:
- type: "match"
service:"http"
regex:"..."
Ignore_case:
New_line_specifier:
version:
raw:
product: ""
vertion_template:
info:
hostname:
operating_system:
device_type:
cpe:
service: "" /a
operating_system:"" /o
hadware_platform:"" /h
- type: "softmatch"
service:""
regex:".."
options: "s/i/both"
version:
raw:
product: ""
vertion_template:
info:
hostname:
operating_system:
device_type:
cpe:
service: "" /a
operating_system:"" /o
hadware_platform:"" /h
"""
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typos in the docstring.

The docstring contains spelling errors:

  • "vertion_template" should be "version_template" (appears on lines 28, 44)
  • "hadware_platform" should be "hardware_platform" (appears on lines 36, 52)

Apply this diff to fix the typos:

-                    vertion_template:
+                    version_template:
-                        hadware_platform:"" /h
+                        hardware_platform:"" /h
📝 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
"""
Format:
Excluded Ports:
- TCP : 3454,2345,3455-3453
UDP : 3443-2453,34
Universal : 23,53,6-345
probe:
- name : "NULL"
protocol : TCP/UDP
totalwaits: xxx
tcpwrappedms:
rarity : 1-9
ports: [23,24,35-654]
sslports:
fallbacks: ["s1" , "s2" ,,]
probe_payload: ""
payload:
signatures:
- type: "match"
service:"http"
regex:"..."
Ignore_case:
New_line_specifier:
version:
raw:
product: ""
vertion_template:
info:
hostname:
operating_system:
device_type:
cpe:
service: "" /a
operating_system:"" /o
hadware_platform:"" /h
- type: "softmatch"
service:""
regex:".."
options: "s/i/both"
version:
raw:
product: ""
vertion_template:
info:
hostname:
operating_system:
device_type:
cpe:
service: "" /a
operating_system:"" /o
hadware_platform:"" /h
"""
"""
Format:
Excluded Ports:
- TCP : 3454,2345,3455-3453
UDP : 3443-2453,34
Universal : 23,53,6-345
probe:
- name : "NULL"
protocol : TCP/UDP
totalwaits: xxx
tcpwrappedms:
rarity : 1-9
ports: [23,24,35-654]
sslports:
fallbacks: ["s1" , "s2" ,,]
probe_payload: ""
payload:
signatures:
- type: "match"
service:"http"
regex:"..."
Ignore_case:
New_line_specifier:
version:
raw:
product: ""
version_template:
info:
hostname:
operating_system:
device_type:
cpe:
service: "" /a
operating_system:"" /o
hardware_platform:"" /h
- type: "softmatch"
service:""
regex:".."
options: "s/i/both"
version:
raw:
product: ""
version_template:
info:
hostname:
operating_system:
device_type:
cpe:
service: "" /a
operating_system:"" /o
hardware_platform:"" /h
"""
🤖 Prompt for AI Agents
In nettacker/core/parser.py around lines 1 to 53, the docstring has two typos:
change every occurrence of "vertion_template" to "version_template" (lines ~28
and ~44) and change every occurrence of "hadware_platform" to
"hardware_platform" (lines ~36 and ~52); update the docstring text accordingly,
preserving formatting and spacing but correcting those two misspellings.

Comment on lines 56 to 57
import yaml
import codecs
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove unused import.

The codecs module is imported but never used in this file.

Apply this diff:

 import yaml
-import codecs
+
 def parse_excluded(line):
📝 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
import yaml
import codecs
import yaml
def parse_excluded(line):
🤖 Prompt for AI Agents
In nettacker/core/parser.py around lines 56 to 57, the codecs module is imported
but never used; remove the unused "import codecs" line (leave "import yaml") and
run linting/type-checking to ensure no other references to codecs exist.

Comment on lines 58 to 87
def parse_excluded(line):
line=line.strip()
if not line:
return []
if(line.startswith("Exclude")):
line = line[len("Exclude"):].strip()
if not line:
return []
parts = [p.strip() for p in line.split(",") if p.strip()]
tcp_spec =[]
udp_spec =[]
universal_spec=[]
for p in parts:
if(":" in p):
proto,spec = p.split(":",1)
proto = proto.upper()
else :
proto,spec = "",p

if proto == "T":
tcp_spec.append(spec)
elif proto == "U":
udp_spec.append(spec)
else :
universal_spec.append(spec)
return {
"TCP": ",".join(tcp_spec),
"UDP": ",".join(udp_spec),
"Universal": ",".join(universal_spec),
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add docstring for public API.

As per coding guidelines, public APIs in the nettacker package require docstrings. This function needs documentation explaining its purpose, parameters, and return value.

Based on coding guidelines for nettacker/**/*.py: "Add docstrings for public APIs in the nettacker package."

Add a docstring like:

def parse_excluded(line):
    """Parse excluded ports specification from probe file.
    
    Args:
        line: Line containing Exclude directive with port specifications
        
    Returns:
        Dictionary with TCP, UDP, and Universal port specifications
    """
🤖 Prompt for AI Agents
In nettacker/core/parser.py around lines 58 to 87, the public function
parse_excluded is missing a docstring; add a concise triple-quoted docstring
immediately below the def line that explains the function purpose (parsing an
"Exclude" line into TCP, UDP, and universal port specs), documents the parameter
(line: str) and the return value (dict with keys "TCP", "UDP", "Universal"
containing comma-separated specs), and optionally notes behavior for
empty/whitespace input—keep it short and follow project docstring style.

⚠️ Potential issue | 🔴 Critical

Fix inconsistent return type.

The function returns an empty list [] on lines 61 and 65, but returns a dictionary on line 83. This type inconsistency will cause runtime errors when callers expect a consistent return type.

Apply this diff to return an empty dict instead:

 def parse_excluded(line):
     line=line.strip()
     if not line:
-        return []
+        return {"TCP": "", "UDP": "", "Universal": ""}
     if(line.startswith("Exclude")):
         line = line[len("Exclude"):].strip()
     if not line:
-        return []
+        return {"TCP": "", "UDP": "", "Universal": ""}
🤖 Prompt for AI Agents
In nettacker/core/parser.py around lines 58 to 87, the function parse_excluded
returns an empty list on lines 61 and 65 but returns a dict later, causing
inconsistent return types; replace those two returns of [] with an empty dict
return (e.g., return {}) so the function always returns a mapping type (or
alternatively return a consistent dict like {"TCP":"", "UDP":"",
"Universal":""}) to keep the return type consistent.

Comment on lines 89 to 106
def parse_ports(line):
line=line.strip()
if not line:
return []
if(line.startswith("ports")):
line=line[len("ports"):].strip()
if not line:
return []
parts = [p.strip() for p in line.split(',') if p.strip()]
final_list=[]
for p in parts:
if '-' in p:
start,end = p.split('-')
for ports in range (int(start),int(end)+1):
final_list.append(ports)
else:
final_list.append(int(p))
return final_list
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add docstring for public API.

This public function needs documentation per coding guidelines.

Based on coding guidelines for nettacker/**/*.py.

🤖 Prompt for AI Agents
In nettacker/core/parser.py around lines 89 to 106, the public function
parse_ports lacks a docstring; add a concise docstring immediately below the def
line that briefly describes the function purpose, documents the parameters and
return value and types (e.g., line: str -> list[int]), notes expected input
format (comma-separated ports and ranges like "80,443,8000-8010"), and any error
behavior (ValueError on invalid integers/ranges) or edge cases; follow the
repository's docstring style (summary line, short description, Args:, Returns:,
Raises:, and a short example) so the public API is documented per coding
guidelines.

⚠️ Potential issue | 🟠 Major

Add error handling for invalid port specifications.

The function will raise ValueError if the input contains non-numeric values or invalid ranges. This can crash the parser on malformed probe files.

Consider adding try-except blocks:

     for p in parts:
         if '-' in p:
-            start,end = p.split('-')
-            for ports in range (int(start),int(end)+1):
+            try:
+                start, end = p.split('-', 1)
+                for port in range(int(start), int(end) + 1):
+                    final_list.append(port)
+            except (ValueError, TypeError) as e:
+                # Log or skip invalid range
+                continue
-                final_list.append(ports)
         else:
-            final_list.append(int(p))
+            try:
+                final_list.append(int(p))
+            except (ValueError, TypeError) as e:
+                # Log or skip invalid port
+                continue
📝 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
def parse_ports(line):
line=line.strip()
if not line:
return []
if(line.startswith("ports")):
line=line[len("ports"):].strip()
if not line:
return []
parts = [p.strip() for p in line.split(',') if p.strip()]
final_list=[]
for p in parts:
if '-' in p:
start,end = p.split('-')
for ports in range (int(start),int(end)+1):
final_list.append(ports)
else:
final_list.append(int(p))
return final_list
def parse_ports(line):
line=line.strip()
if not line:
return []
if(line.startswith("ports")):
line=line[len("ports"):].strip()
if not line:
return []
parts = [p.strip() for p in line.split(',') if p.strip()]
final_list=[]
for p in parts:
if '-' in p:
try:
start, end = p.split('-', 1)
for port in range(int(start), int(end) + 1):
final_list.append(port)
except (ValueError, TypeError) as e:
# Log or skip invalid range
continue
else:
try:
final_list.append(int(p))
except (ValueError, TypeError) as e:
# Log or skip invalid port
continue
return final_list
🤖 Prompt for AI Agents
In nettacker/core/parser.py around lines 89 to 106, the parse_ports function
currently assumes all port tokens and ranges are valid integers and will raise
ValueError on malformed input; update it to validate and handle errors: wrap int
conversions in try-except to catch ValueError, verify range tokens contain
exactly two numeric parts and that start <= end, skip or log invalid tokens
instead of letting the function crash (or collect and raise a single descriptive
error if that's preferred), and ensure the function still returns a
deduplicated, sorted list of valid ports.

Comment on lines 108 to 125
def parse_ssl_ports(line):
line=line.strip()
if not line:
return []
if(line.startswith("sslports")):
line=line[len("sslports"):].strip()
if not line:
return []
parts = [p.strip() for p in line.split(',') if p.strip()]
final_list=[]
for p in parts:
if '-' in p:
start,end = p.split('-')
for ports in range (int(start),int(end)+1):
final_list.append(ports)
else:
final_list.append(int(p))
return final_list
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Eliminate code duplication.

parse_ssl_ports is an exact duplicate of parse_ports except for the prefix string. This violates the DRY principle and creates maintenance burden.

Refactor to use a shared implementation:

def _parse_port_list(line, prefix=""):
    """Parse comma-separated port specifications with range support.
    
    Args:
        line: String containing port specifications
        prefix: Optional prefix to strip from line
        
    Returns:
        List of port numbers
    """
    line = line.strip()
    if not line:
        return []
    if prefix and line.startswith(prefix):
        line = line[len(prefix):].strip()
    if not line:
        return []
    parts = [p.strip() for p in line.split(',') if p.strip()]
    final_list = []
    for p in parts:
        if '-' in p:
            try:
                start, end = p.split('-', 1)
                for port in range(int(start), int(end) + 1):
                    final_list.append(port)
            except (ValueError, TypeError):
                continue
        else:
            try:
                final_list.append(int(p))
            except (ValueError, TypeError):
                continue
    return final_list

def parse_ports(line):
    """Parse ports specification."""
    return _parse_port_list(line, "ports")

def parse_ssl_ports(line):
    """Parse SSL ports specification."""
    return _parse_port_list(line, "sslports")
🤖 Prompt for AI Agents
In nettacker/core/parser.py around lines 108 to 125, parse_ssl_ports duplicates
parse_ports; refactor to remove duplication by implementing a single helper
(e.g., _parse_port_list(line, prefix="")) that trims the line, strips an
optional prefix, splits on commas, supports ranges (start-end) and single ports,
and gracefully ignores invalid entries (wrap int conversions and range parsing
in try/except to skip bad values); then make parse_ports and parse_ssl_ports
simple wrappers that call the helper with prefixes "ports" and "sslports"
respectively, preserving existing behavior and return types.

Comment on lines 155 to 167

name = line[0:line.find(" ",0)]

line = line[len(name)+1:]

if line[0] != 'q':
KeyError

line = line[1:]
delim=line[0:1]
line = line[1:]
probe_string="\""
probe_string = line[0:line.find(delim,0)]
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add bounds checking for string operations.

Multiple string operations use .find() without checking for -1 return value, and index into strings without checking length. This will cause crashes or incorrect parsing on malformed input.

Examples:

  • Line 156: line.find(" ", 0) returns -1 if space not found
  • Line 167: line.find(delim, 0) returns -1 if delimiter not found
  • Line 227: line[0] assumes line is non-empty
  • Line 230: Another unchecked find()

Add validation before string operations:

# Example for line 156:
space_idx = line.find(" ", 0)
if space_idx == -1:
    raise ValueError(f"Invalid probe format: {line}")
name = line[0:space_idx]

# Example for line 167:
delim_idx = line.find(delim, 0)
if delim_idx == -1:
    raise ValueError(f"Probe string delimiter not found: {line}")
probe_string = line[0:delim_idx]

# Example for line 227:
if not line:
    raise ValueError("Unexpected empty line in signature")
line = line[1:]

Also applies to: 227-230

🧰 Tools
🪛 Ruff (0.14.8)

161-161: Found useless expression. Either assign it to a variable or remove it.

(B018)

🤖 Prompt for AI Agents
In nettacker/core/parser.py around lines 155-167 (and also apply to 227-230),
several string operations assume successful finds and non-empty strings; add
explicit bounds checks: verify .find() results are not -1 before slicing and
capture the index in a variable, check string length (or non-emptiness) before
indexing like line[0], and if checks fail raise a descriptive ValueError
indicating the malformed input and include the offending line content; replace
direct usage of .find() and direct indexing with the validated index/length
variables and consistent error messages so malformed probe/signature lines fail
gracefully rather than crash.

Comment on lines 160 to 161
if line[0] != 'q':
KeyError
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix useless expression that should raise an exception.

Line 161 references KeyError but doesn't actually raise it. This is a no-op that will not prevent execution when the expected 'q' character is missing.

As flagged by static analysis tool Ruff (B018).

Apply this diff:

             if line[0] != 'q':
-                KeyError
+                raise KeyError(f"Expected 'q' delimiter, got '{line[0]}'")
📝 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
if line[0] != 'q':
KeyError
if line[0] != 'q':
raise KeyError(f"Expected 'q' delimiter, got '{line[0]}'")
🧰 Tools
🪛 Ruff (0.14.8)

161-161: Found useless expression. Either assign it to a variable or remove it.

(B018)

🤖 Prompt for AI Agents
In nettacker/core/parser.py around lines 160-161, the line "KeyError" is a no-op
and should actually raise an exception when the first character isn't 'q';
replace that expression with a proper raise statement such as raising KeyError
with a descriptive message (e.g., raise KeyError("expected 'q' as first
character")) so execution is interrupted and the error is clear.

Comment on lines 314 to 327
"version":{
"raw": rest,
"product":product,
"version_template":version_,
"info":info,
"hostname":hostname,
"operating_device":operating_system,
"device_type":device_type,
"cpe":{
"cpe_service":cpe_service,
"cpe_os":cpe_operating_system,
"cpe_h":cpe_hardware_platform,
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix incorrect dictionary key.

Line 320 uses "operating_device" as the key, but the variable is named operating_system and the docstring refers to operating_system. This inconsistency will cause confusion when consuming the YAML output.

Apply this diff:

                         "info":info,
                         "hostname":hostname,
-                        "operating_device":operating_system,
+                        "operating_system":operating_system,
                         "device_type":device_type,
📝 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
"version":{
"raw": rest,
"product":product,
"version_template":version_,
"info":info,
"hostname":hostname,
"operating_device":operating_system,
"device_type":device_type,
"cpe":{
"cpe_service":cpe_service,
"cpe_os":cpe_operating_system,
"cpe_h":cpe_hardware_platform,
}
}
"version":{
"raw": rest,
"product":product,
"version_template":version_,
"info":info,
"hostname":hostname,
"operating_system":operating_system,
"device_type":device_type,
"cpe":{
"cpe_service":cpe_service,
"cpe_os":cpe_operating_system,
"cpe_h":cpe_hardware_platform,
}
}
🤖 Prompt for AI Agents
In nettacker/core/parser.py around lines 314 to 327, the dictionary key
"operating_device" is incorrect and inconsistent with the variable name
operating_system and the docstring; change the key to "operating_system" so the
dict entry reads "operating_system": operating_system to match variable names
and produced YAML output.

Comment on lines 339 to 345
def write_yaml(probes, out_path):
data={
"Excluded ports":[excluded_ports],
"probes":probes,
}
with open(out_path, "w", encoding="utf-8") as f:
yaml.safe_dump(data, f, sort_keys=False)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add docstring for public API.

This public function needs documentation per coding guidelines.

Based on coding guidelines for nettacker/**/*.py.

def write_yaml(probes, out_path):
    """Write parsed probes to YAML file.
    
    Args:
        probes: List of probe dictionaries
        out_path: Output file path for YAML
    """
🤖 Prompt for AI Agents
In nettacker/core/parser.py around lines 339 to 345, the public function
write_yaml lacks a docstring per project guidelines; add a concise triple-quoted
docstring immediately under the def that describes the function purpose,
documents parameters and types (probes: list of probe dicts, out_path: str path
to output YAML), and notes any side effects (writes file) and return value
(None). Ensure formatting matches existing file style and coding guidelines for
nettacker/**/*.py.

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.

2 participants