open-api-framework 0.7.0__tar.gz → 0.8.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/CHANGELOG.rst +27 -0
  2. {open_api_framework-0.7.0/open_api_framework.egg-info → open_api_framework-0.8.0}/PKG-INFO +3 -2
  3. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/README.rst +1 -1
  4. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/conf/base.py +132 -8
  5. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/templates/open_api_framework/env_config.rst +1 -1
  6. {open_api_framework-0.7.0 → open_api_framework-0.8.0/open_api_framework.egg-info}/PKG-INFO +3 -2
  7. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework.egg-info/requires.txt +1 -0
  8. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/pyproject.toml +3 -2
  9. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/LICENSE +0 -0
  10. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/MANIFEST.in +0 -0
  11. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/__init__.py +0 -0
  12. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/apps.py +0 -0
  13. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/conf/__init__.py +0 -0
  14. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/conf/utils.py +0 -0
  15. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/context_processors.py +0 -0
  16. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/management/__init__.py +0 -0
  17. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/management/commands/__init__.py +0 -0
  18. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/management/commands/generate_envvar_docs.py +0 -0
  19. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/py.typed +0 -0
  20. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/static/open_api_framework/css/admin.css +0 -0
  21. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/templates/open_api_framework/admin/base_site.html +0 -0
  22. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/templates/open_api_framework/components/environment.html +0 -0
  23. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/templates/open_api_framework/components/version.html +0 -0
  24. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/templatetags/__init__.py +0 -0
  25. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/templatetags/doc_tags.py +0 -0
  26. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework/templatetags/open_api_framework.py +0 -0
  27. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework.egg-info/SOURCES.txt +0 -0
  28. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework.egg-info/dependency_links.txt +0 -0
  29. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/open_api_framework.egg-info/top_level.txt +0 -0
  30. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/setup.cfg +0 -0
  31. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/tests/test_config_helpers.py +0 -0
  32. {open_api_framework-0.7.0 → open_api_framework-0.8.0}/tests/test_generate_envvar_docs.py +0 -0
