WIP (midway checkin): create_example_conf.py

This commit is contained in:
Klaas van Schelven
2024-05-13 23:07:20 +02:00
parent f2de61b273
commit 0863284a50
5 changed files with 157 additions and 56 deletions

View File

View File

@@ -0,0 +1,83 @@
import argparse
import os
import sys
from django.core.management.utils import get_random_secret_key
def main():
parser = argparse.ArgumentParser(description="Create a configuration file for the example")
parser.add_argument("--output-file", "-o", help="Output file", default="bugsink_conf.py")
args = parser.parse_args()
if os.path.exists(args.output_file):
print("Output file already exists; please remove it first")
sys.exit(1)
secret_key = get_random_secret_key()
with open(args.output_file, "w") as f:
f.write('''# auto-generated example bugsink_conf.py
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "''' + secret_key + '''"
# Alternatively, pass the SECRET_KEY as an environment variable. (although that has security implications too!)
# i.e. those may leak in shared server setups.
#
# SECRET_KEY = os.getenv("SECRET_KEY")
# See TODO in the docs
SNAPPEA = {
"TASK_ALWAYS_EAGER": True,
"NUM_WORKERS": 1,
}
# EMAIL_HOST = ...
# EMAIL_HOST_USER = ...
# EMAIL_HOST_PASSWORD = ...
# EMAIL_PORT = ...
# EMAIL_USE_TLS = ...
SERVER_EMAIL = DEFAULT_FROM_EMAIL = "Bugsink <bugsink@example.org>"
BUGSINK = {
# See TODO in the docs
# "DIGEST_IMMEDIATELY": False,
# "MAX_EVENT_SIZE": _MEBIBYTE,
# "MAX_EVENT_COMPRESSED_SIZE": 200 * _KIBIBYTE,
# "MAX_ENVELOPE_SIZE": 100 * _MEBIBYTE,
# "MAX_ENVELOPE_COMPRESSED_SIZE": 20 * _MEBIBYTE,
# "BASE_URL": "http://bugsink:9000", # no trailing slash
# "SITE_TITLE": "Bugsink", # you can customize this as e.g. "My Bugsink" or "Bugsink for My Company"
}
''')
# some thoughts that I haven't been able to squish into a short comment yet:
# 1. regarding env-variables v.s. just using a conf file: we're not religious about Twelve Factor at all, but even if we
# were 12-factor says the following (which is basically what we do):
# > Another approach to config is the use of config files which are not checked into revision control, such as
# > config/database.yml in Rails. This is a huge improvement over using constants which are checked into the code repo,
# > but still has weaknesses: its easy to mistakenly check in a config file to the repo; there is a tendency for config
# > files to be scattered about in different places and different formats, making it hard to see and manage all the
# > config in one place. Further, these formats tend to be language- or framework-specific.
# regarding the mentioned drawbacks: check-in is unlikely (this conf is owned by end-users, not bugsink-programmers) and
# scattering is not what we do: we have just a single file for the bugsink conf (though there are separate ones for e.g.
# gunicorn and nginx, but I'd argue that's a good thing)
#
# 2. when comparing with the auto-generated django settings, the SECRET_KEY that we generate here is less likely to be
# "automatically exposed", because it is not automatically part of the source code (checked into version control) of
# some piece of software. Still, people could check this file in, and you'd have an exposed key in that case.
#
# 3. regarding the sensitivity of this key, and storing it in the file system: I'd argue that if the server you're
# running bugsink on is compromised (and the file can be read) you have bigger problems (since the DB is also on that
# server)

View File

View File

