From 91d5499038ed85998772d810094a81a1d8cac799 Mon Sep 17 00:00:00 2001 From: Kelvin Velasquez Date: Tue, 23 Dec 2025 10:34:15 -0600 Subject: [PATCH 1/6] feat(profiler): add sys.monitoring based sampler for Python 3.12+ --- glances/plugins/profiler/__init__.py | 2 + glances/plugins/profiler/profiler.py | 119 +++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 glances/plugins/profiler/__init__.py create mode 100644 glances/plugins/profiler/profiler.py diff --git a/glances/plugins/profiler/__init__.py b/glances/plugins/profiler/__init__.py new file mode 100644 index 00000000..a6266254 --- /dev/null +++ b/glances/plugins/profiler/__init__.py @@ -0,0 +1,2 @@ + +from glances.plugins.profiler.profiler import PluginModel diff --git a/glances/plugins/profiler/profiler.py b/glances/plugins/profiler/profiler.py new file mode 100644 index 00000000..faefbcf6 --- /dev/null +++ b/glances/plugins/profiler/profiler.py @@ -0,0 +1,119 @@ + +"""Profiler plugin.""" + +import sys +from collections import Counter +from glances.plugins.plugin.model import GlancesPluginModel +from glances.logger import logger + +# Constants for sys.monitoring +TOOL_ID = 2 # ID 0 is reserved, 1 was used in test, 2 should be safe +# We will use PY_START to count function entries +EVENT_ID = getattr(sys.monitoring.events, 'PY_START', None) if hasattr(sys, 'monitoring') else None + +class PluginModel(GlancesPluginModel): + """Glances' Profiler Plugin. + + stats is a list of dict (function name, count) + """ + + def __init__(self, args=None, config=None): + """Init the plugin.""" + super(PluginModel, self).__init__(args=args, config=config) + + # We want to display the stats in the UI + self.args = args + + # Init the internal counter + self._counts = Counter() + self._monitoring_active = False + + # Check availability + if not hasattr(sys, 'monitoring'): + logger.warning("sys.monitoring not available. Profiler plugin disabled.") + self.actions.disable() + return + + try: + sys.monitoring.use_tool_id(TOOL_ID, "glances_profiler") + logger.info(f"sys.monitoring tool ID {TOOL_ID} registered.") + self._monitoring_active = True + + # Register callback + sys.monitoring.register_callback(TOOL_ID, EVENT_ID, self._callback) + + # Enable events + sys.monitoring.set_events(TOOL_ID, EVENT_ID) + + except ValueError as e: + logger.error(f"Failed to register sys.monitoring tool: {e}") + self.actions.disable() + self._monitoring_active = False + + def exit(self): + """Stop monitoring.""" + if self._monitoring_active and hasattr(sys, 'monitoring'): + sys.monitoring.set_events(TOOL_ID, 0) + sys.monitoring.free_tool_id(TOOL_ID) + super(PluginModel, self).exit() + + def _callback(self, code, instruction_offset): + """Callback for sys.monitoring.""" + # This is called VERY frqeuently. Keep it minimal. + # We just increment the counter for the code object name. + self._counts[code.co_name] += 1 + return sys.monitoring.DISABLE + + def get_key(self): + """Return the key of the list.""" + return 'function' + + def update_views(self): + """Update the views.""" + # Standard table view + self.views = {} + if not self.stats: + return self.views + + for i in self.stats: + self.views[i[self.get_key()]] = {'hidden': False} + + return self.views + + def update(self): + """Update stats.""" + # Reset stats + self.reset() + + if not self._monitoring_active: + return self.stats + + # Get the top 10 most frequent functions + # We take the counter snapshot and reset it maybe? + # Or just show cumulative? Let's show rate (per second/update) if possible. + # For now, let's just show top N in the current interval. + + # NOTE: To show rate, we would need to diff with previous. + # But for simplicity V1, let's just show the accumulated counts since start (or allow reset). + # Actually, showing "Hot functions right now" implying per-update interval is better. + + # Snapshot and reset internal counter for the next interval? + # WARNING: _callback runs in another thread/context potentially? + # In simple Python (GIL), it is safe-ish, but let's be careful. + # sys.monitoring callback runs synchronously. + + # Let's copy the current state + current_counts = self._counts.copy() + # self._counts.clear() # If we want per-interval stats, we should clear. + + # Sort by count desc + top_n = current_counts.most_common(10) + + for func_name, count in top_n: + stat = { + 'function': func_name, + 'count': count + } + self.stats.append(stat) + + return self.stats From 4c09c9d6428e90c57da8cf855f733629ebb3321f Mon Sep 17 00:00:00 2001 From: Kelvin Velasquez Date: Tue, 23 Dec 2025 11:30:56 -0600 Subject: [PATCH 2/6] style: fix trailing whitespace and unused import --- glances/plugins/profiler/__init__.py | 2 ++ glances/plugins/profiler/profiler.py | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/glances/plugins/profiler/__init__.py b/glances/plugins/profiler/__init__.py index a6266254..0ba11163 100644 --- a/glances/plugins/profiler/__init__.py +++ b/glances/plugins/profiler/__init__.py @@ -1,2 +1,4 @@ from glances.plugins.profiler.profiler import PluginModel + +__all__ = ["PluginModel"] diff --git a/glances/plugins/profiler/profiler.py b/glances/plugins/profiler/profiler.py index faefbcf6..d04cd237 100644 --- a/glances/plugins/profiler/profiler.py +++ b/glances/plugins/profiler/profiler.py @@ -38,7 +38,7 @@ class PluginModel(GlancesPluginModel): sys.monitoring.use_tool_id(TOOL_ID, "glances_profiler") logger.info(f"sys.monitoring tool ID {TOOL_ID} registered.") self._monitoring_active = True - + # Register callback sys.monitoring.register_callback(TOOL_ID, EVENT_ID, self._callback) @@ -86,7 +86,7 @@ class PluginModel(GlancesPluginModel): self.reset() if not self._monitoring_active: - return self.stats + return self.stats # Get the top 10 most frequent functions # We take the counter snapshot and reset it maybe? @@ -98,7 +98,7 @@ class PluginModel(GlancesPluginModel): # Actually, showing "Hot functions right now" implying per-update interval is better. # Snapshot and reset internal counter for the next interval? - # WARNING: _callback runs in another thread/context potentially? + # WARNING: _callback runs in another thread/context potentially? # In simple Python (GIL), it is safe-ish, but let's be careful. # sys.monitoring callback runs synchronously. From d92a857ea28503f5a59216861c7c16ded9fddba7 Mon Sep 17 00:00:00 2001 From: Kelvin Velasquez Date: Tue, 23 Dec 2025 13:21:07 -0600 Subject: [PATCH 3/6] style: auto-format with ruff --- bandit_report.txt | 429 +++++++++++++++++++++++++++ bandit_report_v2.txt | 399 +++++++++++++++++++++++++ glances.conf | 1 + glances/plugins/profiler/__init__.py | 1 - glances/plugins/profiler/profiler.py | 25 +- 5 files changed, 840 insertions(+), 15 deletions(-) create mode 100644 bandit_report.txt create mode 100644 bandit_report_v2.txt create mode 100644 glances.conf diff --git a/bandit_report.txt b/bandit_report.txt new file mode 100644 index 00000000..d4a935c2 --- /dev/null +++ b/bandit_report.txt @@ -0,0 +1,429 @@ +Run started:2025-12-19 19:20:17.053133+00:00 + +Test results: +>> Issue: [B113:request_without_timeout] Call to requests without timeout + Severity: Medium Confidence: Low + CWE: CWE-400 (https://cwe.mitre.org/data/definitions/400.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b113_request_without_timeout.html + Location: glances/amps/nginx/__init__.py:69:14 +68 logger.debug('{}: Update stats using status URL {}'.format(self.NAME, self.get('status_url'))) +69 res = requests.get(self.get('status_url')) +70 if res.ok: + +-------------------------------------------------- +>> Issue: [B404:blacklist] Consider possible security implications associated with the subprocess module. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_imports.html#b404-import-subprocess + Location: glances/amps/systemd/__init__.py:37:0 +36 +37 from subprocess import CalledProcessError, check_output +38 + +-------------------------------------------------- +>> Issue: [B603:subprocess_without_shell_equals_true] subprocess call - check for execution of untrusted input. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b603_subprocess_without_shell_equals_true.html + Location: glances/amps/systemd/__init__.py:62:18 +61 try: +62 res = check_output(self.get('systemctl_cmd').split()) +63 except (OSError, CalledProcessError) as e: + +-------------------------------------------------- +>> Issue: [B105:hardcoded_password_string] Possible hardcoded password: '' + Severity: Low Confidence: Medium + CWE: CWE-259 (https://cwe.mitre.org/data/definitions/259.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b105_hardcoded_password_string.html + Location: glances/client.py:56:28 +55 # Build the URI +56 if args.password != "": +57 self.uri = f'http://{args.username}:{args.password}@{args.client}:{args.port}' + +-------------------------------------------------- +>> Issue: [B608:hardcoded_sql_expressions] Possible SQL injection vector through string-based query construction. + Severity: Medium Confidence: Low + CWE: CWE-89 (https://cwe.mitre.org/data/definitions/89.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b608_hardcoded_sql_expressions.html + Location: glances/exports/glances_cassandra/__init__.py:112:21 +111 try: +112 stmt = f"INSERT INTO {self.table} (plugin, time, stat) VALUES (?, ?, ?)" +113 query = self.session.prepare(stmt) + +-------------------------------------------------- +>> Issue: [B608:hardcoded_sql_expressions] Possible SQL injection vector through string-based query construction. + Severity: Medium Confidence: Low + CWE: CWE-89 (https://cwe.mitre.org/data/definitions/89.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b608_hardcoded_sql_expressions.html + Location: glances/exports/glances_duckdb/__init__.py:172:31 +171 for values in values_list: +172 insert_query = f""" +173 INSERT INTO {plugin} VALUES ( +174 {', '.join(['?' for _ in values])} +175 );""" +176 logger.debug(f"Insert values into table {plugin}: {values}") + +-------------------------------------------------- +>> Issue: [B113:request_without_timeout] Call to requests without timeout + Severity: Medium Confidence: Low + CWE: CWE-400 (https://cwe.mitre.org/data/definitions/400.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b113_request_without_timeout.html + Location: glances/exports/glances_restful/__init__.py:57:12 +56 # Export stats +57 post(self.client, json=self.buffer, allow_redirects=True) +58 # Reset buffer + +-------------------------------------------------- +>> Issue: [B608:hardcoded_sql_expressions] Possible SQL injection vector through string-based query construction. + Severity: Medium Confidence: Medium + CWE: CWE-89 (https://cwe.mitre.org/data/definitions/89.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b608_hardcoded_sql_expressions.html + Location: glances/exports/glances_timescaledb/__init__.py:178:26 +177 # Is the table exists? +178 cur.execute(f"select exists(select * from information_schema.tables where table_name='{plugin}')") +179 if not cur.fetchone()[0]: + +-------------------------------------------------- +>> Issue: [B608:hardcoded_sql_expressions] Possible SQL injection vector through string-based query construction. + Severity: Medium Confidence: Low + CWE: CWE-89 (https://cwe.mitre.org/data/definitions/89.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b608_hardcoded_sql_expressions.html + Location: glances/exports/glances_timescaledb/__init__.py:202:29 +201 insert_list = [f"({','.join(i)})" for i in values_list] +202 insert_query = f"INSERT INTO {plugin} VALUES {','.join(insert_list)};" +203 logger.debug(f"Insert data into table: {insert_query}") + +-------------------------------------------------- +>> Issue: [B404:blacklist] Consider possible security implications associated with the subprocess module. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_imports.html#b404-import-subprocess + Location: glances/globals.py:25:0 +24 import re +25 import subprocess +26 import sys + +-------------------------------------------------- +>> Issue: [B603:subprocess_without_shell_equals_true] subprocess call - check for execution of untrusted input. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b603_subprocess_without_shell_equals_true.html + Location: glances/globals.py:159:14 +158 try: +159 res = subprocess.run(command.split(' '), stdout=subprocess.PIPE).stdout.decode('utf-8') +160 except Exception as e: + +-------------------------------------------------- +>> Issue: [B310:blacklist] Audit url open for permitted schemes. Allowing use of file:/ or custom schemes is often unexpected. + Severity: Medium Confidence: High + CWE: CWE-22 (https://cwe.mitre.org/data/definitions/22.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_calls.html#b310-urllib-urlopen + Location: glances/globals.py:346:11 +345 """Open a url with basic auth""" +346 return urlopen( +347 Request( +348 url, +349 headers={'Authorization': 'Basic ' + base64.b64encode(f'{username}:{password}'.encode()).decode()}, +350 ) +351 ) +352 + +-------------------------------------------------- +>> Issue: [B105:hardcoded_password_string] Possible hardcoded password: '' + Severity: Low Confidence: Medium + CWE: CWE-259 (https://cwe.mitre.org/data/definitions/259.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b105_hardcoded_password_string.html + Location: glances/main.py:46:15 +45 username = "glances" +46 password = "" +47 + +-------------------------------------------------- +>> Issue: [B104:hardcoded_bind_all_interfaces] Possible binding to all interfaces. + Severity: Medium Confidence: Medium + CWE: CWE-605 (https://cwe.mitre.org/data/definitions/605.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b104_hardcoded_bind_all_interfaces.html + Location: glances/main.py:420:20 +419 '--bind', +420 default='0.0.0.0', +421 dest='bind_address', + +-------------------------------------------------- +>> Issue: [B403:blacklist] Consider possible security implications associated with pickle module. + Severity: Low Confidence: High + CWE: CWE-502 (https://cwe.mitre.org/data/definitions/502.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_imports.html#b403-import-pickle + Location: glances/outdated.py:13:0 +12 import os +13 import pickle +14 import threading + +-------------------------------------------------- +>> Issue: [B301:blacklist] Pickle and modules that wrap it can be unsafe when used to deserialize untrusted data, possible security issue. + Severity: Medium Confidence: High + CWE: CWE-502 (https://cwe.mitre.org/data/definitions/502.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_calls.html#b301-pickle + Location: glances/outdated.py:121:30 +120 with open(self.cache_file, 'rb') as f: +121 cached_data = pickle.load(f) +122 except Exception as e: + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_colors.py:109:12 +108 self.SEPARATOR = curses.color_pair(11) +109 except Exception: +110 # Catch exception in TMUX +111 pass +112 + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_colors.py:119:12 +118 curses.init_pair(12, -1, curses.COLOR_BLUE) +119 except Exception: +120 pass +121 else: + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_curses.py:254:12 +253 curses.curs_set(value) +254 except Exception: +255 pass +256 + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_curses.py:459:8 +458 curses.curs_set(1) +459 except Exception: +460 pass +461 try: + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_curses.py:463:8 +462 curses.endwin() +463 except Exception: +464 pass +465 self.is_end = True + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_curses.py:1029:12 +1028 continue +1029 except Exception: +1030 # Avoid exception (see issue #1692) +1031 pass +1032 # Do not display outside the screen + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_curses.py:1049:12 +1048 self.display_stats_with_current_size(m, y, x) +1049 except Exception: +1050 pass +1051 else: + +-------------------------------------------------- +>> Issue: [B701:jinja2_autoescape_false] By default, jinja2 sets autoescape to False. Consider using autoescape=True or use the select_autoescape function to mitigate XSS vulnerabilities. + Severity: High Confidence: High + CWE: CWE-94 (https://cwe.mitre.org/data/definitions/94.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b701_jinja2_autoescape_false.html + Location: glances/outputs/glances_stdout_fetch.py:81:20 +80 # Create a Jinja2 environment +81 jinja_env = jinja2.Environment(loader=jinja2.BaseLoader()) +82 template = jinja_env.from_string(fetch_template) + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_stdout_issue.py:75:12 +74 stats._plugins[plugin].update() +75 except Exception: +76 pass +77 + +-------------------------------------------------- +>> Issue: [B404:blacklist] Consider possible security implications associated with the subprocess module. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_imports.html#b404-import-subprocess + Location: glances/plugins/ports/__init__.py:14:0 +13 import socket +14 import subprocess +15 import threading + +-------------------------------------------------- +>> Issue: [B113:request_without_timeout] Call to requests without timeout + Severity: Medium Confidence: Low + CWE: CWE-400 (https://cwe.mitre.org/data/definitions/400.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b113_request_without_timeout.html + Location: glances/plugins/ports/__init__.py:305:18 +304 try: +305 req = requests.head( +306 web['url'], +307 allow_redirects=True, +308 verify=web['ssl_verify'], +309 proxies=web['proxies'], +310 timeout=web['timeout'], +311 ) +312 except Exception as e: + +-------------------------------------------------- +>> Issue: [B603:subprocess_without_shell_equals_true] subprocess call - check for execution of untrusted input. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b603_subprocess_without_shell_equals_true.html + Location: glances/plugins/ports/__init__.py:367:18 +366 counter = Counter() +367 ret = subprocess.check_call(cmd, stdout=fnull, stderr=fnull, close_fds=True) +368 if ret == 0: + +-------------------------------------------------- +>> Issue: [B101:assert_used] Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b101_assert_used.html + Location: glances/plugins/smart/__init__.py:111:20 +110 try: +111 assert num is not None +112 except Exception as e: + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/plugins/uptime/__init__.py:68:12 +67 stats = str(timedelta(seconds=int(uptime) / 100)) +68 except Exception: +69 pass +70 + +-------------------------------------------------- +>> Issue: [B101:assert_used] Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b101_assert_used.html + Location: glances/processes.py:739:8 +738 """Kill process with pid""" +739 assert pid != os.getpid(), "Glances can kill itself..." +740 p = psutil.Process(pid) + +-------------------------------------------------- +>> Issue: [B404:blacklist] Consider possible security implications associated with the subprocess module. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_imports.html#b404-import-subprocess + Location: glances/secure.py:12:0 +11 import re +12 from subprocess import PIPE, Popen +13 + +-------------------------------------------------- +>> Issue: [B603:subprocess_without_shell_equals_true] subprocess call - check for execution of untrusted input. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b603_subprocess_without_shell_equals_true.html + Location: glances/secure.py:55:12 +54 sub_cmd_split = [_[1:-1] if (_[0] == _[-1] == '"') or (_[0] == _[-1] == '\'') else _ for _ in tmp_split] +55 p = Popen(sub_cmd_split, shell=False, stdin=sub_cmd_stdin, stdout=PIPE, stderr=PIPE) +56 if p_last is not None: + +-------------------------------------------------- +>> Issue: [B101:assert_used] Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b101_assert_used.html + Location: glances/server.py:55:12 +54 (basic, _, encoded) = headers.get('Authorization').partition(' ') +55 assert basic == 'Basic', 'Only basic authentication supported' +56 # Encoded portion of the header is a string + +-------------------------------------------------- +>> Issue: [B105:hardcoded_password_string] Possible hardcoded password: '' + Severity: Low Confidence: Medium + CWE: CWE-259 (https://cwe.mitre.org/data/definitions/259.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b105_hardcoded_password_string.html + Location: glances/server.py:218:33 +217 # Set the server login/password (if -P/--password tag) +218 if self.args.password != "": +219 self.add_user(self.args.username, self.args.password) + +-------------------------------------------------- +>> Issue: [B104:hardcoded_bind_all_interfaces] Possible binding to all interfaces. + Severity: Medium Confidence: Medium + CWE: CWE-605 (https://cwe.mitre.org/data/definitions/605.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b104_hardcoded_bind_all_interfaces.html + Location: glances/servers_list_dynamic.py:212:66 +211 # -B @ overwrite the dynamic IPv4 choice +212 if netifaces_tag and zeroconf_bind_address == '0.0.0.0': +213 zeroconf_bind_address = self.find_active_ip_address() + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/servers_list_dynamic.py:214:16 +213 zeroconf_bind_address = self.find_active_ip_address() +214 except Exception: +215 # Issue #528 (no network interface available) +216 # Issue #3219 (no implementation for gateway()) +217 pass +218 + +-------------------------------------------------- +>> Issue: [B105:hardcoded_password_string] Possible hardcoded password: '' + Severity: Low Confidence: Medium + CWE: CWE-259 (https://cwe.mitre.org/data/definitions/259.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b105_hardcoded_password_string.html + Location: glances/servers_list_static.py:61:27 +60 new_server['username'] = 'glances' +61 new_server['password'] = '' +62 + +-------------------------------------------------- + +Code scanned: + Total lines of code: 18668 + Total lines skipped (#nosec): 0 + Total potential issues skipped due to specifically being disabled (e.g., #nosec BXXX): 0 + +Run metrics: + Total issues (by severity): + Undefined: 0 + Low: 26 + Medium: 11 + High: 1 + Total issues (by confidence): + Undefined: 0 + Low: 6 + Medium: 7 + High: 25 +Files skipped (0): diff --git a/bandit_report_v2.txt b/bandit_report_v2.txt new file mode 100644 index 00000000..d39c38e7 --- /dev/null +++ b/bandit_report_v2.txt @@ -0,0 +1,399 @@ +Run started:2025-12-19 19:21:21.068196+00:00 + +Test results: +>> Issue: [B404:blacklist] Consider possible security implications associated with the subprocess module. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_imports.html#b404-import-subprocess + Location: glances/amps/systemd/__init__.py:37:0 +36 +37 from subprocess import CalledProcessError, check_output +38 + +-------------------------------------------------- +>> Issue: [B603:subprocess_without_shell_equals_true] subprocess call - check for execution of untrusted input. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b603_subprocess_without_shell_equals_true.html + Location: glances/amps/systemd/__init__.py:62:18 +61 try: +62 res = check_output(self.get('systemctl_cmd').split()) +63 except (OSError, CalledProcessError) as e: + +-------------------------------------------------- +>> Issue: [B105:hardcoded_password_string] Possible hardcoded password: '' + Severity: Low Confidence: Medium + CWE: CWE-259 (https://cwe.mitre.org/data/definitions/259.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b105_hardcoded_password_string.html + Location: glances/client.py:56:28 +55 # Build the URI +56 if args.password != "": +57 self.uri = f'http://{args.username}:{args.password}@{args.client}:{args.port}' + +-------------------------------------------------- +>> Issue: [B608:hardcoded_sql_expressions] Possible SQL injection vector through string-based query construction. + Severity: Medium Confidence: Low + CWE: CWE-89 (https://cwe.mitre.org/data/definitions/89.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b608_hardcoded_sql_expressions.html + Location: glances/exports/glances_cassandra/__init__.py:112:21 +111 try: +112 stmt = f"INSERT INTO {self.table} (plugin, time, stat) VALUES (?, ?, ?)" +113 query = self.session.prepare(stmt) + +-------------------------------------------------- +>> Issue: [B608:hardcoded_sql_expressions] Possible SQL injection vector through string-based query construction. + Severity: Medium Confidence: Low + CWE: CWE-89 (https://cwe.mitre.org/data/definitions/89.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b608_hardcoded_sql_expressions.html + Location: glances/exports/glances_duckdb/__init__.py:172:31 +171 for values in values_list: +172 insert_query = f""" +173 INSERT INTO {plugin} VALUES ( +174 {', '.join(['?' for _ in values])} +175 );""" +176 logger.debug(f"Insert values into table {plugin}: {values}") + +-------------------------------------------------- +>> Issue: [B608:hardcoded_sql_expressions] Possible SQL injection vector through string-based query construction. + Severity: Medium Confidence: Medium + CWE: CWE-89 (https://cwe.mitre.org/data/definitions/89.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b608_hardcoded_sql_expressions.html + Location: glances/exports/glances_timescaledb/__init__.py:178:26 +177 # Is the table exists? +178 cur.execute(f"select exists(select * from information_schema.tables where table_name='{plugin}')") +179 if not cur.fetchone()[0]: + +-------------------------------------------------- +>> Issue: [B608:hardcoded_sql_expressions] Possible SQL injection vector through string-based query construction. + Severity: Medium Confidence: Low + CWE: CWE-89 (https://cwe.mitre.org/data/definitions/89.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b608_hardcoded_sql_expressions.html + Location: glances/exports/glances_timescaledb/__init__.py:202:29 +201 insert_list = [f"({','.join(i)})" for i in values_list] +202 insert_query = f"INSERT INTO {plugin} VALUES {','.join(insert_list)};" +203 logger.debug(f"Insert data into table: {insert_query}") + +-------------------------------------------------- +>> Issue: [B404:blacklist] Consider possible security implications associated with the subprocess module. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_imports.html#b404-import-subprocess + Location: glances/globals.py:25:0 +24 import re +25 import subprocess +26 import sys + +-------------------------------------------------- +>> Issue: [B603:subprocess_without_shell_equals_true] subprocess call - check for execution of untrusted input. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b603_subprocess_without_shell_equals_true.html + Location: glances/globals.py:159:14 +158 try: +159 res = subprocess.run(command.split(' '), stdout=subprocess.PIPE).stdout.decode('utf-8') +160 except Exception as e: + +-------------------------------------------------- +>> Issue: [B310:blacklist] Audit url open for permitted schemes. Allowing use of file:/ or custom schemes is often unexpected. + Severity: Medium Confidence: High + CWE: CWE-22 (https://cwe.mitre.org/data/definitions/22.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_calls.html#b310-urllib-urlopen + Location: glances/globals.py:346:11 +345 """Open a url with basic auth""" +346 return urlopen( +347 Request( +348 url, +349 headers={'Authorization': 'Basic ' + base64.b64encode(f'{username}:{password}'.encode()).decode()}, +350 ) +351 ) +352 + +-------------------------------------------------- +>> Issue: [B105:hardcoded_password_string] Possible hardcoded password: '' + Severity: Low Confidence: Medium + CWE: CWE-259 (https://cwe.mitre.org/data/definitions/259.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b105_hardcoded_password_string.html + Location: glances/main.py:46:15 +45 username = "glances" +46 password = "" +47 + +-------------------------------------------------- +>> Issue: [B104:hardcoded_bind_all_interfaces] Possible binding to all interfaces. + Severity: Medium Confidence: Medium + CWE: CWE-605 (https://cwe.mitre.org/data/definitions/605.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b104_hardcoded_bind_all_interfaces.html + Location: glances/main.py:420:20 +419 '--bind', +420 default='0.0.0.0', +421 dest='bind_address', + +-------------------------------------------------- +>> Issue: [B403:blacklist] Consider possible security implications associated with pickle module. + Severity: Low Confidence: High + CWE: CWE-502 (https://cwe.mitre.org/data/definitions/502.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_imports.html#b403-import-pickle + Location: glances/outdated.py:13:0 +12 import os +13 import pickle +14 import threading + +-------------------------------------------------- +>> Issue: [B301:blacklist] Pickle and modules that wrap it can be unsafe when used to deserialize untrusted data, possible security issue. + Severity: Medium Confidence: High + CWE: CWE-502 (https://cwe.mitre.org/data/definitions/502.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_calls.html#b301-pickle + Location: glances/outdated.py:121:30 +120 with open(self.cache_file, 'rb') as f: +121 cached_data = pickle.load(f) +122 except Exception as e: + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_colors.py:109:12 +108 self.SEPARATOR = curses.color_pair(11) +109 except Exception: +110 # Catch exception in TMUX +111 pass +112 + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_colors.py:119:12 +118 curses.init_pair(12, -1, curses.COLOR_BLUE) +119 except Exception: +120 pass +121 else: + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_curses.py:254:12 +253 curses.curs_set(value) +254 except Exception: +255 pass +256 + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_curses.py:459:8 +458 curses.curs_set(1) +459 except Exception: +460 pass +461 try: + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_curses.py:463:8 +462 curses.endwin() +463 except Exception: +464 pass +465 self.is_end = True + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_curses.py:1029:12 +1028 continue +1029 except Exception: +1030 # Avoid exception (see issue #1692) +1031 pass +1032 # Do not display outside the screen + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_curses.py:1049:12 +1048 self.display_stats_with_current_size(m, y, x) +1049 except Exception: +1050 pass +1051 else: + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/outputs/glances_stdout_issue.py:75:12 +74 stats._plugins[plugin].update() +75 except Exception: +76 pass +77 + +-------------------------------------------------- +>> Issue: [B404:blacklist] Consider possible security implications associated with the subprocess module. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_imports.html#b404-import-subprocess + Location: glances/plugins/ports/__init__.py:14:0 +13 import socket +14 import subprocess +15 import threading + +-------------------------------------------------- +>> Issue: [B113:request_without_timeout] Call to requests without timeout + Severity: Medium Confidence: Low + CWE: CWE-400 (https://cwe.mitre.org/data/definitions/400.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b113_request_without_timeout.html + Location: glances/plugins/ports/__init__.py:305:18 +304 try: +305 req = requests.head( +306 web['url'], +307 allow_redirects=True, +308 verify=web['ssl_verify'], +309 proxies=web['proxies'], +310 timeout=web['timeout'], +311 ) +312 except Exception as e: + +-------------------------------------------------- +>> Issue: [B603:subprocess_without_shell_equals_true] subprocess call - check for execution of untrusted input. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b603_subprocess_without_shell_equals_true.html + Location: glances/plugins/ports/__init__.py:367:18 +366 counter = Counter() +367 ret = subprocess.check_call(cmd, stdout=fnull, stderr=fnull, close_fds=True) +368 if ret == 0: + +-------------------------------------------------- +>> Issue: [B101:assert_used] Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b101_assert_used.html + Location: glances/plugins/smart/__init__.py:111:20 +110 try: +111 assert num is not None +112 except Exception as e: + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/plugins/uptime/__init__.py:68:12 +67 stats = str(timedelta(seconds=int(uptime) / 100)) +68 except Exception: +69 pass +70 + +-------------------------------------------------- +>> Issue: [B101:assert_used] Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b101_assert_used.html + Location: glances/processes.py:739:8 +738 """Kill process with pid""" +739 assert pid != os.getpid(), "Glances can kill itself..." +740 p = psutil.Process(pid) + +-------------------------------------------------- +>> Issue: [B404:blacklist] Consider possible security implications associated with the subprocess module. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/blacklists/blacklist_imports.html#b404-import-subprocess + Location: glances/secure.py:12:0 +11 import re +12 from subprocess import PIPE, Popen +13 + +-------------------------------------------------- +>> Issue: [B603:subprocess_without_shell_equals_true] subprocess call - check for execution of untrusted input. + Severity: Low Confidence: High + CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b603_subprocess_without_shell_equals_true.html + Location: glances/secure.py:55:12 +54 sub_cmd_split = [_[1:-1] if (_[0] == _[-1] == '"') or (_[0] == _[-1] == '\'') else _ for _ in tmp_split] +55 p = Popen(sub_cmd_split, shell=False, stdin=sub_cmd_stdin, stdout=PIPE, stderr=PIPE) +56 if p_last is not None: + +-------------------------------------------------- +>> Issue: [B101:assert_used] Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b101_assert_used.html + Location: glances/server.py:55:12 +54 (basic, _, encoded) = headers.get('Authorization').partition(' ') +55 assert basic == 'Basic', 'Only basic authentication supported' +56 # Encoded portion of the header is a string + +-------------------------------------------------- +>> Issue: [B105:hardcoded_password_string] Possible hardcoded password: '' + Severity: Low Confidence: Medium + CWE: CWE-259 (https://cwe.mitre.org/data/definitions/259.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b105_hardcoded_password_string.html + Location: glances/server.py:218:33 +217 # Set the server login/password (if -P/--password tag) +218 if self.args.password != "": +219 self.add_user(self.args.username, self.args.password) + +-------------------------------------------------- +>> Issue: [B104:hardcoded_bind_all_interfaces] Possible binding to all interfaces. + Severity: Medium Confidence: Medium + CWE: CWE-605 (https://cwe.mitre.org/data/definitions/605.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b104_hardcoded_bind_all_interfaces.html + Location: glances/servers_list_dynamic.py:212:66 +211 # -B @ overwrite the dynamic IPv4 choice +212 if netifaces_tag and zeroconf_bind_address == '0.0.0.0': +213 zeroconf_bind_address = self.find_active_ip_address() + +-------------------------------------------------- +>> Issue: [B110:try_except_pass] Try, Except, Pass detected. + Severity: Low Confidence: High + CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b110_try_except_pass.html + Location: glances/servers_list_dynamic.py:214:16 +213 zeroconf_bind_address = self.find_active_ip_address() +214 except Exception: +215 # Issue #528 (no network interface available) +216 # Issue #3219 (no implementation for gateway()) +217 pass +218 + +-------------------------------------------------- +>> Issue: [B105:hardcoded_password_string] Possible hardcoded password: '' + Severity: Low Confidence: Medium + CWE: CWE-259 (https://cwe.mitre.org/data/definitions/259.html) + More Info: https://bandit.readthedocs.io/en/1.9.2/plugins/b105_hardcoded_password_string.html + Location: glances/servers_list_static.py:61:27 +60 new_server['username'] = 'glances' +61 new_server['password'] = '' +62 + +-------------------------------------------------- + +Code scanned: + Total lines of code: 18668 + Total lines skipped (#nosec): 0 + Total potential issues skipped due to specifically being disabled (e.g., #nosec BXXX): 0 + +Run metrics: + Total issues (by severity): + Undefined: 0 + Low: 26 + Medium: 9 + High: 0 + Total issues (by confidence): + Undefined: 0 + Low: 4 + Medium: 7 + High: 24 +Files skipped (0): diff --git a/glances.conf b/glances.conf new file mode 100644 index 00000000..ef0e7ed3 --- /dev/null +++ b/glances.conf @@ -0,0 +1 @@ +[profiler]\nenable=true diff --git a/glances/plugins/profiler/__init__.py b/glances/plugins/profiler/__init__.py index 0ba11163..be5ac9f0 100644 --- a/glances/plugins/profiler/__init__.py +++ b/glances/plugins/profiler/__init__.py @@ -1,4 +1,3 @@ - from glances.plugins.profiler.profiler import PluginModel __all__ = ["PluginModel"] diff --git a/glances/plugins/profiler/profiler.py b/glances/plugins/profiler/profiler.py index d04cd237..e3f4e650 100644 --- a/glances/plugins/profiler/profiler.py +++ b/glances/plugins/profiler/profiler.py @@ -1,4 +1,3 @@ - """Profiler plugin.""" import sys @@ -11,6 +10,7 @@ TOOL_ID = 2 # ID 0 is reserved, 1 was used in test, 2 should be safe # We will use PY_START to count function entries EVENT_ID = getattr(sys.monitoring.events, 'PY_START', None) if hasattr(sys, 'monitoring') else None + class PluginModel(GlancesPluginModel): """Glances' Profiler Plugin. @@ -41,10 +41,10 @@ class PluginModel(GlancesPluginModel): # Register callback sys.monitoring.register_callback(TOOL_ID, EVENT_ID, self._callback) - + # Enable events sys.monitoring.set_events(TOOL_ID, EVENT_ID) - + except ValueError as e: logger.error(f"Failed to register sys.monitoring tool: {e}") self.actions.disable() @@ -89,31 +89,28 @@ class PluginModel(GlancesPluginModel): return self.stats # Get the top 10 most frequent functions - # We take the counter snapshot and reset it maybe? + # We take the counter snapshot and reset it maybe? # Or just show cumulative? Let's show rate (per second/update) if possible. # For now, let's just show top N in the current interval. - + # NOTE: To show rate, we would need to diff with previous. # But for simplicity V1, let's just show the accumulated counts since start (or allow reset). # Actually, showing "Hot functions right now" implying per-update interval is better. - + # Snapshot and reset internal counter for the next interval? # WARNING: _callback runs in another thread/context potentially? # In simple Python (GIL), it is safe-ish, but let's be careful. # sys.monitoring callback runs synchronously. - + # Let's copy the current state current_counts = self._counts.copy() # self._counts.clear() # If we want per-interval stats, we should clear. - + # Sort by count desc top_n = current_counts.most_common(10) - + for func_name, count in top_n: - stat = { - 'function': func_name, - 'count': count - } + stat = {'function': func_name, 'count': count} self.stats.append(stat) - + return self.stats From d3aef54544f1ee20fda0b0db08d9a7f51eb396dc Mon Sep 17 00:00:00 2001 From: Kelvin Velasquez Date: Tue, 23 Dec 2025 14:30:12 -0600 Subject: [PATCH 4/6] style: fix UP008 manual super() call --- glances/plugins/profiler/profiler.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/glances/plugins/profiler/profiler.py b/glances/plugins/profiler/profiler.py index e3f4e650..50e59a59 100644 --- a/glances/plugins/profiler/profiler.py +++ b/glances/plugins/profiler/profiler.py @@ -2,8 +2,9 @@ import sys from collections import Counter -from glances.plugins.plugin.model import GlancesPluginModel + from glances.logger import logger +from glances.plugins.plugin.model import GlancesPluginModel # Constants for sys.monitoring TOOL_ID = 2 # ID 0 is reserved, 1 was used in test, 2 should be safe @@ -19,7 +20,7 @@ class PluginModel(GlancesPluginModel): def __init__(self, args=None, config=None): """Init the plugin.""" - super(PluginModel, self).__init__(args=args, config=config) + super().__init__(args=args, config=config) # We want to display the stats in the UI self.args = args @@ -55,7 +56,7 @@ class PluginModel(GlancesPluginModel): if self._monitoring_active and hasattr(sys, 'monitoring'): sys.monitoring.set_events(TOOL_ID, 0) sys.monitoring.free_tool_id(TOOL_ID) - super(PluginModel, self).exit() + super().exit() def _callback(self, code, instruction_offset): """Callback for sys.monitoring.""" From 8c52a114c1d9c39961c11ee947a0bd20234ace1d Mon Sep 17 00:00:00 2001 From: Kelvin Velasquez Date: Tue, 23 Dec 2025 14:41:43 -0600 Subject: [PATCH 5/6] fix(profiler): initialize stats as list in reset() --- glances/plugins/profiler/profiler.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/glances/plugins/profiler/profiler.py b/glances/plugins/profiler/profiler.py index 50e59a59..884ecee3 100644 --- a/glances/plugins/profiler/profiler.py +++ b/glances/plugins/profiler/profiler.py @@ -81,6 +81,11 @@ class PluginModel(GlancesPluginModel): return self.views + def reset(self): + """Reset stats.""" + self.stats = [] + self._counts.clear() + def update(self): """Update stats.""" # Reset stats From d3271af5d55a1112aa8757607f1dbf969e29c755 Mon Sep 17 00:00:00 2001 From: Kelvin Velasquez Date: Tue, 23 Dec 2025 14:51:42 -0600 Subject: [PATCH 6/6] fix(profiler): handle missing _counts in reset() during init --- glances/plugins/profiler/profiler.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/glances/plugins/profiler/profiler.py b/glances/plugins/profiler/profiler.py index 884ecee3..785c30c4 100644 --- a/glances/plugins/profiler/profiler.py +++ b/glances/plugins/profiler/profiler.py @@ -84,7 +84,10 @@ class PluginModel(GlancesPluginModel): def reset(self): """Reset stats.""" self.stats = [] - self._counts.clear() + if hasattr(self, '_counts'): + self._counts.clear() + else: + self._counts = Counter() def update(self): """Update stats."""