From 1dac512655c38cc21676c2b59b9bd97e723fbe6a Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Wed, 1 May 2024 12:16:44 +0200 Subject: [PATCH 1/9] :pushpin: Pin open-api-framework to git branch --- requirements/base.in | 2 +- requirements/base.txt | 10 +++++++++- requirements/ci.txt | 14 +++++++++++++- requirements/dev.txt | 14 +++++++++++++- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/requirements/base.in b/requirements/base.in index 7bd81885..714850b3 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -1,4 +1,4 @@ -open-api-framework +git+https://github.com/maykinmedia/open-api-framework.git@feature/django-settings # Core python libraries jsonschema diff --git a/requirements/base.txt b/requirements/base.txt index 49d33aca..77b13a0d 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -73,12 +73,14 @@ django==4.2.11 # via # commonground-api-common # django-admin-index + # django-appconf # django-axes # django-cors-headers # django-filter # django-formtools # django-jsonform # django-jsonsuit + # django-log-outgoing-requests # django-markup # django-otp # django-phonenumber-field @@ -105,6 +107,8 @@ django==4.2.11 # zgw-consumers django-admin-index==3.1.1 # via open-api-framework +django-appconf==1.0.6 + # via django-log-outgoing-requests django-axes==6.4.0 # via open-api-framework django-cors-headers==4.3.1 @@ -121,6 +125,8 @@ django-jsonform==2.21.5 # open-api-framework django-jsonsuit==0.5.0 # via -r requirements/base.in +django-log-outgoing-requests==0.6.1 + # via open-api-framework django-markup==1.8.1 # via open-api-framework django-ordered-model==3.7.4 @@ -146,6 +152,7 @@ django-simple-certmanager==2.0.0 django-solo==2.0.0 # via # commonground-api-common + # django-log-outgoing-requests # mozilla-django-oidc-db # notifications-api-common # sharing-configs @@ -230,7 +237,7 @@ mozilla-django-oidc-db==0.14.1 # via open-api-framework notifications-api-common==0.2.2 # via commonground-api-common -open-api-framework==0.2.0 +open_api_framework @ git+https://github.com/maykinmedia/open-api-framework.git@feature/django-settings # via -r requirements/base.in orderedmultidict==1.0.1 # via furl @@ -286,6 +293,7 @@ requests==2.31.0 # ape-pie # commonground-api-common # coreapi + # django-log-outgoing-requests # gemma-zds-client # mozilla-django-oidc # open-api-framework diff --git a/requirements/ci.txt b/requirements/ci.txt index 9ce9678b..4b759b7b 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -117,6 +117,7 @@ django==4.2.11 # -r requirements/base.txt # commonground-api-common # django-admin-index + # django-appconf # django-axes # django-cors-headers # django-filter @@ -124,6 +125,7 @@ django==4.2.11 # django-jenkins # django-jsonform # django-jsonsuit + # django-log-outgoing-requests # django-markup # django-otp # django-phonenumber-field @@ -152,6 +154,10 @@ django-admin-index==3.1.1 # via # -r requirements/base.txt # open-api-framework +django-appconf==1.0.6 + # via + # -r requirements/base.txt + # django-log-outgoing-requests django-axes==6.4.0 # via # -r requirements/base.txt @@ -178,6 +184,10 @@ django-jsonform==2.21.5 # open-api-framework django-jsonsuit==0.5.0 # via -r requirements/base.txt +django-log-outgoing-requests==0.6.1 + # via + # -r requirements/base.txt + # open-api-framework django-markup==1.8.1 # via # -r requirements/base.txt @@ -224,6 +234,7 @@ django-solo==2.0.0 # via # -r requirements/base.txt # commonground-api-common + # django-log-outgoing-requests # mozilla-django-oidc-db # notifications-api-common # sharing-configs @@ -368,7 +379,7 @@ notifications-api-common==0.2.2 # via # -r requirements/base.txt # commonground-api-common -open-api-framework==0.2.0 +open_api_framework @ git+https://github.com/maykinmedia/open-api-framework.git@feature/django-settings # via -r requirements/base.txt orderedmultidict==1.0.1 # via @@ -461,6 +472,7 @@ requests==2.31.0 # ape-pie # commonground-api-common # coreapi + # django-log-outgoing-requests # gemma-zds-client # mozilla-django-oidc # open-api-framework diff --git a/requirements/dev.txt b/requirements/dev.txt index a1868223..bf22f975 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -135,6 +135,7 @@ django==4.2.11 # -r requirements/ci.txt # commonground-api-common # django-admin-index + # django-appconf # django-axes # django-cors-headers # django-debug-toolbar @@ -144,6 +145,7 @@ django==4.2.11 # django-jenkins # django-jsonform # django-jsonsuit + # django-log-outgoing-requests # django-markup # django-otp # django-phonenumber-field @@ -172,6 +174,10 @@ django-admin-index==3.1.1 # via # -r requirements/ci.txt # open-api-framework +django-appconf==1.0.6 + # via + # -r requirements/ci.txt + # django-log-outgoing-requests django-axes==6.4.0 # via # -r requirements/ci.txt @@ -202,6 +208,10 @@ django-jsonform==2.21.5 # open-api-framework django-jsonsuit==0.5.0 # via -r requirements/ci.txt +django-log-outgoing-requests==0.6.1 + # via + # -r requirements/ci.txt + # open-api-framework django-markup==1.8.1 # via # -r requirements/ci.txt @@ -248,6 +258,7 @@ django-solo==2.0.0 # via # -r requirements/ci.txt # commonground-api-common + # django-log-outgoing-requests # mozilla-django-oidc-db # notifications-api-common # sharing-configs @@ -411,7 +422,7 @@ notifications-api-common==0.2.2 # via # -r requirements/ci.txt # commonground-api-common -open-api-framework==0.2.0 +open_api_framework @ git+https://github.com/maykinmedia/open-api-framework.git@feature/django-settings # via -r requirements/ci.txt orderedmultidict==1.0.1 # via @@ -521,6 +532,7 @@ requests==2.31.0 # ape-pie # commonground-api-common # coreapi + # django-log-outgoing-requests # gemma-zds-client # mozilla-django-oidc # open-api-framework From dc08f1c807514057b0a8ca18b51941523b280d27 Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Wed, 1 May 2024 12:17:28 +0200 Subject: [PATCH 2/9] :wrench: [open-zaak/open-zaak#1629] Refactor settings module use base settings from open-api-framework and add staging/production settings --- src/objecttypes/conf/base.py | 399 +----------------- src/objecttypes/conf/docker.py | 60 +-- src/objecttypes/conf/production.py | 48 +++ src/objecttypes/conf/staging.py | 10 + src/objecttypes/conf/tests/__init__.py | 0 .../conf/tests/test_config_helper.py | 15 - src/objecttypes/conf/utils.py | 26 -- 7 files changed, 77 insertions(+), 481 deletions(-) create mode 100644 src/objecttypes/conf/production.py create mode 100644 src/objecttypes/conf/staging.py delete mode 100644 src/objecttypes/conf/tests/__init__.py delete mode 100644 src/objecttypes/conf/tests/test_config_helper.py delete mode 100644 src/objecttypes/conf/utils.py diff --git a/src/objecttypes/conf/base.py b/src/objecttypes/conf/base.py index 2192d521..7a016c83 100644 --- a/src/objecttypes/conf/base.py +++ b/src/objecttypes/conf/base.py @@ -1,90 +1,20 @@ -import os - -from django.urls import reverse_lazy - -from sentry_sdk.integrations import django, redis +from open_api_framework.conf.base import * # noqa +from open_api_framework.conf.utils import config from .api import * # noqa -from .utils import config - -try: - from sentry_sdk.integrations import celery -except Exception: # no celery in this project - celery = None -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -DJANGO_PROJECT_DIR = os.path.abspath( - os.path.join(os.path.dirname(__file__), os.path.pardir) -) -BASE_DIR = os.path.abspath( - os.path.join(DJANGO_PROJECT_DIR, os.path.pardir, os.path.pardir) -) +init_sentry() # # Core Django settings # -SITE_ID = config("SITE_ID", 1) - -DEFAULT_AUTO_FIELD = "django.db.models.AutoField" - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = config("SECRET_KEY") - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = config("DEBUG", default=False) - -ALLOWED_HOSTS = config("ALLOWED_HOSTS", default="", split=True) -IS_HTTPS = config("IS_HTTPS", default=not DEBUG) - -USE_X_FORWARDED_HOST = config("USE_X_FORWARDED_HOST", default=False) - -DATABASES = { - "default": { - "ENGINE": "django.db.backends.postgresql", - "NAME": config("DB_NAME", "objecttypes"), - "USER": config("DB_USER", "objecttypes"), - "PASSWORD": config("DB_PASSWORD", "objecttypes"), - "HOST": config("DB_HOST", "localhost"), - "PORT": config("DB_PORT", 5432), - } -} # Application definition -INSTALLED_APPS = [ - # Note: contenttypes should be first, see Django ticket #10827 - "django.contrib.contenttypes", - "django.contrib.auth", - "django.contrib.sessions", - # Note: If enabled, at least one Site object is required - "django.contrib.sites", - "django.contrib.messages", - "django.contrib.staticfiles", - # django-admin-index - "ordered_model", - "django_admin_index", - # Optional applications. - "django.contrib.admin", - # 'django.contrib.admindocs', - # 'django.contrib.humanize', - # 'django.contrib.sitemaps', +INSTALLED_APPS = INSTALLED_APPS + [ # External applications. - "axes", "jsonsuit.apps.JSONSuitConfig", - "mozilla_django_oidc", - "mozilla_django_oidc_db", - "django_jsonform", - "rest_framework", - "solo", - "drf_spectacular", - "vng_api_common", - "django_setup_configuration", # Two-factor authentication in the Django admin, enforced. - "django_otp", - "django_otp.plugins.otp_static", - "django_otp.plugins.otp_totp", - "two_factor", - "maykin_2fa", "sharing_configs", # Project applications. "objecttypes.accounts", @@ -95,338 +25,33 @@ "objecttypes.utils", ] -MIDDLEWARE = [ - "django.middleware.security.SecurityMiddleware", - "django.contrib.sessions.middleware.SessionMiddleware", - # 'django.middleware.locale.LocaleMiddleware', - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - "django.contrib.auth.middleware.AuthenticationMiddleware", - "maykin_2fa.middleware.OTPMiddleware", - "mozilla_django_oidc_db.middleware.SessionRefresh", - "django.contrib.messages.middleware.MessageMiddleware", - "django.middleware.clickjacking.XFrameOptionsMiddleware", - "axes.middleware.AxesMiddleware", -] - -ROOT_URLCONF = "objecttypes.urls" - -# List of callables that know how to import templates from various sources. -RAW_TEMPLATE_LOADERS = ( - "django.template.loaders.filesystem.Loader", - "django.template.loaders.app_directories.Loader", - # 'admin_tools.template_loaders.Loader', -) - -TEMPLATES = [ - { - "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [ - os.path.join(DJANGO_PROJECT_DIR, "templates"), - ], - "APP_DIRS": False, # conflicts with explicity specifying the loaders - "OPTIONS": { - "context_processors": [ - "django.template.context_processors.debug", - "django.template.context_processors.request", - "django.contrib.auth.context_processors.auth", - "django.contrib.messages.context_processors.messages", - "objecttypes.utils.context_processors.settings", - ], - "loaders": RAW_TEMPLATE_LOADERS, - }, - }, -] - -WSGI_APPLICATION = "objecttypes.wsgi.application" - -# Database: Defined in target specific settings files. -# https://docs.djangoproject.com/en/3.0/ref/settings/#databases - -# Password validation -# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", - }, -] - # Internationalization # https://docs.djangoproject.com/en/3.0/topics/i18n/ -LANGUAGE_CODE = "en-us" - -TIME_ZONE = "Europe/Amsterdam" - -USE_I18N = True - -USE_TZ = True - -USE_THOUSAND_SEPARATOR = True - -# Translations -LOCALE_PATHS = (os.path.join(DJANGO_PROJECT_DIR, "conf", "locale"),) - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/3.0/howto/static-files/ - -STATIC_URL = "/static/" - -STATIC_ROOT = os.path.join(BASE_DIR, "static") - -# Additional locations of static files -STATICFILES_DIRS = (os.path.join(DJANGO_PROJECT_DIR, "static"),) - -# List of finder classes that know how to find static files in -# various locations. -STATICFILES_FINDERS = [ - "django.contrib.staticfiles.finders.FileSystemFinder", - "django.contrib.staticfiles.finders.AppDirectoriesFinder", - # 'django.contrib.staticfiles.finders.DefaultStorageFinder', -] - -MEDIA_ROOT = os.path.join(BASE_DIR, "media") -MEDIA_URL = "/media/" -FILE_UPLOAD_PERMISSIONS = 0o644 - -FIXTURE_DIRS = (os.path.join(DJANGO_PROJECT_DIR, "fixtures"),) - -LOGGING_DIR = os.path.join(BASE_DIR, "log") +LANGUAGE_CODE = "en-us" # FIXME should this be "nl-nl"? -LOGGING = { - "version": 1, - "disable_existing_loggers": False, - "formatters": { - "verbose": { - "format": "%(asctime)s %(levelname)s %(name)s %(module)s %(process)d %(thread)d %(message)s" - }, - "timestamped": {"format": "%(asctime)s %(levelname)s %(name)s %(message)s"}, - "simple": {"format": "%(levelname)s %(message)s"}, - "performance": { - "format": "%(asctime)s %(process)d | %(thread)d | %(message)s", - }, - }, - "filters": { - "require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}, - }, - "handlers": { - "mail_admins": { - "level": "ERROR", - "filters": ["require_debug_false"], - "class": "django.utils.log.AdminEmailHandler", - }, - "null": { - "level": "DEBUG", - "class": "logging.NullHandler", - }, - "console": { - "level": "DEBUG", - "class": "logging.StreamHandler", - "formatter": "timestamped", - }, - "django": { - "level": "DEBUG", - "class": "logging.handlers.RotatingFileHandler", - "filename": os.path.join(LOGGING_DIR, "django.log"), - "formatter": "verbose", - "maxBytes": 1024 * 1024 * 10, # 10 MB - "backupCount": 10, - }, - "project": { - "level": "DEBUG", - "class": "logging.handlers.RotatingFileHandler", - "filename": os.path.join(LOGGING_DIR, "objecttypes.log"), - "formatter": "verbose", - "maxBytes": 1024 * 1024 * 10, # 10 MB - "backupCount": 10, - }, - "performance": { - "level": "INFO", - "class": "logging.handlers.RotatingFileHandler", - "filename": os.path.join(LOGGING_DIR, "performance.log"), - "formatter": "performance", - "maxBytes": 1024 * 1024 * 10, # 10 MB - "backupCount": 10, - }, - }, - "loggers": { - "objecttypes": { - "handlers": ["project"], - "level": "INFO", - "propagate": True, - }, - "django.request": { - "handlers": ["django"], - "level": "ERROR", - "propagate": True, - }, - "django.template": { - "handlers": ["console"], - "level": "INFO", - "propagate": True, - }, - "mozilla_django_oidc": { - "handlers": ["project"], - "level": "DEBUG", - }, - }, -} - -# -# Additional Django settings -# - -# Custom user model -AUTH_USER_MODEL = "accounts.User" - -# Allow logging in with both username+password and email+password -AUTHENTICATION_BACKENDS = [ - "axes.backends.AxesBackend", - "objecttypes.accounts.backends.UserModelEmailBackend", - "django.contrib.auth.backends.ModelBackend", - "mozilla_django_oidc_db.backends.OIDCAuthenticationBackend", -] - -SESSION_COOKIE_NAME = "objecttypes_sessionid" - -LOGIN_REDIRECT_URL = reverse_lazy("admin:index") -LOGOUT_REDIRECT_URL = reverse_lazy("admin:index") +TIME_ZONE = "Europe/Amsterdam" # FIXME should this be "UTC"? # # Custom settings # PROJECT_NAME = "Objecttypes" SITE_TITLE = "Starting point" -ENVIRONMENT = config("ENVIRONMENT", "") -SHOW_ALERT = True +SHOW_ALERT = True # FIXME this doesn't seem to be used anywhere? -# -# Library settings -# +############################## +# # +# 3RD PARTY LIBRARY SETTINGS # +# # +############################## # Django-Admin-Index -ADMIN_INDEX_SHOW_REMAINING_APPS_TO_SUPERUSERS = False ADMIN_INDEX_DISPLAY_DROP_DOWN_MENU_CONDITION_FUNCTION = ( "objecttypes.utils.admin_index.should_display_dropdown_menu" ) -# Django-Axes -# -# The number of login attempts allowed before a record is created for the -# failed logins. Default: 3 -AXES_FAILURE_LIMIT = 10 -# If set, defines a period of inactivity after which old failed login attempts -# will be forgotten. Can be set to a python timedelta object or an integer. If -# an integer, will be interpreted as a number of hours. Default: None -AXES_COOLOFF_TIME = 1 -# If set, specifies a template to render when a user is locked out. Template -# receives cooloff_time and failure_limit as context variables. Default: None -AXES_LOCKOUT_TEMPLATE = "account_blocked.html" -AXES_LOCKOUT_PARAMETERS = [["ip_address", "user_agent", "username"]] - -# The default meta precedence order -IPWARE_META_PRECEDENCE_ORDER = ( - "HTTP_X_FORWARDED_FOR", - "X_FORWARDED_FOR", # , , - "HTTP_CLIENT_IP", - "HTTP_X_REAL_IP", - "HTTP_X_FORWARDED", - "HTTP_X_CLUSTER_CLIENT_IP", - "HTTP_FORWARDED_FOR", - "HTTP_FORWARDED", - "HTTP_VIA", - "REMOTE_ADDR", -) - -# -# Sending EMAIL -# -EMAIL_HOST = config("EMAIL_HOST", default="localhost") -# disabled on Google Cloud, use 487 instead: -EMAIL_PORT = config("EMAIL_PORT", default=25) -EMAIL_HOST_USER = config("EMAIL_HOST_USER", default="") -EMAIL_HOST_PASSWORD = config("EMAIL_HOST_PASSWORD", default="") -EMAIL_USE_TLS = config("EMAIL_USE_TLS", default=False) -EMAIL_TIMEOUT = 10 - -DEFAULT_FROM_EMAIL = config("DEFAULT_FROM_EMAIL", "objecttypes@example.com") - -# Sentry SDK -SENTRY_DSN = config("SENTRY_DSN", None) - -SENTRY_SDK_INTEGRATIONS = [ - django.DjangoIntegration(), - redis.RedisIntegration(), -] -if celery is not None: - SENTRY_SDK_INTEGRATIONS.append(celery.CeleryIntegration()) - -if SENTRY_DSN: - import sentry_sdk - - SENTRY_CONFIG = { - "dsn": SENTRY_DSN, - "release": config("VERSION_TAG", "VERSION_TAG not set"), - "environment": ENVIRONMENT, - } - - sentry_sdk.init( - **SENTRY_CONFIG, integrations=SENTRY_SDK_INTEGRATIONS, send_default_pii=True - ) - -# -# Elastic APM -# -ELASTIC_APM_SERVER_URL = config("ELASTIC_APM_SERVER_URL", None) -ELASTIC_APM = { - "SERVICE_NAME": config("ELASTIC_APM_SERVICE_NAME", "Objecttypes API"), - "SECRET_TOKEN": config("ELASTIC_APM_SECRET_TOKEN", "default"), - "SERVER_URL": ELASTIC_APM_SERVER_URL, - "ENABLED": bool(ELASTIC_APM_SERVER_URL), -} -if ELASTIC_APM_SERVER_URL: - MIDDLEWARE = ["elasticapm.contrib.django.middleware.TracingMiddleware"] + MIDDLEWARE - INSTALLED_APPS = INSTALLED_APPS + [ - "elasticapm.contrib.django", - ] - - -# -# MAYKIN-2FA -# Uses django-two-factor-auth under the hood, so relevant upstream package settings -# apply too. -# - -# we run the admin site monkeypatch instead. -TWO_FACTOR_PATCH_ADMIN = False -# add entries from AUTHENTICATION_BACKENDS that already enforce their own two-factor -# auth, avoiding having some set up MFA again in the project. -MAYKIN_2FA_ALLOW_MFA_BYPASS_BACKENDS = [ - "mozilla_django_oidc_db.backends.OIDCAuthenticationBackend", -] - -# -# Mozilla Django OIDC DB settings -# -OIDC_AUTHENTICATE_CLASS = "mozilla_django_oidc_db.views.OIDCAuthenticationRequestView" -MOZILLA_DJANGO_OIDC_DB_CACHE = "oidc" -MOZILLA_DJANGO_OIDC_DB_CACHE_TIMEOUT = 5 * 60 - -if config("DISABLE_2FA", default=False): # pragma: no cover - MAYKIN_2FA_ALLOW_MFA_BYPASS_BACKENDS = AUTHENTICATION_BACKENDS - # # Django setup configuration # diff --git a/src/objecttypes/conf/docker.py b/src/objecttypes/conf/docker.py index efd2b87c..55673759 100644 --- a/src/objecttypes/conf/docker.py +++ b/src/objecttypes/conf/docker.py @@ -1,57 +1,11 @@ import os -os.environ.setdefault("DB_USER", os.getenv("DB_USER", "objecttypes")) -os.environ.setdefault("DB_NAME", os.getenv("DB_NAME", "objecttypes")) -os.environ.setdefault("DB_PASSWORD", os.getenv("DB_PASSWORD", "objecttypes")) -os.environ.setdefault("DB_HOST", os.getenv("DB_HOST", "db")) -os.environ.setdefault("ENVIRONMENT", "docker") - -from .base import * # noqa isort:skip -from .utils import config # noqa isort:skip - -# -# Standard Django settings. -# - -CACHES = { - "default": { - "BACKEND": "django.core.cache.backends.locmem.LocMemCache", - }, - # https://github.com/jazzband/django-axes/blob/master/docs/configuration.rst#cache-problems - "axes_cache": { - "BACKEND": "django.core.cache.backends.dummy.DummyCache", - }, - "oidc": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}, -} - -# Deal with being hosted on a subpath -subpath = config("SUBPATH", None) -if subpath: - if not subpath.startswith("/"): - subpath = f"/{subpath}" - - FORCE_SCRIPT_NAME = subpath - STATIC_URL = f"{FORCE_SCRIPT_NAME}{STATIC_URL}" - MEDIA_URL = f"{FORCE_SCRIPT_NAME}{MEDIA_URL}" +os.environ.setdefault("DB_HOST", "db") +os.environ.setdefault("DB_NAME", "postgres") +os.environ.setdefault("DB_USER", "postgres") +os.environ.setdefault("DB_PASSWORD", "") +os.environ.setdefault("ENVIRONMENT", "docker") +os.environ.setdefault("LOG_STDOUT", "yes") -# -# Additional Django settings -# - -# Disable security measures for development -SESSION_COOKIE_SECURE = config("SESSION_COOKIE_SECURE", False) -SESSION_COOKIE_HTTPONLY = config("SESSION_COOKIE_HTTPONLY", False) -CSRF_COOKIE_SECURE = config("CSRF_COOKIE_SECURE", False) - - -# -# Library settings -# - -# django-axes -AXES_BEHIND_REVERSE_PROXY = False -AXES_CACHE = "axes_cache" - -# Elastic APM -ELASTIC_APM["SERVICE_NAME"] += " " + ENVIRONMENT +from .production import * # noqa isort:skip diff --git a/src/objecttypes/conf/production.py b/src/objecttypes/conf/production.py new file mode 100644 index 00000000..dc7c2a6c --- /dev/null +++ b/src/objecttypes/conf/production.py @@ -0,0 +1,48 @@ +import os + +os.environ.setdefault("ENVIRONMENT", "production") + +from .base import * # noqa isort:skip + +# +# Standard Django settings. +# + +# Caching sessions. +SESSION_ENGINE = "django.contrib.sessions.backends.cache" +SESSION_CACHE_ALIAS = "default" + +# Caching templates. +TEMPLATES[0]["OPTIONS"]["loaders"] = [ + ("django.template.loaders.cached.Loader", TEMPLATE_LOADERS) +] + +# The file storage engine to use when collecting static files with the +# collectstatic management command. +STATICFILES_STORAGE = "django.contrib.staticfiles.storage.ManifestStaticFilesStorage" + +# Production logging facility. +LOGGING["loggers"].update( + { + "django.security.DisallowedHost": { + "handlers": logging_django_handlers, + "level": "CRITICAL", + "propagate": False, + }, + } +) + +# Only set this when we're behind a reverse proxy +SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") +SECURE_CONTENT_TYPE_NOSNIFF = True # Sets X-Content-Type-Options: nosniff +SECURE_BROWSER_XSS_FILTER = True # Sets X-XSS-Protection: 1; mode=block + +# Deal with being hosted on a subpath +if subpath and subpath != "/": + STATIC_URL = f"{subpath}{STATIC_URL}" + MEDIA_URL = f"{subpath}{MEDIA_URL}" + +# +# Custom settings overrides +# +ENVIRONMENT_SHOWN_IN_ADMIN = False diff --git a/src/objecttypes/conf/staging.py b/src/objecttypes/conf/staging.py new file mode 100644 index 00000000..b9f88fb0 --- /dev/null +++ b/src/objecttypes/conf/staging.py @@ -0,0 +1,10 @@ +""" +Staging environment settings module. + +This *should* be nearly identical to production. +""" +import os + +os.environ.setdefault("ENVIRONMENT", "staging") + +from .production import * # noqa diff --git a/src/objecttypes/conf/tests/__init__.py b/src/objecttypes/conf/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/objecttypes/conf/tests/test_config_helper.py b/src/objecttypes/conf/tests/test_config_helper.py deleted file mode 100644 index 198e684c..00000000 --- a/src/objecttypes/conf/tests/test_config_helper.py +++ /dev/null @@ -1,15 +0,0 @@ -from django.test import SimpleTestCase - -from ..utils import config - - -class ConfigHelperTests(SimpleTestCase): - def test_empty_list_as_default(self): - value = config("SOME_TEST_ENVVAR", split=True, default=[]) - - self.assertEqual(value, []) - - def test_non_empty_list_as_default(self): - value = config("SOME_TEST_ENVVAR", split=True, default=["foo"]) - - self.assertEqual(value, ["foo"]) diff --git a/src/objecttypes/conf/utils.py b/src/objecttypes/conf/utils.py deleted file mode 100644 index 86dd7cb7..00000000 --- a/src/objecttypes/conf/utils.py +++ /dev/null @@ -1,26 +0,0 @@ -import logging - -from decouple import Csv, config as _config, undefined - -logger = logging.getLogger(__name__) - - -def config(option: str, default=undefined, *args, **kwargs): - """ - Pull a config parameter from the environment. - - Read the config variable ``option``. If it's optional, use the ``default`` value. - Input is automatically cast to the correct type, where the type is derived from the - default value if possible. - - Pass ``split=True`` to split the comma-separated input into a list. - """ - if "split" in kwargs: - kwargs.pop("split") - kwargs["cast"] = Csv() - if isinstance(default, list): - default = ",".join(default) - - if default is not undefined and default is not None: - kwargs.setdefault("cast", type(default)) - return _config(option, default=default, *args, **kwargs) From d9ee94d4617af73d17fd148987030d9402a0f6bd Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Wed, 1 May 2024 14:08:20 +0200 Subject: [PATCH 3/9] :construction_worker: Use CI settings/deps in Github actions --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93abec22..860abff8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ jobs: gdal-bin - name: Install dependencies - run: pip install -r requirements/dev.txt codecov + run: pip install -r requirements/ci.txt codecov - name: Build frontend run: | npm ci @@ -55,7 +55,7 @@ jobs: python src/manage.py collectstatic --noinput --link coverage run src/manage.py test src env: - DJANGO_SETTINGS_MODULE: objecttypes.conf.dev + DJANGO_SETTINGS_MODULE: objecttypes.conf.ci SECRET_KEY: dummy DB_USER: postgres DB_PASSWORD: '' From b21837ee10c24a93dab7b0c2d0aaa97f49621528 Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Wed, 1 May 2024 14:19:35 +0200 Subject: [PATCH 4/9] :whale: Fix docker-compose setup * fix interpolation issue in docker-compose * upgrade postgres to 12 * add redis container * add DISABLE_2FA envvar * add CACHE_DEFAULT and CACHE_AXES --- docker-compose.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 90561482..5e2122a0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '3' services: db: - image: postgres:11-alpine + image: postgres:12-alpine environment: - POSTGRES_HOST_AUTH_METHOD=trust volumes: @@ -10,14 +10,18 @@ services: # - db:/var/lib/postgresql/data command: postgres -c max_connections=300 -c log_min_messages=LOG + redis: + image: redis + web: build: . environment: &app-env - DJANGO_SETTINGS_MODULE=objecttypes.conf.docker - - SECRET_KEY=${SECRET_KEY:-fgv=c0hz&tl*8*3m3893@m+1pstrvidc9e^5@fpspmg%cy$15d} + - SECRET_KEY=${SECRET_KEY:-fgv=c0hz&tl*8*3m3893@m+1pstrvidc9e^5@fpspmg%cyf15d} - ALLOWED_HOSTS=* - - TWO_FACTOR_FORCE_OTP_ADMIN=no - - TWO_FACTOR_PATCH_ADMIN=no + - CACHE_DEFAULT=redis:6379/0 + - CACHE_AXES=redis:6379/0 + - DISABLE_2FA=yes # setup_configuration env vars - OBJECTTYPES_DOMAIN=web:8000 - OBJECTTYPES_ORGANIZATION=ObjectTypes From af6f80dda28f2ca11423bbf578360def3ec39ba0 Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Wed, 1 May 2024 15:01:36 +0200 Subject: [PATCH 5/9] :fire: Remove old fonts _fonts.scss relied on font assets that were in Django 2.2.x, but this causes errors when using ManifestStaticFilesStorage --- src/objecttypes/scss/_fonts.scss | 20 -------------------- src/objecttypes/scss/screen.scss | 1 - 2 files changed, 21 deletions(-) delete mode 100644 src/objecttypes/scss/_fonts.scss diff --git a/src/objecttypes/scss/_fonts.scss b/src/objecttypes/scss/_fonts.scss deleted file mode 100644 index d260cea6..00000000 --- a/src/objecttypes/scss/_fonts.scss +++ /dev/null @@ -1,20 +0,0 @@ -@font-face { - font-family: "Roboto"; - src: url("../admin/fonts/Roboto-Bold-webfont.woff"); - font-weight: 700; - font-style: normal; -} - -@font-face { - font-family: "Roboto"; - src: url("../admin/fonts/Roboto-Regular-webfont.woff"); - font-weight: 400; - font-style: normal; -} - -@font-face { - font-family: "Roboto"; - src: url("../admin/fonts/Roboto-Light-webfont.woff"); - font-weight: 300; - font-style: normal; -} \ No newline at end of file diff --git a/src/objecttypes/scss/screen.scss b/src/objecttypes/scss/screen.scss index 28eb97e0..0db56da4 100644 --- a/src/objecttypes/scss/screen.scss +++ b/src/objecttypes/scss/screen.scss @@ -1,4 +1,3 @@ @import "vars"; -@import "fonts"; @import "app"; @import "components/all.scss"; From 5b8fffdacdf322774e693a2c26140f98eb6db7d5 Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Tue, 7 May 2024 13:52:21 +0200 Subject: [PATCH 6/9] :wrench: Show log_outgoing_requests log and config in admin --- src/objecttypes/fixtures/default_admin_index.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/objecttypes/fixtures/default_admin_index.json b/src/objecttypes/fixtures/default_admin_index.json index d6af7d9f..80dd7b77 100644 --- a/src/objecttypes/fixtures/default_admin_index.json +++ b/src/objecttypes/fixtures/default_admin_index.json @@ -81,6 +81,14 @@ [ "axes", "accesslog" + ], + [ + "log_outgoing_requests", + "outgoingrequestslog" + ], + [ + "log_outgoing_requests", + "outgoingrequestslogconfig" ] ] } From 95b0f4c895ad8bea0361b0d09ab937b1ca2de9dd Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Tue, 7 May 2024 14:02:38 +0200 Subject: [PATCH 7/9] :arrow_up: Upgrade mozilla-django-oidc-db to 0.16.0 as it was previously broken using 0.14.1 --- requirements/base.txt | 2 +- requirements/ci.txt | 2 +- requirements/dev.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements/base.txt b/requirements/base.txt index 77b13a0d..57bdeb3c 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -233,7 +233,7 @@ maykin-2fa==1.0.0 # via open-api-framework mozilla-django-oidc==4.0.0 # via mozilla-django-oidc-db -mozilla-django-oidc-db==0.14.1 +mozilla-django-oidc-db==0.16.0 # via open-api-framework notifications-api-common==0.2.2 # via commonground-api-common diff --git a/requirements/ci.txt b/requirements/ci.txt index 4b759b7b..8e9b633d 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -371,7 +371,7 @@ mozilla-django-oidc==4.0.0 # via # -r requirements/base.txt # mozilla-django-oidc-db -mozilla-django-oidc-db==0.14.1 +mozilla-django-oidc-db==0.16.0 # via # -r requirements/base.txt # open-api-framework diff --git a/requirements/dev.txt b/requirements/dev.txt index bf22f975..4959f6f2 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -412,7 +412,7 @@ mozilla-django-oidc==4.0.0 # via # -r requirements/ci.txt # mozilla-django-oidc-db -mozilla-django-oidc-db==0.14.1 +mozilla-django-oidc-db==0.16.0 # via # -r requirements/ci.txt # open-api-framework From 48e1d3b57a683fb3d0e7dfb6797e4739a4e08441 Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Tue, 14 May 2024 11:13:15 +0200 Subject: [PATCH 8/9] :ok_hand: [open-zaak/open-zaak#1629] PR feedback * remove unused setting * add warning in changelog to add Redis --- CHANGELOG.rst | 7 +++++++ src/objecttypes/conf/base.py | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3b6eb728..b750bb76 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,12 +8,19 @@ Change history **Bugfixes and QOL** * updated to Django 4.2 (objects-api#385) +* changed caching backend from LocMem to Redis .. warning:: Two-factor authentication is enabled by default. The ``DISABLE_2FA`` environment variable can be used to disable it if needed. +.. warning:: + + Because the caching barefer to env config for envvarsckend was changed to Redis, + existing deployments must add a Redis container or Redis instance + (see ``Installation > Environment configuration reference`` in the documentation on how to configure) the connection with Redis + 2.1.2 (2024-02-06) ------------------ diff --git a/src/objecttypes/conf/base.py b/src/objecttypes/conf/base.py index 7a016c83..a8683f9d 100644 --- a/src/objecttypes/conf/base.py +++ b/src/objecttypes/conf/base.py @@ -38,7 +38,6 @@ # PROJECT_NAME = "Objecttypes" SITE_TITLE = "Starting point" -SHOW_ALERT = True # FIXME this doesn't seem to be used anywhere? ############################## From 9d73d430925fc8c72f09df5a2a2929b0f7e2ad15 Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Fri, 17 May 2024 10:17:21 +0200 Subject: [PATCH 9/9] :arrow_up: Upgrade open-api-framework to 0.3.0 --- requirements/base.in | 2 +- requirements/base.txt | 2 +- requirements/ci.txt | 2 +- requirements/dev.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements/base.in b/requirements/base.in index 714850b3..7bd81885 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -1,4 +1,4 @@ -git+https://github.com/maykinmedia/open-api-framework.git@feature/django-settings +open-api-framework # Core python libraries jsonschema diff --git a/requirements/base.txt b/requirements/base.txt index 57bdeb3c..a0224210 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -237,7 +237,7 @@ mozilla-django-oidc-db==0.16.0 # via open-api-framework notifications-api-common==0.2.2 # via commonground-api-common -open_api_framework @ git+https://github.com/maykinmedia/open-api-framework.git@feature/django-settings +open-api-framework==0.3.0 # via -r requirements/base.in orderedmultidict==1.0.1 # via furl diff --git a/requirements/ci.txt b/requirements/ci.txt index 8e9b633d..1b577911 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -379,7 +379,7 @@ notifications-api-common==0.2.2 # via # -r requirements/base.txt # commonground-api-common -open_api_framework @ git+https://github.com/maykinmedia/open-api-framework.git@feature/django-settings +open-api-framework==0.3.0 # via -r requirements/base.txt orderedmultidict==1.0.1 # via diff --git a/requirements/dev.txt b/requirements/dev.txt index 4959f6f2..90c136da 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -422,7 +422,7 @@ notifications-api-common==0.2.2 # via # -r requirements/ci.txt # commonground-api-common -open_api_framework @ git+https://github.com/maykinmedia/open-api-framework.git@feature/django-settings +open-api-framework==0.3.0 # via -r requirements/ci.txt orderedmultidict==1.0.1 # via