Skip to content

test: unskip 12 tests, add coverage tests, fix thread-unsafe stdout pollution#124

Merged
docdyhr merged 1 commit intomasterfrom
test/quality-and-coverage-85pct
Apr 1, 2026
Merged

test: unskip 12 tests, add coverage tests, fix thread-unsafe stdout pollution#124
docdyhr merged 1 commit intomasterfrom
test/quality-and-coverage-85pct

Conversation

@docdyhr
Copy link
Copy Markdown
Owner

@docdyhr docdyhr commented Mar 31, 2026

Summary

  • Root cause fixed: test_concurrent_operations used patch("builtins.print") inside threads — not thread-safe. Racing patch/unpatch operations permanently replaced builtins.print with a MagicMock, silencing all subsequent capsys output captures and causing 10 test_ui.py tests to fail with captured.out == '' in the full suite.
  • Second corruption vector: open(MagicMock(), "w") inside export paths — Python resolves MagicMock().__index__() == 1 as fd 1 (stdout), opening then closing stdout. Fixed by adding export_format=None, output_file=None to the concurrent test's MagicMock calls.
  • 12 skipped tests unskipped in tests/test_ui.py: switched from monkeypatch.setattr to patch() context managers for reliable HAS_TERMCOLOR overrides across the full suite.
  • 37 new tests added targeting previously-uncovered handler branches.

Test plan

  • Full suite passes: 2194 passed, 3 skipped (verified locally)
  • tests/test_ui.py::TestTerminalOutput — all 30 tests pass in full suite context
  • tests/test_integration.py::test_concurrent_operations — still passes with the fix
  • Pre-commit hooks (ruff, ruff-format) clean

🤖 Generated with Claude Code

Summary by Sourcery

Increase test coverage for handlers and UI while fixing thread-unsafe test behavior and enabling previously skipped UI tests.

Bug Fixes:

  • Fix concurrent operations integration test to avoid thread-unsafe stdout mocking and accidental stdout closure during export handling.

Enhancements:

  • Add tests covering brew handler display, export, error handling, debug logging, and strict mode branches.
  • Add tests covering outdated handler notification behavior across platforms, availability states, and error paths.
  • Add tests for setup handlers to cover config initialization fallbacks and logging setup error recovery.
  • Add tests for utils warning suppression internals to verify logging filter behavior for different warning types and sources.
  • Unskip and stabilize multiple UI tests by using termcolor availability patches instead of monkeypatch and by relaxing environment-specific assumptions about output behavior.

Tests:

  • Add or expand unit tests across handlers, utilities, and UI modules to exercise previously uncovered branches and edge cases in output, notification, and error-handling logic.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Mar 31, 2026

Reviewer's Guide

Adds targeted coverage tests for previously uncovered handler branches, fixes a thread-unsafe stdout/print mocking pattern in an integration test, and unskips/refactors several UI output tests to rely on stable termcolor fallbacks instead of environment-sensitive monkeypatching.

File-Level Changes

Change Details Files
Add coverage tests for previously uncovered Homebrew handler branches including display, export, error, and debug paths.
  • Introduce TestDisplayBrewList to validate auto-update marker rendering based on options and auto-update lists.
  • Add TestHandleExportIfRequested to assert stdout vs. file behavior depending on export options.
  • Add TestHandleListBrewsOuterException to cover the outer exception handler return code.
  • Add TestGetHomebrewCasksHandler to cover the generic exception fallback path returning an empty list.
  • Add TestLogDebugInfo to exercise debug=False no-op behavior and debug=True logging loops.
  • Add TestDetermineStrictMode to cover strict_recom/strict_recommend and test-detection branches including argv-based mock_test setting.
tests/handlers/test_brew_handlers_coverage.py
Add tests to cover macOS notification handler behavior across availability, platform, success, failure, and exception paths.
  • Import _send_notification_if_available into outdated handler tests for direct coverage.
  • Create TestSendNotificationIfAvailable test class with a helper progress bar mock wired to the expected color() behavior.
  • Cover cases where notifications are unavailable, on non-darwin platforms, when only outdated items are sent, on notification failure, and when notification raising exceptions triggers logging without crashing.
tests/test_outdated_handlers.py
Unskip and stabilize UI print/colored tests by using patch-based termcolor fallbacks and simplifying expectations around stdout behavior.
  • Remove pytest.skip markers from multiple UI tests and replace monkeypatch-based HAS_TERMCOLOR/cprint overrides with context-managed patch on versiontracker.ui.HAS_TERMCOLOR.
  • Simplify print_functions_fallback and print_functions_edge_cases to rely on direct call behavior and straightforward stdout assertions.
  • Relax colored fallback expectations to only require that the original text appears in the result regardless of color handling.
  • Simplify cprint fallback test to assert that text is written to stdout without environment-specific fallbacks.
  • Tighten print_functions_with_file_kwarg to assert that output is redirected to the provided file-like object and not printed to stdout.
tests/test_ui.py
Add coverage for setup handler branches around config initialization and logging error recovery.
  • Add tests to ensure handle_initialize_config uses opts.config when no cached config exists, by asserting Config(config_file=...) is called.
  • Add tests to ensure OSError during Config initialization triggers a fallback to Config() with no arguments and returns success.
  • Add tests to ensure handle_setup_logging recovers from an initial basicConfig failure, re-invokes basicConfig, and logs the original error.
tests/handlers/test_setup_handlers.py
Add coverage for suppress_console_warnings internals and its WarningFilter behavior on different log record types and sources.
  • Introduce TestSuppressConsoleWarningsInternals with a helper that installs suppress_console_warnings and retrieves the attached WarningFilter.
  • Verify that warnings originating from versiontracker files are never suppressed by the filter.
  • Verify that deprecation-like warnings from external code are suppressed.
  • Verify that non-WARNING log levels always pass through the filter.
tests/handlers/test_utils_handlers.py
Fix thread-unsafe mocking and potential stdout corruption in concurrent integration tests by removing per-thread print patching and avoiding open(MagicMock()) misuse.
  • Update test_concurrent_operations to stop using patch("builtins.print") inside threads, eliminating a race that could permanently replace builtins.print with a MagicMock and break subsequent capsys captures.
  • Ensure MagicMock options passed to handle_list_apps and handle_list_brews explicitly set export_format=None and output_file=None to avoid open(MagicMock()) being resolved as fd 1 (stdout), which previously could close stdout in tests.
  • Keep the overall concurrency behavior and result/error collection semantics intact while making I/O interactions deterministic and thread-safe.
tests/test_integration.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions
Copy link
Copy Markdown

🔒 Security Analysis Report

Security Analysis Report

Generated: Tue Mar 31 22:30:48 UTC 2026
Repository: docdyhr/versiontracker
Commit: 7f1aa09

Bandit Security Scan