@@ -1,6 +1,33 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ 0.8.0 (2024-08-22)
5
+ ------------------
6
+
7
+ **New features**
8
+
9
+ * Add Django CSP with configurable settings
10
+ * Add SECURE_HSTS_SECONDS and CSRF_COOKIE_HTTPONLY settings
11
+
12
+ .. warning::
13
+
14
+ SECURE_HSTS_SECONDS has been added with a default of 31536000 seconds, ensure that
15
+ before upgrading to this version of open-api-framework, your entire application is served
16
+ over HTTPS, otherwise this setting can break parts of your application (see https://docs.djangoproject.com/en/4.2/ref/middleware/#http-strict-transport-security)
17
+
18
+ **Bugfixes/QOL**
19
+
20
+ * Fix rendering for envvar defaults (previously quotes were escaped)
21
+ * Move ``CACHE_DEFAULT``, ``CACHE_AXES``, ``EMAIL_HOST`` envvars to Required group (because they are required for Docker)
22
+ * Add CI job to check if all envvars are either documented or excluded from documentation
23
+
24
+ 0.7.1 (2024-08-16)
25
+ ------------------
26
+
27
+ **Bugfixes**
28
+
29
+ * Add missing help_text for SESSION_COOKIE_SAMESITE and CSRF_COOKIE_SAMESITE envvars
30
+
4
31
  0.7.0 (2024-08-15)
5
32
  ------------------
6
33
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: open_api_framework
3
- Version: 0.7.0
3
+ Version: 0.8.0
4
4
  Summary: A metapackage for registration components, that bundles the dependencies shared between these components and provides generic settings
5
5
  Author-email: Maykin Media <support@maykinmedia.nl>
6
6
  License: Copyright © Maykin 2024
@@ -42,6 +42,7 @@ Requires-Dist: djangorestframework>=3.15.2
42
42
  Requires-Dist: djangorestframework-gis>=1.0
43
43
  Requires-Dist: django-filter>=24.2
44
44
  Requires-Dist: drf-spectacular>=0.27.2
45
+ Requires-Dist: django-csp>=3.8
45
46
  Requires-Dist: djangorestframework-inclusions>=1.2.0
46
47
  Requires-Dist: commonground-api-common>=1.12.1
47
48
  Requires-Dist: mozilla-django-oidc-db>=0.19.0
@@ -77,7 +78,7 @@ Requires-Dist: twine; extra == "release"
77
78
  Open API Framework
78
79
  ==================
79
80
 
80
- :Version: 0.7.0
81
+ :Version: 0.8.0
81
82
  :Source: https://github.com/maykinmedia/open-api-framework
82
83
  :Keywords: metapackage, dependencies
83
84
 
@@ -1,7 +1,7 @@
1
1
  Open API Framework
2
2
  ==================
3
3
 
4
- :Version: 0.7.0
4
+ :Version: 0.8.0
5
5
  :Source: https://github.com/maykinmedia/open-api-framework
6
6
  :Keywords: metapackage, dependencies
7
7
 
@@ -149,12 +149,17 @@ DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
149
149
  CACHE_DEFAULT = config(
150
150
  "CACHE_DEFAULT",
151
151
  "localhost:6379/0",
152
- help_text="redis cache address for the default cache",
152
+ help_text="redis cache address for the default cache (this **MUST** be set when using Docker)",
153
+ group="Required",
153
154
  )
154
155
  CACHE_AXES = config(
155
156
  "CACHE_AXES",
156
157
  "localhost:6379/0",
157
- help_text="redis cache address for the brute force login protection cache",
158
+ help_text=(
159
+ "redis cache address for the brute force login protection cache "
160
+ "(this **MUST** be set when using Docker)"
161
+ ),
162
+ group="Required",
158
163
  )
159
164
 
160
165
  CACHES = {
@@ -203,6 +208,7 @@ INSTALLED_APPS = [
203
208
  # External applications.
204
209
  "axes",
205
210
  "django_filters",
211
+ "csp",
206
212
  "corsheaders",
207
213
  "vng_api_common",
208
214
  "notifications_api_common",
@@ -241,6 +247,7 @@ MIDDLEWARE = [
241
247
  "django.contrib.messages.middleware.MessageMiddleware",
242
248
  "django.middleware.clickjacking.XFrameOptionsMiddleware",
243
249
  "axes.middleware.AxesMiddleware",
250
+ "csp.contrib.rate_limiting.RateLimitedCSPMiddleware",
244
251
  ]
245
252
 
246
253
  ROOT_URLCONF = f"{PROJECT_DIRNAME}.urls"
@@ -305,7 +312,8 @@ FILE_UPLOAD_PERMISSIONS = 0o644
305
312
  EMAIL_HOST = config(
306
313
  "EMAIL_HOST",
307
314
  default="localhost",
308
- help_text="hostname for the outgoing e-mail server",
315
+ help_text="hostname for the outgoing e-mail server (this **MUST** be set when using Docker)",
316
+ group="Required",
309
317
  )
310
318
  EMAIL_PORT = config(
311
319
  "EMAIL_PORT",
@@ -539,10 +547,29 @@ LOGOUT_REDIRECT_URL = reverse_lazy("admin:index")
539
547
  #
540
548
  SESSION_COOKIE_SECURE = IS_HTTPS
541
549
  SESSION_COOKIE_HTTPONLY = True
542
- SESSION_COOKIE_SAMESITE = config("SESSION_COOKIE_SAMESITE", "Strict")
550
+ SESSION_COOKIE_SAMESITE = config(
551
+ "SESSION_COOKIE_SAMESITE",
552
+ "Strict",
553
+ help_text=(
554
+ "The value of the SameSite flag on the session cookie. This flag prevents the "
555
+ "cookie from being sent in cross-site requests thus preventing CSRF attacks and "
556
+ "making some methods of stealing session cookie impossible."
557
+ ),
558
+ )
543
559
 
544
560
  CSRF_COOKIE_SECURE = IS_HTTPS
545
- CSRF_COOKIE_SAMESITE = config("CSRF_COOKIE_SAMESITE", "Strict")
561
+ CSRF_COOKIE_HTTPONLY = True
562
+ CSRF_COOKIE_SAMESITE = config(
563
+ "CSRF_COOKIE_SAMESITE",
564
+ "Strict",
565
+ help_text=(
566
+ "The value of the SameSite flag on the CSRF cookie. This flag prevents the cookie "
567
+ "from being sent in cross-site requests."
568
+ ),
569
+ )
570
+
571
+ if IS_HTTPS:
572
+ SECURE_HSTS_SECONDS = 31536000
546
573
 
547
574
  X_FRAME_OPTIONS = "DENY"
548
575
 
@@ -591,7 +618,7 @@ if subpath:
591
618
  SUBPATH = subpath
592
619
 
593
620
  if "GIT_SHA" in os.environ:
594
- GIT_SHA = config("GIT_SHA", "")
621
+ GIT_SHA = config("GIT_SHA", "", add_to_docs=False)
595
622
  # in docker (build) context, there is no .git directory
596
623
  elif (Path(BASE_DIR) / ".git").exists():
597
624
  try:
@@ -822,7 +849,7 @@ MOZILLA_DJANGO_OIDC_DB_CACHE_TIMEOUT = 5 * 60
822
849
  ELASTIC_APM_SERVER_URL = config(
823
850
  "ELASTIC_APM_SERVER_URL",
824
851
  None,
825
- "URL where Elastic APM is hosted",
852
+ help_text="URL where Elastic APM is hosted",
826
853
  group="Elastic APM",
827
854
  )
828
855
  ELASTIC_APM = {
@@ -840,7 +867,7 @@ ELASTIC_APM = {
840
867
  "SECRET_TOKEN": config(
841
868
  "ELASTIC_APM_SECRET_TOKEN",
842
869
  "default",
843
- "Token used to communicate with Elastic APM",
870
+ help_text="Token used to communicate with Elastic APM",
844
871
  group="Elastic APM",
845
872
  ),
846
873
  "SERVER_URL": ELASTIC_APM_SERVER_URL,
@@ -917,3 +944,100 @@ LOG_OUTGOING_REQUESTS_MAX_AGE = config(
917
944
  default=7,
918
945
  help_text="The amount of time after which request logs should be deleted from the database",
919
946
  ) # number of days
947
+
948
+
949
+ #
950
+ # Django CSP settings
951
+ #
952
+ # explanation of directives: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
953
+ # and how to specify them: https://django-csp.readthedocs.io/en/latest/configuration.html
954
+ #
955
+ # NOTE: make sure values are a tuple or list, and to quote special values like 'self'
956
+
957
+ # ideally we'd use BASE_URI but it'd have to be lazy or cause issues
958
+ CSP_DEFAULT_SRC = [
959
+ "'self'",
960
+ ] + config(
961
+ "CSP_EXTRA_DEFAULT_SRC",
962
+ default=[],
963
+ split=True,
964
+ group="Content Security Policy",
965
+ help_text="Extra default source URLs for CSP other than ``self``. "
966
+ "Used for ``img-src``, ``style-src`` and ``script-src``",
967
+ )
968
+
969
+
970
+ CSP_REPORT_URI = config(
971
+ "CSP_REPORT_URI",
972
+ None,
973
+ group="Content Security Policy",
974
+ help_text="URI of the``report-uri`` directive.",
975
+ )
976
+ CSP_REPORT_PERCENTAGE = config(
977
+ "CSP_REPORT_PERCENTAGE",
978
+ 0,
979
+ group="Content Security Policy",
980
+ help_text="Percentage of requests that get the ``report-uri`` directive.",
981
+ ) # float between 0 and 1
982
+
983
+ CSP_FORM_ACTION = (
984
+ config(
985
+ "CSP_FORM_ACTION",
986
+ default=["\"'self'\""]
987
+ + config(
988
+ "CSP_EXTRA_FORM_ACTION",
989
+ default=[],
990
+ split=True,
991
+ group="Content Security Policy",
992
+ help_text="Add additional ``form-action`` source to the default ",
993
+ ),
994
+ split=True,
995
+ group="Content Security Policy",
996
+ help_text="Override the default ``form-action`` source",
997
+ )
998
+ + CORS_ALLOWED_ORIGINS
999
+ )
1000
+
1001
+ CSP_IMG_SRC = CSP_DEFAULT_SRC + config(
1002
+ "CSP_EXTRA_IMG_SRC",
1003
+ default=[],
1004
+ split=True,
1005
+ group="Content Security Policy",
1006
+ help_text="Extra ``img-src`` sources for CSP other than ``CSP_DEFAULT_SRC``.",
1007
+ )
1008
+
1009
+ # affects <object> and <embed> tags, block everything by default but allow deploy-time
1010
+ # overrides.
1011
+ CSP_OBJECT_SRC = config(
1012
+ "CSP_OBJECT_SRC",
1013
+ default=["\"'none'\""],
1014
+ split=True,
1015
+ group="Content Security Policy",
1016
+ help_text="``object-src`` urls",
1017
+ )
1018
+
1019
+ # we must include this explicitly, otherwise the style-src only includes the nonce because
1020
+ # of CSP_INCLUDE_NONCE_IN
1021
+ CSP_STYLE_SRC = CSP_DEFAULT_SRC
1022
+ CSP_SCRIPT_SRC = CSP_DEFAULT_SRC
1023
+
1024
+ # firefox does not get the nonce from default-src, see
1025
+ # https://stackoverflow.com/a/63376012
1026
+ CSP_INCLUDE_NONCE_IN = ["style-src", "script-src"]
1027
+
1028
+ # directives that don't fallback to default-src
1029
+ CSP_BASE_URI = ["'self'"]
1030
+
1031
+ # Frame directives do not fall back to default-src
1032
+ CSP_FRAME_ANCESTORS = ["'none'"] # equivalent to X-Frame-Options: deny
1033
+ CSP_FRAME_SRC = ["'self'"]
1034
+ # CSP_NAVIGATE_TO = ["'self'"] # this will break all outgoing links etc # too much & tricky, see note on MDN
1035
+ # CSP_SANDBOX # too much
1036
+
1037
+ CSP_UPGRADE_INSECURE_REQUESTS = False # TODO enable on production?
1038
+
1039
+ CSP_EXCLUDE_URL_PREFIXES = (
1040
+ # ReDoc/Swagger pull in external sources, so don't enforce CSP on API endpoints/documentation.
1041
+ "/api/",
1042
+ "/admin/",
1043
+ )
@@ -13,7 +13,7 @@ Available environment variables
13
13
  {{group_name}}
14
14
  {{group_name|repeat_char:"-"}}
15
15
 
16
- {% for var in vars %}* ``{{var.name}}``: {% if var.help_text %}{{var.help_text|safe|ensure_endswith:"."}}{% endif %}{% if var.auto_display_default and not var.default|is_undefined %} Defaults to: ``{{var.default|to_str}}``.{% endif %}
16
+ {% for var in vars %}* ``{{var.name}}``: {% if var.help_text %}{{var.help_text|safe|ensure_endswith:"."}}{% endif %}{% if var.auto_display_default and not var.default|is_undefined %} Defaults to: ``{{var.default|to_str|safe}}``.{% endif %}
17
17
  {% endfor %}
18
18
  {% endfor %}
19
19
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: open_api_framework
3
- Version: 0.7.0
3
+ Version: 0.8.0
4
4
  Summary: A metapackage for registration components, that bundles the dependencies shared between these components and provides generic settings
5
5
  Author-email: Maykin Media <support@maykinmedia.nl>
6
6
  License: Copyright © Maykin 2024
@@ -42,6 +42,7 @@ Requires-Dist: djangorestframework>=3.15.2
42
42
  Requires-Dist: djangorestframework-gis>=1.0
43
43
  Requires-Dist: django-filter>=24.2
44
44
  Requires-Dist: drf-spectacular>=0.27.2
45
+ Requires-Dist: django-csp>=3.8
45
46
  Requires-Dist: djangorestframework-inclusions>=1.2.0
46
47
  Requires-Dist: commonground-api-common>=1.12.1
47
48
  Requires-Dist: mozilla-django-oidc-db>=0.19.0
@@ -77,7 +78,7 @@ Requires-Dist: twine; extra == "release"
77
78
  Open API Framework
78
79
  ==================
79
80
 
80
- :Version: 0.7.0
81
+ :Version: 0.8.0
81
82
  :Source: https://github.com/maykinmedia/open-api-framework
82
83
  :Keywords: metapackage, dependencies
83
84
 
@@ -10,6 +10,7 @@ djangorestframework>=3.15.2
10
10
  djangorestframework-gis>=1.0
11
11
  django-filter>=24.2
12
12
  drf-spectacular>=0.27.2
13
+ django-csp>=3.8
13
14
  djangorestframework-inclusions>=1.2.0
14
15
  commonground-api-common>=1.12.1
15
16
  mozilla-django-oidc-db>=0.19.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "open_api_framework"
7
- version = "0.7.0"
7
+ version = "0.8.0"
8
8
  description = "A metapackage for registration components, that bundles the dependencies shared between these components and provides generic settings"
9
9
  authors = [
10
10
  {name = "Maykin Media", email = "support@maykinmedia.nl"}
@@ -39,6 +39,7 @@ dependencies = [
39
39
  "djangorestframework-gis>=1.0",
40
40
  "django-filter>=24.2",
41
41
  "drf-spectacular>=0.27.2",
42
+ "django-csp>=3.8",
42
43
  "djangorestframework-inclusions>=1.2.0",
43
44
  "commonground-api-common>=1.12.1",
44
45
  "mozilla-django-oidc-db>=0.19.0",
@@ -100,7 +101,7 @@ testpaths = ["tests"]
100
101
  DJANGO_SETTINGS_MODULE = "testapp.settings"
101
102
 
102
103
  [tool.bumpversion]
103
- current_version = "0.7.0"
104
+ current_version = "0.8.0"
104
105
  files = [
105
106
  {filename = "pyproject.toml"},
106
107
  {filename = "README.rst"},