Просмотр исходного кода

Fix safe security findings: hashlib, log injection, broad excepts, bandit suppressions

- Add usedforsecurity=False to MD5 (AMS fingerprint) and SHA1 (git blob
  hash) calls to silence Bandit B303 / CodeQL weak-crypto findings
- Convert ~996 f-string logging calls to parameterized %s-style across
  55 files to prevent log injection (Bandit G201 / CodeQL log-injection)
- Narrow ~199 broad except Exception blocks to specific types:
  OperationalError for DB migrations, OSError for network/file cleanup,
  (OSError, ftplib.error_reply) for FTP, and targeted tuples for
  ZIP/XML/JSON parsing — 36 intentionally left broad (mixed async,
  re-raise patterns)
- Add # nosec comments to 9 known-safe lines (0.0.0.0 virtual printer
  binds, ftplib imports) and exclude backend/tests/ from bandit scan
- Bandit now reports 0 medium/high findings
maziggy 3 месяцев назад
Родитель
Сommit
a0133fb43b

+ 1 - 1
backend/app/main.py

@@ -76,7 +76,7 @@ def _start_error_server(missing_packages: list):
     print(f"\nStarting error server on http://0.0.0.0:{port}")
     print("Visit this URL in your browser to see the error details.\n")
 
-    server = HTTPServer(("0.0.0.0", port), ErrorHandler)
+    server = HTTPServer(("0.0.0.0", port), ErrorHandler)  # nosec B104 - intentional bind-all for container
 
     def shutdown(signum, frame):
         print("\nShutting down error server...")

+ 2 - 2
backend/app/services/bambu_ftp.py

@@ -1,11 +1,11 @@
 import asyncio
-import ftplib
+import ftplib  # nosec B402 - FTP required by Bambu Lab printer protocol
 import logging
 import os
 import socket
 import ssl
 from collections.abc import Awaitable, Callable
-from ftplib import FTP, FTP_TLS
+from ftplib import FTP, FTP_TLS  # nosec B402
 from io import BytesIO
 from pathlib import Path
 from typing import TypeVar

+ 1 - 1
backend/app/services/external_camera.py

@@ -59,7 +59,7 @@ def _sanitize_camera_url(url: str, allowed_schemes: tuple[str, ...] = ("http", "
             "localhost",  # Block localhost to prevent internal service access
             "127.0.0.1",
             "::1",
-            "0.0.0.0",
+            "0.0.0.0",  # nosec B104 - SSRF blocklist, not a bind
         )
         if hostname_lower in blocked_hosts:
             logger.warning("Blocked camera URL targeting restricted host: %s", hostname)

+ 3 - 3
backend/app/services/virtual_printer/ftp_server.py

@@ -217,7 +217,7 @@ class FTPSession:
             # Create data server with TLS - use same context for session reuse
             self.data_server = await asyncio.start_server(
                 self._handle_data_connection,
-                "0.0.0.0",
+                "0.0.0.0",  # nosec B104 - virtual printer proxy
                 self.data_port,
                 ssl=self.ssl_context,
             )
@@ -251,7 +251,7 @@ class FTPSession:
             # Create data server with TLS
             self.data_server = await asyncio.start_server(
                 self._handle_data_connection,
-                "0.0.0.0",
+                "0.0.0.0",  # nosec B104 - virtual printer proxy
                 self.data_port,
                 ssl=self.ssl_context,
             )
@@ -514,7 +514,7 @@ class VirtualPrinterFTPServer:
             # Create server with SSL - TLS handshake happens before any FTP data
             self._server = await asyncio.start_server(
                 self._handle_client,
-                "0.0.0.0",
+                "0.0.0.0",  # nosec B104 - virtual printer proxy
                 self.port,
                 ssl=self._ssl_context,  # This makes it implicit FTPS!
             )

+ 1 - 1
backend/app/services/virtual_printer/mqtt_server.py

@@ -250,7 +250,7 @@ class SimpleMQTTServer:
 
             self._server = await asyncio.start_server(
                 connection_handler,
-                "0.0.0.0",
+                "0.0.0.0",  # nosec B104 - virtual printer proxy
                 self.port,
                 ssl=ssl_context,
             )

+ 1 - 1
backend/app/services/virtual_printer/tcp_proxy.py

@@ -102,7 +102,7 @@ class TLSProxy:
             # Start server with TLS
             self._server = await asyncio.start_server(
                 self._handle_client,
-                "0.0.0.0",
+                "0.0.0.0",  # nosec B104 - virtual printer proxy
                 self.listen_port,
                 ssl=self._server_ssl_context,
             )

+ 1 - 1
test_security.sh

@@ -118,7 +118,7 @@ scan_bandit() {
         echo "SKIP: 'bandit' not found. Install: pip install bandit[sarif]"
         return 2
     fi
-    bandit -r backend/ --severity-level medium 2>&1
+    bandit -r backend/ --severity-level medium -x backend/tests 2>&1
 }
 
 scan_codeql_python() {