Procházet zdrojové kódy

Closes #22654: Redact install paths from debug tracebacks (#22655)

bctiemann před 1 týdnem
rodič
revize
16875c747c

+ 20 - 1
netbox/extras/models/configs.py

@@ -1,3 +1,6 @@
+import os
+import re
+import sys
 import traceback
 
 import jsonschema
@@ -333,7 +336,23 @@ class ConfigTemplate(
         is returned.
         """
         if self.debug:
-            return ''.join(traceback.format_exception(exc))
+            # Strip deployment-specific path prefixes from File "..." lines to avoid disclosing
+            # the server's filesystem layout. install_root covers all NetBox source files plus
+            # any venv co-located inside the repo. When the venv lives outside the repo
+            # (the typical production pattern, e.g. ~/.venv/netbox/), sys.prefix differs from
+            # sys.base_prefix and the venv root is stripped separately so that the deployment
+            # user's home directory is not exposed. Stdlib paths not under either prefix are
+            # left as-is — they reveal only standard OS locations, not deployment structure.
+            install_root = os.path.dirname(settings.BASE_DIR) + os.sep
+            prefixes_to_strip = [install_root]
+            if sys.prefix != sys.base_prefix:
+                venv_root = sys.prefix + os.sep
+                if venv_root != install_root:
+                    prefixes_to_strip.append(venv_root)
+            tb = ''.join(traceback.format_exception(exc))
+            for prefix in prefixes_to_strip:
+                tb = re.sub(r'(File ")' + re.escape(prefix), r'\1', tb)
+            return tb
         if isinstance(exc, TemplateError):
             parts = [f"{type(exc).__name__}: {exc}"]
             if getattr(exc, 'name', None):

+ 29 - 0
netbox/extras/tests/test_models.py

@@ -1,9 +1,12 @@
 import io
+import os
+import sys
 import tempfile
 from pathlib import Path
 from types import SimpleNamespace
 from unittest.mock import patch
 
+from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
 from django.core.files.base import ContentFile
 from django.core.files.storage import Storage
@@ -1200,6 +1203,32 @@ class ConfigTemplateDebugTestCase(TestCase):
         with self.assertRaises(TemplateSyntaxError):
             render_jinja2("{% debug %}", {}, debug=False)
 
+    def test_format_render_error_debug_redacts_install_path(self):
+        """format_render_error() strips the repo install-path prefix from debug tracebacks."""
+        t = ConfigTemplate(name='redact-test', template_code='hello', debug=True)
+        try:
+            raise ValueError("deliberate test error")
+        except ValueError as exc:
+            result = t.format_render_error(exc)
+        install_root = os.path.dirname(settings.BASE_DIR) + os.sep
+        self.assertIn('Traceback', result)
+        self.assertNotIn(install_root, result)
+        # Also verify the venv prefix is stripped when running inside a virtualenv.
+        if sys.prefix != sys.base_prefix:
+            venv_root = sys.prefix + os.sep
+            if venv_root != install_root:
+                self.assertNotIn(venv_root, result)
+
+    def test_format_render_error_non_debug_returns_concise_message(self):
+        """format_render_error() returns a one-line message (no traceback) when debug=False."""
+        t = ConfigTemplate(name='nodebug-test', template_code='hello', debug=False)
+        try:
+            raise TemplateError("bad template")
+        except TemplateError as exc:
+            result = t.format_render_error(exc)
+        self.assertNotIn('Traceback', result)
+        self.assertIn('TemplateError', result)
+
 
 class JinjaEnvFilterTestCase(TestCase):
     """