Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions nettacker/api/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,10 +374,12 @@ def get_results():
@app.route("/results/get", methods=["GET"])
def get_result_content():
"""
get a result HTML/TEXT/JSON content

Retrieve the raw scan result content for a given report id and return it as an HTTP response.

Validates the API key on the incoming request. If the "id" parameter is missing, responds with HTTP 400; if the report cannot be retrieved, responds with HTTP 500.

Returns:
content of the scan result
Response: HTTP response whose body is the scan file content, with the MIME type determined from the file extension and a `Content-Disposition` attachment filename header.
"""
api_key_is_valid(app, flask_request)
scan_id = get_value(flask_request, "id")
Expand All @@ -392,7 +394,7 @@ def get_result_content():
return Response(
file_content,
mimetype=mime_types().get(os.path.splitext(filename)[1], "text/plain"),
headers={"Content-Disposition": "attachment;filename=" + filename.split("/")[-1]},
headers={"Content-Disposition": "attachment;filename=" + os.path.basename(filename)},
)


Expand Down Expand Up @@ -612,4 +614,4 @@ def start_api_server(options):
except KeyboardInterrupt:
for process in multiprocessing.active_children():
process.terminate()
break
break
38 changes: 21 additions & 17 deletions nettacker/core/arg_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,48 +43,52 @@ def __init__(self, api_arguments=None) -> None:
@staticmethod
def load_graphs():
"""
load all available graphs

Discover available graph engine names.
Returns:
an array of graph names
graph_names (list[str]): Unique graph identifiers found under the graph directory, formatted as "<directory>_graph".
"""

graph_names = []
for graph_library in Config.path.graph_dir.glob("*/engine.py"):
graph_names.append(str(graph_library).split("/")[-2] + "_graph")
graph_names.append(graph_library.parent.name + "_graph")
return list(set(graph_names))

@staticmethod
def load_languages():
"""
Get available languages

Discover available language identifiers by scanning the locale directory for YAML files.
Returns:
an array of languages
list[str]: Unique language names derived from locale file stems (order not guaranteed).
"""
languages_list = []

for language in Config.path.locale_dir.glob("*.yaml"):
languages_list.append(str(language).split("/")[-1].split(".")[0])
languages_list.append(language.stem)

return list(set(languages_list))

@staticmethod
def load_modules(limit=-1, full_details=False):
"""
load all available modules

limit: return limited number of modules
full: with full details

Load available scanning modules from the configured modules directory.

Parameters:
limit (int): Maximum number of modules to return; -1 means no limit. If the limit is reached a "..." placeholder will be inserted.
full_details (bool): If True, include each module's parsed `info` mapping as the value; otherwise the value will be None.

Returns:
an array of all module names
dict: Mapping of module keys ("<library>_<category>") to either their `info` dict (when full_details is True) or None. Always includes an "all" entry and may include a "..." placeholder when truncated.

Notes:
This function also updates the module severity and description cache (all_module_severity_and_desc) for each discovered module.
"""
# Search for Modules
module_names = {}
for module_name in sorted(Config.path.modules_dir.glob("**/*.yaml")):
library = str(module_name).split("/")[-1].split(".")[0]
category = str(module_name).split("/")[-2]
library = module_name.stem
category = module_name.parent.name
module = f"{library}_{category}"
contents = yaml.safe_load(TemplateLoader(module).open().split("payload:")[0])
module_names[module] = contents["info"] if full_details else None
Expand Down Expand Up @@ -763,4 +767,4 @@ def parse_arguments(self):
options.time_sleep_between_requests = float(options.time_sleep_between_requests)
options.retries = int(options.retries)

self.arguments = options
self.arguments = options
12 changes: 7 additions & 5 deletions nettacker/core/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,17 @@ def load_yaml(filename):

def get_languages():
"""
Get available languages

Return a deduplicated list of available locale identifiers.

Scans Config.path.locale_dir for files with a .yaml extension and collects each file's stem (filename without extension) as a language identifier.

Returns:
an array of languages
languages (list[str]): List of unique language codes derived from locale YAML filenames.
"""
languages_list = []

for language in Config.path.locale_dir.glob("*.yaml"):
languages_list.append(str(language).split("/")[-1].split(".")[0])
languages_list.append(language.stem)
return list(set(languages_list))


Expand Down Expand Up @@ -68,4 +70,4 @@ def messages(msg_id):
the message content in the selected language if
message found otherwise return message in English
"""
return message_cache[str(msg_id)]
return message_cache[str(msg_id)]
18 changes: 16 additions & 2 deletions nettacker/core/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,29 @@ def parse(module_content, module_inputs):
return module_content

def open(self):
"""
Return the contents of the YAML module file identified by this loader's name.

The name is split on underscores to derive an action (last segment) and a library (remaining segments joined with underscores); the file at Config.path.modules_dir / action / f"{library}.yaml" is opened with UTF-8 encoding and its full text is returned.

Returns:
str: The raw text of the YAML file.
"""
Comment on lines +31 to +38
Copy link
Contributor Author

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Docstring line exceeds 99-character limit.

Line 34 is too long and likely contributing to the ruff-format failure. Split the description across multiple lines.

     def open(self):
         """
         Return the contents of the YAML module file identified by this loader's name.
