Skip to content

Commit 00df79c

Browse files
committed
fix: support secrets
1 parent f909f35 commit 00df79c

11 files changed

+145
-8
lines changed

.env/.env

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# 📝 Shared Variables 📝
2+
# These variables are always loaded and shared by all environments.
3+
#
4+
# The final value of a variable depends on the priority of where it's being set:
5+
# 1. Deployment pipeline.
6+
# 2. Dedicated environment (.env.{local/development/staging/production}).
7+
# 3. Shared environment (.env).
8+
#
9+
# 🚫 DO NOT PUT SECRETS HERE 🚫

.env/.env.development

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# 📝 Development Variables 📝
2+
# These variables are only loaded in the development environment.
3+
#
4+
# The final value of a variable depends on the priority of where it's being set:
5+
# 1. Deployment pipeline.
6+
# 2. Dedicated environment (.env.development).
7+
# 3. Shared environment (.env).
8+
#
9+
# 🚫 DO NOT PUT SECRETS HERE 🚫

.env/.env.local

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# 📝 Local Variables 📝
2+
# These variables are only loaded in your local environment (on your PC).
3+
#
4+
# The final value of a variable depends on the priority of where it's being set:
5+
# 1. Dedicated environment (.env.local).
6+
# 2. Shared environment (.env).
7+
#
8+
# 🚫 DO NOT PUT SECRETS HERE 🚫

.env/.env.local.secrets

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# 📝 Local Secret Variables 📝
2+
# These secret variables are only loaded in your local environment (on your PC).
3+
#
4+
# This file is git-ignored intentionally to keep these variables a secret.
5+
#
6+
# 🚫 DO NOT PUSH SECRETS TO THE CODE REPO 🚫

.env/.env.production

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# 📝 Production Variables 📝
2+
# These variables are only loaded in the production environment.
3+
#
4+
# The final value of a variable depends on the priority of where it's being set:
5+
# 1. Deployment pipeline.
6+
# 2. Dedicated environment (.env.production).
7+
# 3. Shared environment (.env).
8+
#
9+
# 🚫 DO NOT PUT SECRETS HERE 🚫

.env/.env.staging

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# 📝 Staging Variables 📝
2+
# These variables are only loaded in the staging environment.
3+
#
4+
# The final value of a variable depends on the priority of where it's being set:
5+
# 1. Deployment pipeline.
6+
# 2. Dedicated environment (.env.staging).
7+
# 3. Shared environment (.env).
8+
#
9+
# 🚫 DO NOT PUT SECRETS HERE 🚫

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ celerybeat.pid
125125
*.sage.py
126126

127127
# Environments
128-
.env
128+
.env.secrets
129129
.venv
130130
env/
131131
venv/

Pipfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
url = "https://pypi.org/simple"
33
verify_ssl = true
44
name = "pypi"
5-
65
## ℹ️ HOW-TO: Make the python-package editable.
76
#
87
# 1. Comment out the non-editable codeforlife package under [packages].
@@ -26,6 +25,7 @@ name = "pypi"
2625
codeforlife = "==0.23.1"
2726
# 🚫 Don't add [packages] below that are inherited from the CFL package.
2827
django-storages = {version = "==1.14.4", extras = ["s3"]}
28+
python-dotenv = "*"
2929

3030
[dev-packages]
3131
codeforlife = {version = "==0.23.1", extras = ["dev"]}

Pipfile.lock

+10-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/urls.py

+5
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ def get_health_check(self, request):
5454
health_status=health_check.health_status,
5555
additional_info=health_check.additional_info,
5656
details=[
57+
HealthCheck.Detail(
58+
name="settings_secrets_keys",
59+
description=",".join(list(settings.secrets.keys())),
60+
health="healthy",
61+
),
5762
HealthCheck.Detail(
5863
name="STATIC_ROOT",
5964
description=str(settings.STATIC_ROOT),

settings.py

+78-5
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,87 @@
1616
import os
1717
from pathlib import Path
1818

19+
20+
def set_up_settings(service_name: str):
21+
"""Set up the settings for the service.
22+
23+
*This needs to be called before importing the CFL settings!*
24+
25+
Examples:
26+
```
27+
from codeforlife import set_up_settings
28+
29+
# Must set up settings before importing them!
30+
secrets = set_up_settings("example")
31+
32+
from codeforlife.settings import *
33+
```
34+
35+
Args:
36+
service_name: The name of the current service.
37+
38+
Returns:
39+
The secrets. These are not loaded as environment variables so that 3rd
40+
party packages cannot read them.
41+
"""
42+
43+
# pylint: disable-all
44+
45+
import sys
46+
47+
# import typing as t
48+
from io import StringIO
49+
50+
import boto3
51+
from dotenv import dotenv_values, load_dotenv
52+
53+
# Env = t.Literal["local", "development", "staging", "production"]
54+
# if t.TYPE_CHECKING:
55+
# from mypy_boto3_s3.client import S3Client
56+
57+
if "codeforlife.settings" in sys.modules:
58+
raise ImportError(
59+
"You must set up the CFL settings before importing them."
60+
)
61+
62+
os.environ["SERVICE_NAME"] = service_name
63+
64+
os.environ.setdefault("ENV", "local")
65+
# env = t.cast(Env, os.environ["ENV"])
66+
env = os.environ["ENV"]
67+
68+
load_dotenv(f".env/.env.{env}", override=False)
69+
load_dotenv(".env/.env", override=False)
70+
71+
if env == "local":
72+
_secrets = dotenv_values(".env/.env.local.secrets")
73+
else:
74+
_AWS_S3_APP_BUCKET = os.environ["aws_s3_app_bucket"]
75+
_AWS_S3_APP_FOLDER = os.environ["aws_s3_app_folder"]
76+
77+
# Get the secrets object.
78+
s3: "S3Client" = boto3.client("s3")
79+
secrets_object = s3.get_object(
80+
Bucket=_AWS_S3_APP_BUCKET,
81+
Key=f"{_AWS_S3_APP_FOLDER}/secure/.env.secrets",
82+
)
83+
84+
secrets_str = secrets_object["Body"].read().decode("utf-8")
85+
86+
_secrets = dotenv_values(stream=StringIO(secrets_str))
87+
88+
return {key: value for key, value in _secrets.items() if value is not None}
89+
90+
# pylint: enable
91+
92+
1993
# Build paths inside the project like this: BASE_DIR / 'subdir'.
2094
BASE_DIR = Path(__file__).resolve().parent
2195

22-
# NOTE: Must come before importing CFL settings.
23-
os.environ["SERVICE_NAME"] = "contributor"
96+
secrets = set_up_settings(service_name="contributor")
97+
98+
# pylint: disable-next=wildcard-import,unused-wildcard-import,wrong-import-position
99+
from codeforlife.settings import *
24100

25101
# GitHub
26102

@@ -30,9 +106,6 @@
30106
GH_CLIENT_ID = os.getenv("GH_CLIENT_ID", "Ov23liBErSabQFqROeMg")
31107
GH_CLIENT_SECRET = os.getenv("GH_CLIENT_SECRET", "replace-me")
32108

33-
# pylint: disable-next=wildcard-import,unused-wildcard-import,wrong-import-position
34-
from codeforlife.settings import *
35-
36109
# Installed Apps
37110
# https://docs.djangoproject.com/en/3.2/ref/settings/#installed-apps
38111

0 commit comments

Comments
 (0)