summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/core/management/templates.py12
-rw-r--r--django/core/management/utils.py11
-rw-r--r--docs/ref/django-admin.txt18
3 files changed, 35 insertions, 6 deletions
diff --git a/django/core/management/templates.py b/django/core/management/templates.py
index e06e6a6307..71ee0a6ce8 100644
--- a/django/core/management/templates.py
+++ b/django/core/management/templates.py
@@ -11,7 +11,11 @@ from urllib.request import build_opener
import django
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
-from django.core.management.utils import handle_extensions, run_formatters
+from django.core.management.utils import (
+ find_formatters,
+ handle_extensions,
+ run_formatters,
+)
from django.template import Context, Engine
from django.utils import archive
from django.utils.http import parse_header_parameters
@@ -107,6 +111,10 @@ class TemplateCommand(BaseCommand):
"exist, please create it first." % top_dir
)
+ # Find formatters, which are external executables, before input
+ # from the templates can sneak into the path.
+ formatter_paths = find_formatters()
+
extensions = tuple(handle_extensions(options["extensions"]))
extra_files = []
excluded_directories = [".git", "__pycache__"]
@@ -224,7 +232,7 @@ class TemplateCommand(BaseCommand):
else:
shutil.rmtree(path_to_remove)
- run_formatters(self.written_files)
+ run_formatters(self.written_files, **formatter_paths)
def handle_template(self, template, subdir):
"""
diff --git a/django/core/management/utils.py b/django/core/management/utils.py
index e3e1122409..a308763d9d 100644
--- a/django/core/management/utils.py
+++ b/django/core/management/utils.py
@@ -157,11 +157,18 @@ def is_ignored_path(path, ignore_patterns):
return any(ignore(pattern) for pattern in normalize_path_patterns(ignore_patterns))
-def run_formatters(written_files):
+def find_formatters():
+ return {"black_path": shutil.which("black")}
+
+
+def run_formatters(written_files, black_path=(sentinel := object())):
"""
Run the black formatter on the specified files.
"""
- if black_path := shutil.which("black"):
+ # Use a sentinel rather than None, as which() returns None when not found.
+ if black_path is sentinel:
+ black_path = shutil.which("black")
+ if black_path:
subprocess.run(
[black_path, "--fast", "--", *written_files],
capture_output=True,
diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt
index e27ff96eda..af27e0afb5 100644
--- a/docs/ref/django-admin.txt
+++ b/docs/ref/django-admin.txt
@@ -1362,6 +1362,19 @@ files is:
byte-compile invalid ``*.py`` files, template files ending with ``.py-tpl``
will be renamed to ``.py``.
+.. _trusted_code_warning:
+
+.. warning::
+
+ The contents of custom app (or project) templates should always be
+ audited before use: Such templates define code that will become
+ part of your project, and this means that such code will be trusted
+ as much as any app you install, or code you write yourself.
+ Further, even rendering the templates is, effectively, executing
+ code that was provided as input to the management command. The
+ Django template language may provide wide access into the system,
+ so make sure any custom template you use is worthy of your trust.
+
``startproject``
----------------
@@ -1418,8 +1431,9 @@ The :class:`template context <django.template.Context>` used is:
- ``docs_version`` -- the version of the documentation: ``'dev'`` or ``'1.x'``
- ``django_version`` -- the version of Django, e.g. ``'2.0.3'``
-Please also see the :ref:`rendering warning <render_warning>` as mentioned
-for :djadmin:`startapp`.
+Please also see the :ref:`rendering warning <render_warning>` and
+:ref:`trusted code warning <trusted_code_warning>` as mentioned for
+:djadmin:`startapp`.
``test``
--------