�[?25l
�[2KWorking... �[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m  0%�[0m �[36m-:--:--�[0m
�[2KWorking... �[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m  0%�[0m �[36m-:--:--�[0m
�[2KWorking... �[91m━━━━━�[0m�[91m╸�[0m�[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m 15%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━�[0m�[90m╺�[0m�[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m 26%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━━━�[0m�[90m╺�[0m�[90m━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m 35%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━━━━━━━━�[0m�[90m╺�[0m�[90m━━━━━━━━━━━━━━━━━━━━�[0m �[35m 48%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━━━━━━━━━━━━━�[0m�[90m╺�[0m�[90m━━━━━━━━━━━━━━━�[0m �[35m 61%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m�[91m╸�[0m�[90m━━━━━━━━━━━�[0m �[35m 72%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m�[91m╸�[0m�[90m━━━━━━━━�[0m �[35m 80%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m�[91m╸�[0m�[90m━━━━�[0m �[35m 89%�[0m �[36m0:00:01�[0m
�[2KWorking... �[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m100%�[0m �[33m0:00:01�[0m
�[2KWorking... �[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m100%�[0m �[33m0:00:01�[0m
�[?25hRun started:2026-03-31 22:30:50.168106+00:00

Test results:
>> 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.4/plugins/b608_hardcoded_sql_expressions.html
   Location: versiontracker/advanced_cache.py:610:24
609	                # Use f-string for better readability
610	                msg = f"Failed to delete from cache {key}: {e}"
611	                raise CacheError(msg) from e

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/config.py:174:16
173	                cmd = f"{path} --version"
174	                import subprocess
175	

--------------------------------------------------
>> 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.4/plugins/b603_subprocess_without_shell_equals_true.html
   Location: versiontracker/config.py:177:29
176	                try:
177	                    result = subprocess.run(cmd.split(), capture_output=True, timeout=2, check=False)
178	                    returncode = result.returncode

--------------------------------------------------
>> 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.4/plugins/b110_try_except_pass.html
   Location: versiontracker/experimental/analytics.py:645:16
644	                    self.peak_cpu = max(self.peak_cpu, cpu_percent)
645	                except Exception:
646	                    pass
647	                time.sleep(0.05)

--------------------------------------------------
>> 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.4/plugins/b101_assert_used.html
   Location: versiontracker/handlers/outdated_handlers.py:493:8
492	        # Type assertion: apps and brews cannot be None here due to exit_code checks above
493	        assert apps is not None
494	        assert brews 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.4/plugins/b101_assert_used.html
   Location: versiontracker/handlers/outdated_handlers.py:494:8
493	        assert apps is not None
494	        assert brews is not None
495	        apps = _filter_applications(apps, brews, include_brews)

--------------------------------------------------
>> 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.4/plugins/b101_assert_used.html
   Location: versiontracker/handlers/outdated_handlers.py:511:8
510	        # Type assertion: outdated_info cannot be None here due to exit_code check
511	        assert outdated_info is not None
512	        # Type cast: outdated_info cannot be None here due to exit_code check above

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/homebrew.py:12:0
11	import re
12	import subprocess
13	import time

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/macos_integration.py:11:0
10	import os
11	import subprocess
12	from pathlib import Path

--------------------------------------------------
>> 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.4/plugins/b603_subprocess_without_shell_equals_true.html
   Location: versiontracker/macos_integration.py:245:21
244	            # nosec B603 - osascript with controlled arguments
245	            result = subprocess.run(cmd, capture_output=True, text=True)
246	

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/menubar_app.py:8:0
7	import logging
8	import subprocess
9	import sys

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/plugins/example_plugins.py:322:16
321	            try:
322	                import subprocess
323	

--------------------------------------------------
>> Issue: [B607:start_process_with_partial_path] Starting a process with a partial executable path
   Severity: Low   Confidence: High
   CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b607_start_process_with_partial_path.html
   Location: versiontracker/plugins/example_plugins.py:324:25
323	
324	                result = subprocess.run(["brew", "--version"], capture_output=True, text=True, timeout=5)
325	                if result.returncode == 0:

--------------------------------------------------
>> 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.4/plugins/b603_subprocess_without_shell_equals_true.html
   Location: versiontracker/plugins/example_plugins.py:324:25
323	
324	                result = subprocess.run(["brew", "--version"], capture_output=True, text=True, timeout=5)
325	                if result.returncode == 0:

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/utils.py:15:0
14	import shutil
15	import subprocess
16	import sys

--------------------------------------------------
>> Issue: [B607:start_process_with_partial_path] Starting a process with a partial executable path
   Severity: Low   Confidence: High
   CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b607_start_process_with_partial_path.html
   Location: versiontracker/utils.py:784:17
783	    try:
784	        result = subprocess.run(["which", "brew"], capture_output=True, text=True, timeout=5)
785	        return result.returncode == 0

--------------------------------------------------
>> 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.4/plugins/b603_subprocess_without_shell_equals_true.html
   Location: versiontracker/utils.py:784:17
783	    try:
784	        result = subprocess.run(["which", "brew"], capture_output=True, text=True, timeout=5)
785	        return result.returncode == 0

--------------------------------------------------
>> Issue: [B607:start_process_with_partial_path] Starting a process with a partial executable path
   Severity: Low   Confidence: High
   CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b607_start_process_with_partial_path.html
   Location: versiontracker/utils.py:800:17
799	    try:
800	        result = subprocess.run(["brew", "--prefix"], capture_output=True, text=True, timeout=5)
801	        if result.returncode == 0:

--------------------------------------------------
>> 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.4/plugins/b603_subprocess_without_shell_equals_true.html
   Location: versiontracker/utils.py:800:17
799	    try:
800	        result = subprocess.run(["brew", "--prefix"], capture_output=True, text=True, timeout=5)
801	        if result.returncode == 0:

--------------------------------------------------
>> 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.4/plugins/b603_subprocess_without_shell_equals_true.html
   Location: versiontracker/utils.py:833:15
832	    try:
833	        return subprocess.run(command, capture_output=True, text=True, timeout=timeout, check=check)
834	    except subprocess.TimeoutExpired as e:

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/version/batch.py:11:0
10	import logging
11	import subprocess
12	from concurrent.futures import ThreadPoolExecutor

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/version/homebrew.py:18:0
17	import logging
18	import subprocess
19	

--------------------------------------------------

Code scanned:
	Total lines of code: 15020
	Total lines skipped (#nosec): 0
	Total potential issues skipped due to specifically being disabled (e.g., #nosec BXXX): 33

Run metrics:
	Total issues (by severity):
		Undefined: 0
		Low: 21
		Medium: 1
		High: 0
	Total issues (by confidence):
		Undefined: 0
		Low: 1
		Medium: 0
		High: 21
Files skipped (0):

Safety Check Results



�[33m�[1m+===========================================================================================================================================================================================+�[0m


�[31m�[1mDEPRECATED: �[0m�[33m�[1mthis command (`check`) has been DEPRECATED, and will be unsupported beyond 01 June 2024.�[0m


�[32mWe highly encourage switching to the new �[0m�[32m�[1m`scan`�[0m�[32m command which is easier to use, more powerful, and can be set up to mimic the deprecated command if required.�[0m


�[33m�[1m+===========================================================================================================================================================================================+�[0m


+==============================================================================+

                               /$$$$$$            /$$
                              /$$__  $$          | $$
           /$$$$$$$  /$$$$$$ | $$  \__//$$$$$$  /$$$$$$   /$$   /$$
          /$$_____/ |____  $$| $$$$   /$$__  $$|_  $$_/  | $$  | $$
         |  $$$$$$   /$$$$$$$| $$_/  | $$$$$$$$  | $$    | $$  | $$
          \____  $$ /$$__  $$| $$    | $$_____/  | $$ /$$| $$  | $$
          /$$$$$$$/|  $$$$$$$| $$    |  $$$$$$$  |  $$$$/|  $$$$$$$
         |_______/  \_______/|__/     \_______/   \___/   \____  $$
                                                          /$$  | $$
                                                         |  $$$$$$/
  by safetycli.com                                        \______/

+==============================================================================+

 �[1mREPORT�[0m 

  Safety �[1mv3.7.0�[0m is scanning for �[1mVulnerabilities�[0m�[1m...�[0m
�[1m  Scanning dependencies�[0m in your �[1menvironment:�[0m

  -> /opt/hostedtoolcache/Python/3.13.12/x64/lib/python3.13/site-packages

  Using �[1mopen-source vulnerability database�[0m
�[1m  Found and scanned 106 packages�[0m
  Timestamp �[1m2026-03-31 22:30:51�[0m
�[1m  0�[0m�[1m vulnerabilities reported�[0m
�[1m  0�[0m�[1m vulnerabilities ignored�[0m
+==============================================================================+

 �[32m�[1mNo known security vulnerabilities reported.�[0m 

+==============================================================================+�[0m


�[33m�[1m+===========================================================================================================================================================================================+�[0m


�[31m�[1mDEPRECATED: �[0m�[33m�[1mthis command (`check`) has been DEPRECATED, and will be unsupported beyond 01 June 2024.�[0m


�[32mWe highly encourage switching to the new �[0m�[32m�[1m`scan`�[0m�[32m command which is easier to use, more powerful, and can be set up to mimic the deprecated command if required.�[0m


�[33m�[1m+===========================================================================================================================================================================================+�[0m


Pip-Audit Results

�[?25l�[32m-�[0m Collecting inputs
�[2K�[32m-�[0m Collecting inputs
�[2K�[32m-�[0m Collecting inputs
�[2K�[32m-�[0m Collecting inputs
�[2K�[32m\�[0m Collecting inputs
�[2K�[32m\�[0m Collecting inputs
�[2K�[32m\�[0m Collecting inputs
�[2K�[32m\�[0m Collecting aiohappyeyeballs (2.6.1)
�[2K�[32m\�[0m Auditing aiohappyeyeballs (2.6.1)
�[2K�[32m\�[0m Collecting aiohttp (3.13.5)
�[2K�[32m\�[0m Auditing aiohttp (3.13.5)
�[2K�[32m\�[0m Collecting aiosignal (1.4.0)
�[2K�[32m\�[0m Auditing aiosignal (1.4.0)
�[2K�[32m\�[0m Collecting annotated-doc (0.0.4)
�[2K�[32m\�[0m Auditing annotated-doc (0.0.4)
�[2K�[32m\�[0m Collecting annotated-types (0.7.0)
�[2K�[32m\�[0m Auditing annotated-types (0.7.0)
�[2K�[32m\�[0m Collecting anyio (4.13.0)
�[2K�[32m\�[0m Auditing anyio (4.13.0)
�[2K�[32m\�[0m Collecting attrs (26.1.0)
�[2K�[32m\�[0m Auditing attrs (26.1.0)
�[2K�[32m\�[0m Collecting Authlib (1.6.9)
�[2K�[32m\�[0m Auditing Authlib (1.6.9)
�[2K�[32m\�[0m Collecting bandit (1.9.4)
�[2K�[32m\�[0m Auditing bandit (1.9.4)
�[2K�[32m\�[0m Collecting black (26.3.1)
�[2K�[32m\�[0m Auditing black (26.3.1)
�[2K�[32m\�[0m Collecting boolean.py (5.0)
�[2K�[32m\�[0m Auditing boolean.py (5.0)
�[2K�[32m\�[0m Collecting build (1.4.2)
�[2K�[32m\�[0m Auditing build (1.4.2)
�[2K�[32m\�[0m Collecting CacheControl (0.14.4)
�[2K�[32m\�[0m Auditing CacheControl (0.14.4)
�[2K�[32m\�[0m Collecting certifi (2026.2.25)
�[2K�[32m\�[0m Auditing certifi (2026.2.25)
�[2K�[32m\�[0m Collecting cffi (2.0.0)
�[2K�[32m\�[0m Auditing cffi (2.0.0)
�[2K�[32m\�[0m Collecting charset-normalizer (3.4.6)
�[2K�[32m\�[0m Auditing charset-normalizer (3.4.6)
�[2K�[32m\�[0m Collecting click (8.3.1)
�[2K�[32m\�[0m Auditing click (8.3.1)
�[2K�[32m\�[0m Collecting coverage (7.13.5)
�[2K�[32m\�[0m Auditing coverage (7.13.5)
�[2K�[32m\�[0m Collecting cryptography (46.0.6)
�[2K�[32m\�[0m Auditing cryptography (46.0.6)
�[2K�[32m\�[0m Collecting cyclonedx-python-lib (11.7.0)
�[2K�[32m\�[0m Auditing cyclonedx-python-lib (11.7.0)
�[2K�[32m\�[0m Collecting defusedxml (0.7.1)
�[2K�[32m\�[0m Auditing defusedxml (0.7.1)
�[2K�[32m\�[0m Collecting docutils (0.22.4)
�[2K�[32m\�[0m Collecting docutils (0.22.4)
�[2K�[32m\�[0m Auditing docutils (0.22.4)
�[2K�[32m\�[0m Collecting dparse (0.6.4)
�[2K�[32m\�[0m Auditing dparse (0.6.4)
�[2K�[32m\�[0m Collecting filelock (3.25.2)
�[2K�[32m\�[0m Auditing filelock (3.25.2)
�[2K�[32m\�[0m Collecting frozenlist (1.8.0)
�[2K�[32m\�[0m Auditing frozenlist (1.8.0)
�[2K�[32m\�[0m Collecting h11 (0.16.0)
�[2K�[32m\�[0m Auditing h11 (0.16.0)
�[2K�[32m\�[0m Collecting httpcore (1.0.9)
�[2K�[32m\�[0m Auditing httpcore (1.0.9)
�[2K�[32m\�[0m Collecting httpx (0.28.1)
�[2K�[32m\�[0m Auditing httpx (0.28.1)
�[2K�[32m\�[0m Collecting id (1.6.1)
�[2K�[32m\�[0m Auditing id (1.6.1)
�[2K�[32m\�[0m Collecting idna (3.11)
�[2K�[32m\�[0m Auditing idna (3.11)
�[2K�[32m\�[0m Collecting iniconfig (2.3.0)
�[2K�[32m\�[0m Auditing iniconfig (2.3.0)
�[2K�[32m\�[0m Collecting jaraco.classes (3.4.0)
�[2K�[32m\�[0m Auditing jaraco.classes (3.4.0)
�[2K�[32m\�[0m Collecting jaraco.context (6.1.2)
�[2K�[32m\�[0m Auditing jaraco.context (6.1.2)
�[2K�[32m\�[0m Collecting jaraco.functools (4.4.0)
�[2K�[32m\�[0m Auditing jaraco.functools (4.4.0)
�[2K�[32m\�[0m Collecting jeepney (0.9.0)
�[2K�[32m\�[0m Auditing jeepney (0.9.0)
�[2K�[32m\�[0m Collecting Jinja2 (3.1.6)
�[2K�[32m\�[0m Auditing Jinja2 (3.1.6)
�[2K�[32m\�[0m Collecting joblib (1.5.3)
�[2K�[32m\�[0m Auditing joblib (1.5.3)
�[2K�[32m\�[0m Collecting keyring (25.7.0)
�[2K�[32m\�[0m Auditing keyring (25.7.0)
�[2K�[32m\�[0m Collecting librt (0.8.1)
�[2K�[32m\�[0m Auditing librt (0.8.1)
�[2K�[32m\�[0m Collecting license-expression (30.4.4)
�[2K�[32m\�[0m Auditing license-expression (30.4.4)
�[2K�[32m\�[0m Collecting macversiontracker (0.9.0)
�[2K�[32m|�[0m Auditing macversiontracker (0.9.0)
�[2K�[32m|�[0m Collecting markdown-it-py (4.0.0)
�[2K�[32m|�[0m Auditing markdown-it-py (4.0.0)
�[2K�[32m|�[0m Collecting MarkupSafe (3.0.3)
�[2K�[32m|�[0m Auditing MarkupSafe (3.0.3)
�[2K�[32m|�[0m Collecting marshmallow (4.2.3)
�[2K�[32m|�[0m Auditing marshmallow (4.2.3)
�[2K�[32m|�[0m Collecting mdurl (0.1.2)
�[2K�[32m|�[0m Auditing mdurl (0.1.2)
�[2K�[32m|�[0m Collecting more-itertools (10.8.0)
�[2K�[32m|�[0m Auditing more-itertools (10.8.0)
�[2K�[32m|�[0m Collecting msgpack (1.1.2)
�[2K�[32m|�[0m Auditing msgpack (1.1.2)
�[2K�[32m|�[0m Collecting multidict (6.7.1)
�[2K�[32m|�[0m Auditing multidict (6.7.1)
�[2K�[32m|�[0m Collecting mypy (1.20.0)
�[2K�[32m|�[0m Collecting mypy (1.20.0)
�[2K�[32m|�[0m Auditing mypy (1.20.0)
�[2K�[32m|�[0m Collecting mypy_extensions (1.1.0)
�[2K�[32m|�[0m Auditing mypy_extensions (1.1.0)
�[2K�[32m|�[0m Collecting nh3 (0.3.4)
�[2K�[32m|�[0m Auditing nh3 (0.3.4)
�[2K�[32m|�[0m Collecting nltk (3.9.4)
�[2K�[32m|�[0m Auditing nltk (3.9.4)
�[2K�[32m|�[0m Collecting packageurl-python (0.17.6)
�[2K�[32m|�[0m Auditing packageurl-python (0.17.6)
�[2K�[32m|�[0m Collecting packaging (26.0)
�[2K�[32m|�[0m Auditing packaging (26.0)
�[2K�[32m|�[0m Collecting pathspec (1.0.4)
�[2K�[32m|�[0m Auditing pathspec (1.0.4)
�[2K�[32m|�[0m Collecting pip (26.0.1)
�[2K�[32m|�[0m Auditing pip (26.0.1)
�[2K�[32m|�[0m Collecting pip-api (0.0.34)
�[2K�[32m|�[0m Auditing pip-api (0.0.34)
�[2K�[32m|�[0m Collecting pip_audit (2.10.0)
�[2K�[32m|�[0m Auditing pip_audit (2.10.0)
�[2K�[32m|�[0m Collecting pip-requirements-parser (32.0.1)
�[2K�[32m|�[0m Auditing pip-requirements-parser (32.0.1)
�[2K�[32m|�[0m Collecting platformdirs (4.9.4)
�[2K�[32m|�[0m Auditing platformdirs (4.9.4)
�[2K�[32m|�[0m Collecting pluggy (1.6.0)
�[2K�[32m|�[0m Auditing pluggy (1.6.0)
�[2K�[32m|�[0m Collecting propcache (0.4.1)
�[2K�[32m|�[0m Auditing propcache (0.4.1)
�[2K�[32m|�[0m Collecting psutil (7.2.2)
�[2K�[32m|�[0m Auditing psutil (7.2.2)
�[2K�[32m|�[0m Collecting py-serializable (2.1.0)
�[2K�[32m|�[0m Auditing py-serializable (2.1.0)
�[2K�[32m|�[0m Collecting pycparser (3.0)
�[2K�[32m|�[0m Auditing pycparser (3.0)
�[2K�[32m|�[0m Collecting pydantic (2.12.5)
�[2K�[32m|�[0m Auditing pydantic (2.12.5)
�[2K�[32m|�[0m Collecting pydantic_core (2.41.5)
�[2K�[32m|�[0m Auditing pydantic_core (2.41.5)
�[2K�[32m|�[0m Collecting Pygments (2.20.0)
�[2K�[32m|�[0m Auditing Pygments (2.20.0)
�[2K�[32m|�[0m Collecting pyparsing (3.3.2)
�[2K�[32m|�[0m Auditing pyparsing (3.3.2)
�[2K�[32m|�[0m Collecting pyproject_hooks (1.2.0)
�[2K�[32m|�[0m Auditing pyproject_hooks (1.2.0)
�[2K�[32m|�[0m Collecting pytest (9.0.2)
�[2K�[32m|�[0m Auditing pytest (9.0.2)
�[2K�[32m|�[0m Collecting pytest-asyncio (1.3.0)
�[2K�[32m|�[0m Auditing pytest-asyncio (1.3.0)
�[2K�[32m|�[0m Collecting pytest-cov (7.1.0)
�[2K�[32m|�[0m Auditing pytest-cov (7.1.0)
�[2K�[32m|�[0m Collecting pytest-mock (3.15.1)
�[2K�[32m|�[0m Auditing pytest-mock (3.15.1)
�[2K�[32m|�[0m Collecting pytest-timeout (2.4.0)
�[2K�[32m|�[0m Auditing pytest-timeout (2.4.0)
�[2K�[32m|�[0m Collecting pytokens (0.4.1)
�[2K�[32m|�[0m Auditing pytokens (0.4.1)
�[2K�[32m|�[0m Collecting PyYAML (6.0.3)
�[2K�[32m|�[0m Collecting PyYAML (6.0.3)
�[2K�[32m|�[0m Auditing PyYAML (6.0.3)
�[2K�[32m|�[0m Collecting readme_renderer (44.0)
�[2K�[32m|�[0m Auditing readme_renderer (44.0)
�[2K�[32m|�[0m Collecting regex (2026.3.32)
�[2K�[32m|�[0m Auditing regex (2026.3.32)
�[2K�[32m|�[0m Collecting requests (2.33.1)
�[2K�[32m|�[0m Auditing requests (2.33.1)
�[2K�[32m|�[0m Collecting requests-toolbelt (1.0.0)
�[2K�[32m|�[0m Auditing requests-toolbelt (1.0.0)
�[2K�[32m|�[0m Collecting rfc3986 (2.0.0)
�[2K�[32m|�[0m Auditing rfc3986 (2.0.0)
�[2K�[32m|�[0m Collecting rich (14.3.3)
�[2K�[32m|�[0m Auditing rich (14.3.3)
�[2K�[32m|�[0m Collecting ruamel.yaml (0.19.1)
�[2K�[32m|�[0m Auditing ruamel.yaml (0.19.1)
�[2K�[32m|�[0m Collecting ruff (0.15.8)
�[2K�[32m|�[0m Auditing ruff (0.15.8)
�[2K�[32m|�[0m Collecting safety (3.7.0)
�[2K�[32m|�[0m Auditing safety (3.7.0)
�[2K�[32m|�[0m Collecting safety-schemas (0.0.16)
�[2K�[32m|�[0m Auditing safety-schemas (0.0.16)
�[2K�[32m|�[0m Collecting SecretStorage (3.5.0)
�[2K�[32m|�[0m Auditing SecretStorage (3.5.0)
�[2K�[32m|�[0m Collecting setuptools (82.0.1)
�[2K�[32m|�[0m Auditing setuptools (82.0.1)
�[2K�[32m|�[0m Collecting shellingham (1.5.4)
�[2K�[32m|�[0m Auditing shellingham (1.5.4)
�[2K�[32m|�[0m Collecting sortedcontainers (2.4.0)
�[2K�[32m|�[0m Auditing sortedcontainers (2.4.0)
�[2K�[32m|�[0m Collecting stevedore (5.7.0)
�[2K�[32m|�[0m Auditing stevedore (5.7.0)
�[2K�[32m|�[0m Collecting tabulate (0.10.0)
�[2K�[32m|�[0m Auditing tabulate (0.10.0)
�[2K�[32m|�[0m Collecting tenacity (9.1.4)
�[2K�[32m|�[0m Auditing tenacity (9.1.4)
�[2K�[32m|�[0m Collecting tomli (2.4.1)
�[2K�[32m|�[0m Auditing tomli (2.4.1)
�[2K�[32m|�[0m Collecting tomli_w (1.2.0)
�[2K�[32m|�[0m Auditing tomli_w (1.2.0)
�[2K�[32m|�[0m Collecting tomlkit (0.14.0)
�[2K�[32m|�[0m Auditing tomlkit (0.14.0)
�[2K�[32m|�[0m Collecting tqdm (4.67.3)
�[2K�[32m|�[0m Auditing tqdm (4.67.3)
�[2K�[32m|�[0m Collecting twine (6.2.0)
�[2K�[32m|�[0m Auditing twine (6.2.0)
�[2K�[32m|�[0m Collecting typer (0.24.1)
�[2K�[32m|�[0m Auditing typer (0.24.1)
�[2K�[32m|�[0m Collecting types-PyYAML (6.0.12.20250915)
�[2K�[32m|�[0m Auditing types-PyYAML (6.0.12.20250915)
�[2K�[32m|�[0m Collecting typing_extensions (4.15.0)
�[2K�[32m|�[0m Auditing typing_extensions (4.15.0)
�[2K�[32m|�[0m Collecting typing-inspection (0.4.2)
�[2K�[32m|�[0m Auditing typing-inspection (0.4.2)
�[2K�[32m|�[0m Collecting urllib3 (2.6.3)
�[2K�[32m|�[0m Auditing urllib3 (2.6.3)
�[2K�[32m|�[0m Collecting wheel (0.46.3)
�[2K�[32m|�[0m Auditing wheel (0.46.3)
�[2K�[32m|�[0m Collecting yarl (1.23.0)
�[2K�[32m|�[0m Collecting yarl (1.23.0)
�[2K�[32m|�[0m Auditing yarl (1.23.0)
�[2K�[32m|�[0m Auditing yarl (1.23.0)
�[?25h
�[1A�[2K```

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • Several test classes (e.g., TestDisplayBrewList, TestHandleExportIfRequested, TestGetHomebrewCasksHandler, TestSendNotificationIfAvailable) repeatedly patch create_progress_bar to a very similar mock; consider extracting a shared fixture/helper to reduce duplication and keep the behaviour consistent across tests.
  • The TestLogDebugInfo.test_debug_logs_items assertion on mock_log.debug.call_count >= 6 is quite coupled to the current implementation details; tightening this to assert on specific messages or using smaller, focused assertions would make the test less brittle to harmless logging changes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Several test classes (e.g., TestDisplayBrewList, TestHandleExportIfRequested, TestGetHomebrewCasksHandler, TestSendNotificationIfAvailable) repeatedly patch `create_progress_bar` to a very similar mock; consider extracting a shared fixture/helper to reduce duplication and keep the behaviour consistent across tests.
- The `TestLogDebugInfo.test_debug_logs_items` assertion on `mock_log.debug.call_count >= 6` is quite coupled to the current implementation details; tightening this to assert on specific messages or using smaller, focused assertions would make the test less brittle to harmless logging changes.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 31, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…fe stdout pollution

- Fix test_concurrent_operations: remove patch("builtins.print") from threads
  (not thread-safe; racing patches permanently replace builtins.print with
  MagicMock, silencing all subsequent capsys captures). Also add export_format=None
  and output_file=None to prevent open(MagicMock()) from closing fd 1 (stdout).
- Unskip 12 previously-skipped tests in test_ui.py: replace monkeypatch.setattr
  with patch() context managers for stable HAS_TERMCOLOR overrides.
- Add TestSuppressConsoleWarningsInternals (3 tests) to test_utils_handlers.py
  covering WarningFilter branches.
- Add TestHandleInitializeConfigBranches and TestHandleSetupLoggingErrorRecovery
  to test_setup_handlers.py.
- Add TestSendNotificationIfAvailable (5 tests) to test_outdated_handlers.py.
- Add 6 new test classes to test_brew_handlers_coverage.py covering
  _display_brew_list, _handle_export_if_requested, _get_homebrew_casks,
  _log_debug_info, and _determine_strict_mode branches.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@docdyhr docdyhr force-pushed the test/quality-and-coverage-85pct branch from 7af37f5 to 6e04208 Compare April 1, 2026 11:15
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 1, 2026

🔒 Security Analysis Report

Security Analysis Report

Generated: Wed Apr 1 11:16:40 UTC 2026
Repository: docdyhr/versiontracker
Commit: ef7cdb4

Bandit Security Scan

�[?25l
�[2KWorking... �[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m  0%�[0m �[36m-:--:--�[0m
�[2KWorking... �[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m  0%�[0m �[36m-:--:--�[0m
�[2KWorking... �[91m━━━━�[0m�[90m╺�[0m�[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m 11%�[0m �[36m0:00:02�[0m
�[2KWorking... �[91m━━━━━━━━�[0m�[91m╸�[0m�[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m 22%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━�[0m�[91m╸�[0m�[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m 31%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━━━�[0m�[90m╺�[0m�[90m━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m 35%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━━━━━━━━�[0m�[90m╺�[0m�[90m━━━━━━━━━━━━━━━━━━━━�[0m �[35m 48%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━━━━━━━━━━━━�[0m�[91m╸�[0m�[90m━━━━━━━━━━━━━━━━�[0m �[35m 59%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m�[90m╺�[0m�[90m━━━━━━━━━━━�[0m �[35m 70%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m�[90m╺�[0m�[90m━━━━━━━━━�[0m �[35m 76%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m�[90m╺�[0m�[90m━━━━━━�[0m �[35m 83%�[0m �[36m0:00:01�[0m
�[2KWorking... �[91m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m�[91m╸�[0m�[90m━━━━�[0m �[35m 89%�[0m �[36m0:00:01�[0m
�[2KWorking... �[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m100%�[0m �[33m0:00:01�[0m
�[2KWorking... �[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━�[0m �[35m100%�[0m �[33m0:00:01�[0m
�[?25hRun started:2026-04-01 11:16:42.377842+00:00

Test results:
>> 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.4/plugins/b608_hardcoded_sql_expressions.html
   Location: versiontracker/advanced_cache.py:610:24
609	                # Use f-string for better readability
610	                msg = f"Failed to delete from cache {key}: {e}"
611	                raise CacheError(msg) from e

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/config.py:174:16
173	                cmd = f"{path} --version"
174	                import subprocess
175	

--------------------------------------------------
>> 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.4/plugins/b603_subprocess_without_shell_equals_true.html
   Location: versiontracker/config.py:177:29
176	                try:
177	                    result = subprocess.run(cmd.split(), capture_output=True, timeout=2, check=False)
178	                    returncode = result.returncode

--------------------------------------------------
>> 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.4/plugins/b110_try_except_pass.html
   Location: versiontracker/experimental/analytics.py:645:16
644	                    self.peak_cpu = max(self.peak_cpu, cpu_percent)
645	                except Exception:
646	                    pass
647	                time.sleep(0.05)

--------------------------------------------------
>> 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.4/plugins/b101_assert_used.html
   Location: versiontracker/handlers/outdated_handlers.py:493:8
492	        # Type assertion: apps and brews cannot be None here due to exit_code checks above
493	        assert apps is not None
494	        assert brews 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.4/plugins/b101_assert_used.html
   Location: versiontracker/handlers/outdated_handlers.py:494:8
493	        assert apps is not None
494	        assert brews is not None
495	        apps = _filter_applications(apps, brews, include_brews)

--------------------------------------------------
>> 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.4/plugins/b101_assert_used.html
   Location: versiontracker/handlers/outdated_handlers.py:511:8
510	        # Type assertion: outdated_info cannot be None here due to exit_code check
511	        assert outdated_info is not None
512	        # Type cast: outdated_info cannot be None here due to exit_code check above

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/homebrew.py:12:0
11	import re
12	import subprocess
13	import time

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/macos_integration.py:11:0
10	import os
11	import subprocess
12	from pathlib import Path

--------------------------------------------------
>> 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.4/plugins/b603_subprocess_without_shell_equals_true.html
   Location: versiontracker/macos_integration.py:245:21
244	            # nosec B603 - osascript with controlled arguments
245	            result = subprocess.run(cmd, capture_output=True, text=True)
246	

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/menubar_app.py:8:0
7	import logging
8	import subprocess
9	import sys

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/plugins/example_plugins.py:322:16
321	            try:
322	                import subprocess
323	

--------------------------------------------------
>> Issue: [B607:start_process_with_partial_path] Starting a process with a partial executable path
   Severity: Low   Confidence: High
   CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b607_start_process_with_partial_path.html
   Location: versiontracker/plugins/example_plugins.py:324:25
323	
324	                result = subprocess.run(["brew", "--version"], capture_output=True, text=True, timeout=5)
325	                if result.returncode == 0:

--------------------------------------------------
>> 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.4/plugins/b603_subprocess_without_shell_equals_true.html
   Location: versiontracker/plugins/example_plugins.py:324:25
323	
324	                result = subprocess.run(["brew", "--version"], capture_output=True, text=True, timeout=5)
325	                if result.returncode == 0:

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/utils.py:15:0
14	import shutil
15	import subprocess
16	import sys

--------------------------------------------------
>> Issue: [B607:start_process_with_partial_path] Starting a process with a partial executable path
   Severity: Low   Confidence: High
   CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b607_start_process_with_partial_path.html
   Location: versiontracker/utils.py:784:17
783	    try:
784	        result = subprocess.run(["which", "brew"], capture_output=True, text=True, timeout=5)
785	        return result.returncode == 0

--------------------------------------------------
>> 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.4/plugins/b603_subprocess_without_shell_equals_true.html
   Location: versiontracker/utils.py:784:17
783	    try:
784	        result = subprocess.run(["which", "brew"], capture_output=True, text=True, timeout=5)
785	        return result.returncode == 0

--------------------------------------------------
>> Issue: [B607:start_process_with_partial_path] Starting a process with a partial executable path
   Severity: Low   Confidence: High
   CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b607_start_process_with_partial_path.html
   Location: versiontracker/utils.py:800:17
799	    try:
800	        result = subprocess.run(["brew", "--prefix"], capture_output=True, text=True, timeout=5)
801	        if result.returncode == 0:

--------------------------------------------------
>> 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.4/plugins/b603_subprocess_without_shell_equals_true.html
   Location: versiontracker/utils.py:800:17
799	    try:
800	        result = subprocess.run(["brew", "--prefix"], capture_output=True, text=True, timeout=5)
801	        if result.returncode == 0:

--------------------------------------------------
>> 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.4/plugins/b603_subprocess_without_shell_equals_true.html
   Location: versiontracker/utils.py:833:15
832	    try:
833	        return subprocess.run(command, capture_output=True, text=True, timeout=timeout, check=check)
834	    except subprocess.TimeoutExpired as e:

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/version/batch.py:11:0
10	import logging
11	import subprocess
12	from concurrent.futures import ThreadPoolExecutor

--------------------------------------------------
>> 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.4/blacklists/blacklist_imports.html#b404-import-subprocess
   Location: versiontracker/version/homebrew.py:18:0
17	import logging
18	import subprocess
19	

--------------------------------------------------

Code scanned:
	Total lines of code: 15020
	Total lines skipped (#nosec): 0
	Total potential issues skipped due to specifically being disabled (e.g., #nosec BXXX): 33

Run metrics:
	Total issues (by severity):
		Undefined: 0
		Low: 21
		Medium: 1
		High: 0
	Total issues (by confidence):
		Undefined: 0
		Low: 1
		Medium: 0
		High: 21
Files skipped (0):

Safety Check Results



�[33m�[1m+===========================================================================================================================================================================================+�[0m


�[31m�[1mDEPRECATED: �[0m�[33m�[1mthis command (`check`) has been DEPRECATED, and will be unsupported beyond 01 June 2024.�[0m


�[32mWe highly encourage switching to the new �[0m�[32m�[1m`scan`�[0m�[32m command which is easier to use, more powerful, and can be set up to mimic the deprecated command if required.�[0m


�[33m�[1m+===========================================================================================================================================================================================+�[0m


+==============================================================================+

                               /$$$$$$            /$$
                              /$$__  $$          | $$
           /$$$$$$$  /$$$$$$ | $$  \__//$$$$$$  /$$$$$$   /$$   /$$
          /$$_____/ |____  $$| $$$$   /$$__  $$|_  $$_/  | $$  | $$
         |  $$$$$$   /$$$$$$$| $$_/  | $$$$$$$$  | $$    | $$  | $$
          \____  $$ /$$__  $$| $$    | $$_____/  | $$ /$$| $$  | $$
          /$$$$$$$/|  $$$$$$$| $$    |  $$$$$$$  |  $$$$/|  $$$$$$$
         |_______/  \_______/|__/     \_______/   \___/   \____  $$
                                                          /$$  | $$
                                                         |  $$$$$$/
  by safetycli.com                                        \______/

+==============================================================================+

 �[1mREPORT�[0m 

  Safety �[1mv3.7.0�[0m is scanning for �[1mVulnerabilities�[0m�[1m...�[0m
�[1m  Scanning dependencies�[0m in your �[1menvironment:�[0m

  -> /opt/hostedtoolcache/Python/3.13.12/x64/lib/python3.13/site-packages

  Using �[1mopen-source vulnerability database�[0m
�[1m  Found and scanned 106 packages�[0m
  Timestamp �[1m2026-04-01 11:16:43�[0m
�[1m  0�[0m�[1m vulnerabilities reported�[0m
�[1m  0�[0m�[1m vulnerabilities ignored�[0m
+==============================================================================+

 �[32m�[1mNo known security vulnerabilities reported.�[0m 

+==============================================================================+�[0m


�[33m�[1m+===========================================================================================================================================================================================+�[0m


�[31m�[1mDEPRECATED: �[0m�[33m�[1mthis command (`check`) has been DEPRECATED, and will be unsupported beyond 01 June 2024.�[0m


�[32mWe highly encourage switching to the new �[0m�[32m�[1m`scan`�[0m�[32m command which is easier to use, more powerful, and can be set up to mimic the deprecated command if required.�[0m


�[33m�[1m+===========================================================================================================================================================================================+�[0m


Pip-Audit Results

�[?25l�[32m-�[0m Collecting inputs
�[2K�[32m-�[0m Collecting inputs
�[2K�[32m-�[0m Collecting inputs
�[2K�[32m-�[0m Collecting inputs
�[2K�[32m\�[0m Collecting inputs
�[2K�[32m\�[0m Collecting inputs
�[2K�[32m\�[0m Collecting inputs
�[2K�[32m\�[0m Collecting aiohappyeyeballs (2.6.1)
�[2K�[32m\�[0m Collecting aiohappyeyeballs (2.6.1)
�[2K�[32m\�[0m Auditing aiohappyeyeballs (2.6.1)
�[2K�[32m\�[0m Collecting aiohttp (3.13.5)
�[2K�[32m\�[0m Auditing aiohttp (3.13.5)
�[2K�[32m\�[0m Collecting aiosignal (1.4.0)
�[2K�[32m\�[0m Auditing aiosignal (1.4.0)
�[2K�[32m\�[0m Collecting annotated-doc (0.0.4)
�[2K�[32m\�[0m Auditing annotated-doc (0.0.4)
�[2K�[32m\�[0m Collecting annotated-types (0.7.0)
�[2K�[32m\�[0m Auditing annotated-types (0.7.0)
�[2K�[32m\�[0m Collecting anyio (4.13.0)
�[2K�[32m\�[0m Auditing anyio (4.13.0)
�[2K�[32m\�[0m Collecting attrs (26.1.0)
�[2K�[32m\�[0m Auditing attrs (26.1.0)
�[2K�[32m\�[0m Collecting Authlib (1.6.9)
�[2K�[32m\�[0m Auditing Authlib (1.6.9)
�[2K�[32m\�[0m Collecting bandit (1.9.4)
�[2K�[32m\�[0m Auditing bandit (1.9.4)
�[2K�[32m\�[0m Collecting black (26.3.1)
�[2K�[32m\�[0m Auditing black (26.3.1)
�[2K�[32m\�[0m Collecting boolean.py (5.0)
�[2K�[32m\�[0m Auditing boolean.py (5.0)
�[2K�[32m\�[0m Collecting build (1.4.2)
�[2K�[32m\�[0m Auditing build (1.4.2)
�[2K�[32m\�[0m Collecting CacheControl (0.14.4)
�[2K�[32m\�[0m Auditing CacheControl (0.14.4)
�[2K�[32m\�[0m Collecting certifi (2026.2.25)
�[2K�[32m\�[0m Auditing certifi (2026.2.25)
�[2K�[32m\�[0m Collecting cffi (2.0.0)
�[2K�[32m\�[0m Auditing cffi (2.0.0)
�[2K�[32m\�[0m Collecting charset-normalizer (3.4.6)
�[2K�[32m|�[0m Auditing charset-normalizer (3.4.6)
�[2K�[32m|�[0m Collecting click (8.3.1)
�[2K�[32m|�[0m Auditing click (8.3.1)
�[2K�[32m|�[0m Collecting coverage (7.13.5)
�[2K�[32m|�[0m Auditing coverage (7.13.5)
�[2K�[32m|�[0m Collecting cryptography (46.0.6)
�[2K�[32m|�[0m Auditing cryptography (46.0.6)
�[2K�[32m|�[0m Collecting cyclonedx-python-lib (11.7.0)
�[2K�[32m|�[0m Auditing cyclonedx-python-lib (11.7.0)
�[2K�[32m|�[0m Collecting defusedxml (0.7.1)
�[2K�[32m|�[0m Auditing defusedxml (0.7.1)
�[2K�[32m|�[0m Collecting docutils (0.22.4)
�[2K�[32m|�[0m Auditing docutils (0.22.4)
�[2K�[32m|�[0m Collecting dparse (0.6.4)
�[2K�[32m|�[0m Auditing dparse (0.6.4)
�[2K�[32m|�[0m Collecting filelock (3.25.2)
�[2K�[32m|�[0m Collecting filelock (3.25.2)
�[2K�[32m|�[0m Auditing filelock (3.25.2)
�[2K�[32m|�[0m Collecting frozenlist (1.8.0)
�[2K�[32m|�[0m Auditing frozenlist (1.8.0)
�[2K�[32m|�[0m Collecting h11 (0.16.0)
�[2K�[32m|�[0m Auditing h11 (0.16.0)
�[2K�[32m|�[0m Collecting httpcore (1.0.9)
�[2K�[32m|�[0m Auditing httpcore (1.0.9)
�[2K�[32m|�[0m Collecting httpx (0.28.1)
�[2K�[32m|�[0m Auditing httpx (0.28.1)
�[2K�[32m|�[0m Collecting id (1.6.1)
�[2K�[32m|�[0m Auditing id (1.6.1)
�[2K�[32m|�[0m Collecting idna (3.11)
�[2K�[32m|�[0m Auditing idna (3.11)
�[2K�[32m|�[0m Collecting iniconfig (2.3.0)
�[2K�[32m|�[0m Auditing iniconfig (2.3.0)
�[2K�[32m|�[0m Collecting jaraco.classes (3.4.0)
�[2K�[32m|�[0m Auditing jaraco.classes (3.4.0)
�[2K�[32m|�[0m Collecting jaraco.context (6.1.2)
�[2K�[32m|�[0m Auditing jaraco.context (6.1.2)
�[2K�[32m|�[0m Collecting jaraco.functools (4.4.0)
�[2K�[32m|�[0m Auditing jaraco.functools (4.4.0)
�[2K�[32m|�[0m Collecting jeepney (0.9.0)
�[2K�[32m|�[0m Auditing jeepney (0.9.0)
�[2K�[32m|�[0m Collecting Jinja2 (3.1.6)
�[2K�[32m|�[0m Auditing Jinja2 (3.1.6)
�[2K�[32m|�[0m Collecting joblib (1.5.3)
�[2K�[32m|�[0m Auditing joblib (1.5.3)
�[2K�[32m|�[0m Collecting keyring (25.7.0)
�[2K�[32m|�[0m Auditing keyring (25.7.0)
�[2K�[32m|�[0m Collecting librt (0.8.1)
�[2K�[32m|�[0m Auditing librt (0.8.1)
�[2K�[32m|�[0m Collecting license-expression (30.4.4)
�[2K�[32m|�[0m Auditing license-expression (30.4.4)
�[2K�[32m|�[0m Collecting macversiontracker (1.0.0)
�[2K�[32m|�[0m Collecting macversiontracker (1.0.0)
�[2K�[32m|�[0m Skipping macversiontracker: Dependency not found on PyPI and could not be 
audited: macversiontracker (1.0.0)
�[2K�[1A�[2K�[32m|�[0m Collecting markdown-it-py (4.0.0)
�[2K�[32m|�[0m Auditing markdown-it-py (4.0.0)
�[2K�[32m|�[0m Collecting MarkupSafe (3.0.3)
�[2K�[32m|�[0m Auditing MarkupSafe (3.0.3)
�[2K�[32m|�[0m Collecting marshmallow (4.2.3)
�[2K�[32m|�[0m Auditing marshmallow (4.2.3)
�[2K�[32m|�[0m Collecting mdurl (0.1.2)
�[2K�[32m|�[0m Auditing mdurl (0.1.2)
�[2K�[32m|�[0m Collecting more-itertools (10.8.0)
�[2K�[32m|�[0m Auditing more-itertools (10.8.0)
�[2K�[32m|�[0m Collecting msgpack (1.1.2)
�[2K�[32m|�[0m Auditing msgpack (1.1.2)
�[2K�[32m|�[0m Collecting multidict (6.7.1)
�[2K�[32m|�[0m Auditing multidict (6.7.1)
�[2K�[32m|�[0m Collecting mypy (1.20.0)
�[2K�[32m|�[0m Auditing mypy (1.20.0)
�[2K�[32m|�[0m Collecting mypy_extensions (1.1.0)
�[2K�[32m|�[0m Auditing mypy_extensions (1.1.0)
�[2K�[32m|�[0m Collecting nh3 (0.3.4)
�[2K�[32m|�[0m Collecting nh3 (0.3.4)
�[2K�[32m|�[0m Auditing nh3 (0.3.4)
�[2K�[32m|�[0m Collecting nltk (3.9.4)
�[2K�[32m|�[0m Auditing nltk (3.9.4)
�[2K�[32m|�[0m Collecting packageurl-python (0.17.6)
�[2K�[32m|�[0m Auditing packageurl-python (0.17.6)
�[2K�[32m|�[0m Collecting packaging (26.0)
�[2K�[32m|�[0m Auditing packaging (26.0)
�[2K�[32m|�[0m Collecting pathspec (1.0.4)
�[2K�[32m|�[0m Auditing pathspec (1.0.4)
�[2K�[32m|�[0m Collecting pip (26.0.1)
�[2K�[32m|�[0m Auditing pip (26.0.1)
�[2K�[32m|�[0m Collecting pip-api (0.0.34)
�[2K�[32m|�[0m Auditing pip-api (0.0.34)
�[2K�[32m|�[0m Collecting pip_audit (2.10.0)
�[2K�[32m|�[0m Auditing pip_audit (2.10.0)
�[2K�[32m|�[0m Collecting pip-requirements-parser (32.0.1)
�[2K�[32m|�[0m Auditing pip-requirements-parser (32.0.1)
�[2K�[32m|�[0m Collecting platformdirs (4.9.4)
�[2K�[32m|�[0m Auditing platformdirs (4.9.4)
�[2K�[32m|�[0m Collecting pluggy (1.6.0)
�[2K�[32m|�[0m Auditing pluggy (1.6.0)
�[2K�[32m|�[0m Collecting propcache (0.4.1)
�[2K�[32m|�[0m Auditing propcache (0.4.1)
�[2K�[32m|�[0m Collecting psutil (7.2.2)
�[2K�[32m|�[0m Auditing psutil (7.2.2)
�[2K�[32m|�[0m Collecting py-serializable (2.1.0)
�[2K�[32m|�[0m Auditing py-serializable (2.1.0)
�[2K�[32m|�[0m Collecting pycparser (3.0)
�[2K�[32m|�[0m Auditing pycparser (3.0)
�[2K�[32m|�[0m Collecting pydantic (2.12.5)
�[2K�[32m|�[0m Auditing pydantic (2.12.5)
�[2K�[32m|�[0m Collecting pydantic_core (2.41.5)
�[2K�[32m|�[0m Auditing pydantic_core (2.41.5)
�[2K�[32m|�[0m Collecting Pygments (2.20.0)
�[2K�[32m|�[0m Auditing Pygments (2.20.0)
�[2K�[32m|�[0m Collecting pyparsing (3.3.2)
�[2K�[32m|�[0m Auditing pyparsing (3.3.2)
�[2K�[32m|�[0m Collecting pyproject_hooks (1.2.0)
�[2K�[32m|�[0m Auditing pyproject_hooks (1.2.0)
�[2K�[32m|�[0m Collecting pytest (9.0.2)
�[2K�[32m|�[0m Auditing pytest (9.0.2)
�[2K�[32m|�[0m Collecting pytest-asyncio (1.3.0)
�[2K�[32m|�[0m Auditing pytest-asyncio (1.3.0)
�[2K�[32m|�[0m Collecting pytest-cov (7.1.0)
�[2K�[32m|�[0m Auditing pytest-cov (7.1.0)
�[2K�[32m|�[0m Collecting pytest-mock (3.15.1)
�[2K�[32m|�[0m Auditing pytest-mock (3.15.1)
�[2K�[32m|�[0m Collecting pytest-timeout (2.4.0)
�[2K�[32m|�[0m Auditing pytest-timeout (2.4.0)
�[2K�[32m|�[0m Collecting pytokens (0.4.1)
�[2K�[32m|�[0m Auditing pytokens (0.4.1)
�[2K�[32m|�[0m Collecting PyYAML (6.0.3)
�[2K�[32m|�[0m Collecting PyYAML (6.0.3)
�[2K�[32m|�[0m Auditing PyYAML (6.0.3)
�[2K�[32m|�[0m Collecting readme_renderer (44.0)
�[2K�[32m|�[0m Auditing readme_renderer (44.0)
�[2K�[32m|�[0m Collecting regex (2026.3.32)
�[2K�[32m|�[0m Auditing regex (2026.3.32)
�[2K�[32m|�[0m Collecting requests (2.33.1)
�[2K�[32m|�[0m Auditing requests (2.33.1)
�[2K�[32m|�[0m Collecting requests-toolbelt (1.0.0)
�[2K�[32m|�[0m Auditing requests-toolbelt (1.0.0)
�[2K�[32m|�[0m Collecting rfc3986 (2.0.0)
�[2K�[32m|�[0m Auditing rfc3986 (2.0.0)
�[2K�[32m|�[0m Collecting rich (14.3.3)
�[2K�[32m|�[0m Auditing rich (14.3.3)
�[2K�[32m|�[0m Collecting ruamel.yaml (0.19.1)
�[2K�[32m|�[0m Auditing ruamel.yaml (0.19.1)
�[2K�[32m|�[0m Collecting ruff (0.15.8)
�[2K�[32m|�[0m Auditing ruff (0.15.8)
�[2K�[32m|�[0m Collecting safety (3.7.0)
�[2K�[32m|�[0m Auditing safety (3.7.0)
�[2K�[32m|�[0m Collecting safety-schemas (0.0.16)
�[2K�[32m|�[0m Auditing safety-schemas (0.0.16)
�[2K�[32m|�[0m Collecting SecretStorage (3.5.0)
�[2K�[32m|�[0m Auditing SecretStorage (3.5.0)
�[2K�[32m|�[0m Collecting setuptools (82.0.1)
�[2K�[32m|�[0m Auditing setuptools (82.0.1)
�[2K�[32m|�[0m Collecting shellingham (1.5.4)
�[2K�[32m/�[0m Auditing shellingham (1.5.4)
�[2K�[32m/�[0m Collecting sortedcontainers (2.4.0)
�[2K�[32m/�[0m Auditing sortedcontainers (2.4.0)
�[2K�[32m/�[0m Collecting stevedore (5.7.0)
�[2K�[32m/�[0m Auditing stevedore (5.7.0)
�[2K�[32m/�[0m Collecting tabulate (0.10.0)
�[2K�[32m/�[0m Auditing tabulate (0.10.0)
�[2K�[32m/�[0m Collecting tenacity (9.1.4)
�[2K�[32m/�[0m Auditing tenacity (9.1.4)
�[2K�[32m/�[0m Collecting tomli (2.4.1)
�[2K�[32m/�[0m Auditing tomli (2.4.1)
�[2K�[32m/�[0m Collecting tomli_w (1.2.0)
�[2K�[32m/�[0m Auditing tomli_w (1.2.0)
�[2K�[32m/�[0m Collecting tomlkit (0.14.0)
�[2K�[32m/�[0m Auditing tomlkit (0.14.0)
�[2K�[32m/�[0m Collecting tqdm (4.67.3)
�[2K�[32m/�[0m Auditing tqdm (4.67.3)
�[2K�[32m/�[0m Collecting twine (6.2.0)
�[2K�[32m/�[0m Auditing twine (6.2.0)
�[2K�[32m/�[0m Collecting typer (0.24.1)
�[2K�[32m/�[0m Auditing typer (0.24.1)
�[2K�[32m/�[0m Collecting types-PyYAML (6.0.12.20250915)
�[2K�[32m/�[0m Auditing types-PyYAML (6.0.12.20250915)
�[2K�[32m/�[0m Collecting typing_extensions (4.15.0)
�[2K�[32m/�[0m Auditing typing_extensions (4.15.0)
�[2K�[32m/�[0m Collecting typing-inspection (0.4.2)
�[2K�[32m/�[0m Collecting typing-inspection (0.4.2)
�[2K�[32m/�[0m Auditing typing-inspection (0.4.2)
�[2K�[32m/�[0m Collecting urllib3 (2.6.3)
�[2K�[32m/�[0m Auditing urllib3 (2.6.3)
�[2K�[32m/�[0m Collecting wheel (0.46.3)
�[2K�[32m/�[0m Auditing wheel (0.46.3)
�[2K�[32m/�[0m Collecting yarl (1.23.0)
�[2K�[32m/�[0m Auditing yarl (1.23.0)
�[2K�[32m/�[0m Auditing yarl (1.23.0)
�[?25h
�[1A�[2KName              Skip Reason
----------------- --------------------------------------------------------------------------------
macversiontracker Dependency not found on PyPI and could not be audited: macversiontracker (1.0.0)

@docdyhr docdyhr merged commit e7807ba into master Apr 1, 2026
28 checks passed
@docdyhr docdyhr deleted the test/quality-and-coverage-85pct branch April 1, 2026 11:25
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.

1 participant