Skip to content

Add .well-known/security.txt file #2062

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions djangoproject/templates/well-known/security.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{% spaceless %}
{% comment %}
This file is served under the well-known URIs

- https://www.djangoproject.com/.well-known/security.txt
- https://docs.djangoproject.com/.well-known/security.txt

See https://securitytxt.org/ for more information about the security.txt standard.
{% endcomment %}
{% endspaceless %}# Hello security researcher!
# We appreciate your help in keeping Django & djangoproject.com secure.

# Please report security issues that concern this website (djangoproject.com)
# to the website working group: [email protected]
# This helps us make sure your report is directed to the right people.
# You can find guidelines for reporting website security issues here: https://github.com/django/djangoproject.com/blob/main/.github/SECURITY.md
Copy link
Member Author

Choose a reason for hiding this comment

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

Note: this url doesn't exist yet. Assumes #2086 is merged.


# DO NOT USE [email protected] FOR ISSUES THAT CONCERN THE WEBSITE.

# If your report concerns Django itself (the Python package, not this website), please follow the Django security reporting process:
Policy: https://www.djangoproject.com/security/
Contact: https://www.djangoproject.com/security/
Expires: 2026-12-31T00:00:00.000Z
Preferred-Languages: en

# If you would like to encrypt your report, you can use the following PGP key:
Encryption: https://keys.openpgp.org/vks/v1/by-fingerprint/AF3516D27D0621171E0CCE25FCB84B8D1D17F80B
35 changes: 35 additions & 0 deletions djangoproject/tests.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import re
import warnings
from datetime import datetime, timedelta
from http import HTTPStatus
from io import StringIO

Expand Down Expand Up @@ -164,3 +167,35 @@ def test_single_h1_per_page(self):
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, "<h1", count=1)


class SecurityTxtTests(TestCase):
"""
Tests for the security.txt file.
"""

def test_security_txt(self):
"""
The security.txt file should be reachable at the expected URL.
"""
response = self.client.get("/.well-known/security.txt")
self.assertEqual(response.status_code, HTTPStatus.OK)
self.assertEqual(response["Content-Type"], "text/plain")

match = re.search(
"^Expires: (.*)$", response.content.decode("utf-8"), flags=re.MULTILINE
)
if match is None:
self.fail("No Expires line found in security.txt")
else:
expires = match[1]

expires_date = datetime.fromisoformat(expires).date()

if expires_date < datetime.now().date() - timedelta(days=15):
warnings.warn(
"The djangoproject/templates/well-known/security.txt file is"
" close to expiring. Please update the 'Expires' line to confirm"
" the contents are still accurate.",
category=UserWarning,
)
7 changes: 7 additions & 0 deletions djangoproject/urls/docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.contrib.sitemaps.views import sitemap
from django.http import HttpResponse
from django.urls import include, path
from django.views.generic import TemplateView

from docs.models import DocumentRelease
from docs.sitemaps import DocsSitemap
Expand Down Expand Up @@ -55,6 +56,12 @@ def __setitem__(key, value):
"google-site-verification: google79eabba6bf6fd6d3.html"
),
),
path(
".well-known/security.txt",
TemplateView.as_view(
template_name="well-known/security.txt", content_type="text/plain"
),
),
# This just exists to make sure we can proof that the error pages work
# under both hostnames.
path("", include("legacy.urls")),
Expand Down
6 changes: 6 additions & 0 deletions djangoproject/urls/www.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@
cache_page(60 * 60 * 6)(sitemap_views.sitemap),
{"sitemaps": sitemaps},
),
path(
".well-known/security.txt",
TemplateView.as_view(
template_name="well-known/security.txt", content_type="text/plain"
),
),
path("weblog/", include("blog.urls")),
path("download/", include("releases.urls")),
path("svntogit/", include("svntogit.urls")),
Expand Down
35 changes: 35 additions & 0 deletions docs/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import re
import warnings
from datetime import datetime, timedelta
from http import HTTPStatus

from django.contrib.sites.models import Site
Expand Down Expand Up @@ -268,3 +271,35 @@ def test_sitemap_404(self):
self.assertEqual(
response.context["exception"], "No sitemap available for section: 'xx'"
)


class SecurityTxtTests(TestCase):
"""
Tests for the security.txt file.
"""

def test_security_txt(self):
"""
The security.txt file should be reachable at the expected URL.
"""
response = self.client.get("/.well-known/security.txt")
self.assertEqual(response.status_code, HTTPStatus.OK)
self.assertEqual(response["Content-Type"], "text/plain")

match = re.search(
"^Expires: (.*)$", response.content.decode("utf-8"), flags=re.MULTILINE
)
if match is None:
self.fail("No Expires line found in security.txt")
else:
expires = match[1]

expires_date = datetime.fromisoformat(expires).date()

if expires_date < datetime.now().date() - timedelta(days=15):
warnings.warn(
"The djangoproject/templates/well-known/security.txt file is"
" close to expiring. Please update the 'Expires' line to confirm"
" the contents are still accurate.",
category=UserWarning,
)