dotenv handling published: 09/02/24 (dd/mm/yy) updated: not yet Here's how we're handling secrets at work (for Django projects): 1) Put whatever we need in .env files. 2) Load the env vars in manage.py (& wsgi.py on prod). 3) Use this cute little function: ```py def get_secret(setting, default=None): try: if os.environ[setting].lower() in ("true", "on", "1"): return True elif os.environ[setting].lower() in ("false", "off", "0"): return False return os.environ[setting] except KeyError: if default is not None: return default raise ImproperlyConfigured(f"Set the {setting} environment variable") ``` What are the benefits? We *know* that boolean values will be returned as boolean values, and *all* the other ones will be strings. We then cast them to their correct type if we need to. We can also provide default values if needed (the keys are not always defined in our dev env, so the default values are the ones we use in our dev env): ```py get_secret("REDIS_DB", 42), ``` Why don't we use an external lib that cast values for us? Well, here's a few reasons I can think of: - We don't need more dependencies. Well, we're using hundreds of packages, if we can avoid a new potentially dead package, then go for it, don't use something like this for a critical task. - We know where we need casts, so there's no need to auto-cast some values (by letting an external lib guess which type our env var should be). - Those 11 lines are on a lot of our projects "by default" (we use a starter package for certain projects, importing a tar.gz export of our repo using the django command), no need to think about upgrading a package because of a security issue or a new shiny feature. Shitty conclusion: Whatever you do on your django projects, use what you want. But we're a small team, with a lot of dead dependencies and dead code that we can't remove because we don't have the time to do it properly. In order to reduce those constraints we're making some choices, and this `get_secret` function is one of them.