@@ -4,13 +4,24 @@ import sys
from pathlib import Path
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
from django.utils.log import DEFAULT_LOGGING
from debug_toolbar.middleware import show_toolbar
# We have a single file for our default settings, and expect (if they use the recommended setup) the end-users to
# configure their setup using a single bugsink_conf.py also. To be able to have (slightly) different settings for e.g.
# logging for various commands, we expose a variable I_AM_RUNNING that can be used to determine what command is being
# run. We use (potentially fragile) sys.argv checks to determine what command is being run. For now "it works, don't
# fix it"
if sys.argv[1:2] == ['runsnappea']:
I_AM_RUNNING = "SNAPPEA"
elif sys.argv[1:2] == ['test']:
I_AM_RUNNING = "TEST"
else:
I_AM_RUNNING = "OTHER"
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
@@ -18,8 +29,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-$@clhhieazwnxnha-_zah&(bieq%yux7#^07&xsvhn58t)8@xw'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = False
ALLOWED_HOSTS = ["*"] # SECURITY WARNING: also make production-worthy
@@ -193,10 +203,11 @@ DEBUG_TOOLBAR_CONFIG = {
LOGGING = deepcopy(DEFAULT_LOGGING)
# Django's standard logging has LOGGING['handlers']['console']['filters'] = ['require_debug_true']; our app is
# configured (by default at least) to just spit everything on stdout, even in production. stdout is picked up by
# gunicorn, and we can "take it from there".
LOGGING['handlers']['console']['filters'] = []
if I_AM_RUNNING != "TEST":
# Django's standard logging has LOGGING['handlers']['console']['filters'] = ['require_debug_true']; our app is
# configured (by default at least) to just spit everything on stdout, even in production. stdout is picked up by
# gunicorn, and we can "take it from there".
LOGGING['handlers']['console']['filters'] = []
LOGGING['loggers']['bugsink'] = {
"level": "INFO",
@@ -210,7 +221,7 @@ LOGGING["formatters"]["snappea"] = {
}
LOGGING["handlers"]["snappea"] = {
"level": "DEBUG" if DEBUG else "INFO",
"level": "DEBUG" if DEBUG else "INFO", # TODO this won't work either. but this I can do more classically (development.py)
"class": "logging.StreamHandler"
}
@@ -221,51 +232,9 @@ LOGGING['loggers']['snappea'] = {
"handlers": ["snappea"],
}
# TODO sys.argv checking: how do I want to deal with it in my final config setup?
if sys.argv[1:2] == ['runsnappea']:
if I_AM_RUNNING == "SNAPPEA":
# We set all handlers to the snappea handler in this case: this way the things that are logged inside individual
# workers show up with the relevant worker-annotations (i.e. threadName).
for logger in LOGGING['loggers'].values():
logger["handlers"] = ["snappea"]
# ###################### MOST PER-SITE CONFIG BELOW THIS LINE ###################
# {PROTOCOL}://{PUBLIC_KEY}:{DEPRECATED_SECRET_KEY}@{HOST}{PATH}/{PROJECT_ID}
SENTRY_DSN = os.getenv("SENTRY_DSN")
if SENTRY_DSN is not None:
sentry_sdk.init(
dsn=SENTRY_DSN,
integrations=[DjangoIntegration()],
auto_session_tracking=False,
traces_sample_rate=0,
send_default_pii=True,
)
SNAPPEA = {
"TASK_ALWAYS_EAGER": True,
"NUM_WORKERS": 1,
}
POSTMARK_API_KEY = os.getenv('POSTMARK_API_KEY')
EMAIL_HOST = 'smtp.postmarkapp.com'
EMAIL_HOST_USER = POSTMARK_API_KEY
EMAIL_HOST_PASSWORD = POSTMARK_API_KEY
EMAIL_PORT = 587
EMAIL_USE_TLS = True
SERVER_EMAIL = DEFAULT_FROM_EMAIL = 'Klaas van Schelven <klaas@vanschelven.com>'
BUGSINK = {
"DIGEST_IMMEDIATELY": False,
# "MAX_EVENT_SIZE": _MEBIBYTE,
# "MAX_EVENT_COMPRESSED_SIZE": 200 * _KIBIBYTE,
# "MAX_ENVELOPE_SIZE": 100 * _MEBIBYTE,
# "MAX_ENVELOPE_COMPRESSED_SIZE": 20 * _MEBIBYTE,
"BASE_URL": "http://bugsink:9000", # no trailing slash
"SITE_TITLE": "Bugsink", # you can customize this as e.g. "My Bugsink" or "Bugsink for My Company"
}

View File

@@ -0,0 +1,49 @@
from .default import * # noqa
import os
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
DEBUG = True
# {PROTOCOL}://{PUBLIC_KEY}:{DEPRECATED_SECRET_KEY}@{HOST}{PATH}/{PROJECT_ID}
SENTRY_DSN = os.getenv("SENTRY_DSN")
if SENTRY_DSN is not None:
sentry_sdk.init(
dsn=SENTRY_DSN,
integrations=[DjangoIntegration()],
auto_session_tracking=False,
traces_sample_rate=0,
send_default_pii=True,
)
SNAPPEA = {
"TASK_ALWAYS_EAGER": True,
"NUM_WORKERS": 1,
}
POSTMARK_API_KEY = os.getenv('POSTMARK_API_KEY')
EMAIL_HOST = 'smtp.postmarkapp.com'
EMAIL_HOST_USER = POSTMARK_API_KEY
EMAIL_HOST_PASSWORD = POSTMARK_API_KEY
EMAIL_PORT = 587
EMAIL_USE_TLS = True
SERVER_EMAIL = DEFAULT_FROM_EMAIL = 'Klaas van Schelven <klaas@vanschelven.com>'
BUGSINK = {
"DIGEST_IMMEDIATELY": False,
# "MAX_EVENT_SIZE": _MEBIBYTE,
# "MAX_EVENT_COMPRESSED_SIZE": 200 * _KIBIBYTE,
# "MAX_ENVELOPE_SIZE": 100 * _MEBIBYTE,
# "MAX_ENVELOPE_COMPRESSED_SIZE": 20 * _MEBIBYTE,
"BASE_URL": "http://bugsink:9000", # no trailing slash
"SITE_TITLE": "Bugsink", # you can customize this as e.g. "My Bugsink" or "Bugsink for My Company"
}