-        
-        The name is split on underscores to derive an action (last segment) and a library (remaining segments joined with underscores); the file at Config.path.modules_dir / action / f"{library}.yaml" is opened with UTF-8 encoding and its full text is returned.
-        
+
+        The name is split on underscores to derive an action (last segment) and a library
+        (remaining segments joined with underscores). The file at
+        Config.path.modules_dir / action / f"{library}.yaml" is opened with UTF-8 encoding
+        and its full text is returned.
+
         Returns:
             str: The raw text of the YAML file.
         """
📝 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
"""
Return the contents of the YAML module file identified by this loader's name.
The name is split on underscores to derive an action (last segment) and a library (remaining segments joined with underscores); the file at Config.path.modules_dir / action / f"{library}.yaml" is opened with UTF-8 encoding and its full text is returned.
Returns:
str: The raw text of the YAML file.
"""
"""
Return the contents of the YAML module file identified by this loader's name.
The name is split on underscores to derive an action (last segment) and a library
(remaining segments joined with underscores). The file at
Config.path.modules_dir / action / f"{library}.yaml" is opened with UTF-8 encoding
and its full text is returned.
Returns:
str: The raw text of the YAML file.
"""
🤖 Prompt for AI Agents
In nettacker/core/template.py around lines 31 to 38, the docstring contains a
single description line that exceeds the 99-character limit (line 34); break
that long sentence into two or more shorter lines (each <=99 chars) within the
docstring, keeping existing indentation and punctuation, so the content remains
the same but wrapped across multiple lines to satisfy the formatter.

module_name_parts = self.name.split("_")
action = module_name_parts[-1]
library = "_".join(module_name_parts[:-1])

with open(Config.path.modules_dir / action / f"{library}.yaml") as yaml_file:
with open(Config.path.modules_dir / action / f"{library}.yaml", encoding="utf-8") as yaml_file:
return yaml_file.read()

def format(self):
"""
Render the module's YAML template by applying the instance's inputs as format placeholders.

Returns:
formatted (str): The template string produced by calling `open()` and applying `str.format` with `self.inputs`.
"""
return self.open().format(**self.inputs)

def load(self):
return self.parse(yaml.safe_load(self.format()), self.inputs)
return self.parse(yaml.safe_load(self.format()), self.inputs)
12 changes: 11 additions & 1 deletion nettacker/core/utils/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,16 @@ def find_args_value(args_name):


def re_address_repeaters_key_name(key_name):
# Note: This uses "/" as a key delimiter, not a file path separator
"""
Format a slash-delimited key path into a sequence of dictionary-access segments excluding the final key.

Parameters:
key_name (str): A "/"-delimited key path ("/" is a key delimiter, not a filesystem separator).

Returns:
str: Concatenated "['key']" segments for every component of `key_name` except the last; returns an empty string if there are no components before the final segment.
"""
return "".join(["['" + _key + "']" for _key in key_name.split("/")[:-1]])
Comment on lines 167 to 178
Copy link
Contributor Author

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Docstring uses tab indentation instead of 4 spaces.

The docstring at lines 172-176 appears to use tab indentation, which violates the coding guideline requiring 4-space indents. This is likely contributing to the ruff-format failure.

 def re_address_repeaters_key_name(key_name):
     # Note: This uses "/" as a key delimiter, not a file path separator
     """
     Format a slash-delimited key path into a sequence of dictionary-access segments excluding the final key.
-    
+
     Parameters:
-    	key_name (str): A "/"-delimited key path ("/" is a key delimiter, not a filesystem separator).
-    
+        key_name (str): A "/"-delimited key path ("/" is a key delimiter, not a filesystem separator).
+
     Returns:
-    	str: Concatenated "['key']" segments for every component of `key_name` except the last; returns an empty string if there are no components before the final segment.
+        str: Concatenated "['key']" segments for every component of `key_name` except
+            the last; returns an empty string if there are no components before the
+            final segment.
     """
📝 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 re_address_repeaters_key_name(key_name):
# Note: This uses "/" as a key delimiter, not a file path separator
"""
Format a slash-delimited key path into a sequence of dictionary-access segments excluding the final key.
Parameters:
key_name (str): A "/"-delimited key path ("/" is a key delimiter, not a filesystem separator).
Returns:
str: Concatenated "['key']" segments for every component of `key_name` except the last; returns an empty string if there are no components before the final segment.
"""
return "".join(["['" + _key + "']" for _key in key_name.split("/")[:-1]])
def re_address_repeaters_key_name(key_name):
# Note: This uses "/" as a key delimiter, not a file path separator
"""
Format a slash-delimited key path into a sequence of dictionary-access segments excluding the final key.
Parameters:
key_name (str): A "/"-delimited key path ("/" is a key delimiter, not a filesystem separator).
Returns:
str: Concatenated "['key']" segments for every component of `key_name` except
the last; returns an empty string if there are no components before the
final segment.
"""
return "".join(["['" + _key + "']" for _key in key_name.split("/")[:-1]])
🤖 Prompt for AI Agents
In nettacker/core/utils/common.py around lines 167 to 178, the docstring lines
(172–176) use tab indentation instead of the project-required 4-space
indentation; update the docstring so all interior lines are indented with 4
spaces (replace tabs with 4 spaces), maintain the existing content and wrapping,
then run the formatter/linter to verify the ruff-format failure is resolved.



Expand Down Expand Up @@ -449,4 +459,4 @@ def generate_compare_filepath(scan_id):
return "/report_compare_{date_time}_{scan_id}.json".format(
date_time=now(format="%Y_%m_%d_%H_%M_%S"),
scan_id=scan_id,
)
)
Loading