|
14 | 14 | import sys |
15 | 15 | from os import environ as env |
16 | 16 | from pathlib import Path |
| 17 | +from typing import Annotated |
17 | 18 |
|
18 | 19 | import dj_database_url |
19 | 20 | import sentry_sdk |
20 | | -from pydantic import BaseModel, DirectoryPath, Field |
| 21 | +from pydantic import BaseModel, DirectoryPath, Field, PlainSerializer |
21 | 22 | from pydantic_settings import BaseSettings, SettingsConfigDict |
22 | 23 | from sentry_sdk.integrations.django import DjangoIntegration |
23 | 24 |
|
24 | 25 |
|
| 26 | +def get_secret(name: str, encoding: str = "utf-8") -> str: |
| 27 | + credentials_dir = Secrets().CREDENTIALS_DIRECTORY # type: ignore[reportCallIssue] |
| 28 | + |
| 29 | + try: |
| 30 | + with open(f"{credentials_dir}/{name}", encoding=encoding) as f: |
| 31 | + secret = f.read().removesuffix("\n") |
| 32 | + except FileNotFoundError: |
| 33 | + raise RuntimeError(f"No secret named {name} found in {credentials_dir}.") |
| 34 | + |
| 35 | + return secret |
| 36 | + |
| 37 | + |
25 | 38 | class Secrets(BaseSettings): |
26 | 39 | CREDENTIALS_DIRECTORY: DirectoryPath |
27 | 40 |
|
@@ -90,32 +103,43 @@ class DjangoSettings(BaseModel): |
90 | 103 | default=[], |
91 | 104 | ) |
92 | 105 |
|
93 | | - DJANGO_SETTINGS: DjangoSettings |
| 106 | + class SocialAccountProviders(BaseModel): |
| 107 | + class GitHub(BaseModel): |
| 108 | + SCOPE: list[str] = Field( |
| 109 | + description="Access scopes required by the application" |
| 110 | + ) |
94 | 111 |
|
| 112 | + class AppSettings(BaseModel): |
| 113 | + client_id: Annotated[str, PlainSerializer(get_secret)] |
| 114 | + secret: Annotated[str, PlainSerializer(get_secret)] |
| 115 | + key: str = "" |
95 | 116 |
|
96 | | -for key, value in Settings().dict()["DJANGO_SETTINGS"].items(): # type: ignore[reportCallIssue] |
97 | | - setattr(sys.modules[__name__], key, value) |
| 117 | + APPS: list[AppSettings] = [] |
98 | 118 |
|
99 | | -# TODO(@fricklerhandwerk): move all configuration over to pydantic-settings |
| 119 | + github: GitHub | None |
100 | 120 |
|
101 | | -# Build paths inside the project like this: BASE_DIR / 'subdir'. |
102 | | -BASE_DIR = Path(__file__).resolve().parent.parent |
| 121 | + _GitHub = SocialAccountProviders.GitHub |
| 122 | + _App = SocialAccountProviders.GitHub.AppSettings |
103 | 123 |
|
| 124 | + SOCIALACCOUNT_PROVIDERS: SocialAccountProviders = SocialAccountProviders( |
| 125 | + github=_GitHub( |
| 126 | + SCOPE=["read:user", "read:org"], |
| 127 | + APPS=[_App(client_id="GH_CLIENT_ID", secret="GH_SECRET")], |
| 128 | + ), |
| 129 | + ) |
104 | 130 |
|
105 | | -def get_secret(name: str, encoding: str = "utf-8") -> str: |
106 | | - credentials_dir = Secrets().CREDENTIALS_DIRECTORY # type: ignore[reportCallIssue] |
| 131 | + DJANGO_SETTINGS: DjangoSettings |
107 | 132 |
|
108 | | - try: |
109 | | - with open(f"{credentials_dir}/{name}", encoding=encoding) as f: |
110 | | - secret = f.read().removesuffix("\n") |
111 | | - except FileNotFoundError: |
112 | | - raise RuntimeError(f"No secret named {name} found in {credentials_dir}.") |
113 | 133 |
|
114 | | - return secret |
| 134 | +for key, value in Settings().model_dump()["DJANGO_SETTINGS"].items(): # type: ignore[reportCallIssue] |
| 135 | + setattr(sys.modules[__name__], key, value) |
115 | 136 |
|
| 137 | +# TODO(@fricklerhandwerk): move all configuration over to pydantic-settings |
116 | 138 |
|
117 | | -## GlitchTip setup |
| 139 | +# Build paths inside the project like this: BASE_DIR / 'subdir'. |
| 140 | +BASE_DIR = Path(__file__).resolve().parent.parent |
118 | 141 |
|
| 142 | +## GlitchTip setup |
119 | 143 | if "GLITCHTIP_DSN" in env: |
120 | 144 | sentry_sdk.init( |
121 | 145 | dsn=get_secret("GLITCHTIP_DSN"), |
@@ -312,21 +336,6 @@ def get_secret(name: str, encoding: str = "utf-8") -> str: |
312 | 336 | "allauth.account.auth_backends.AuthenticationBackend", |
313 | 337 | ] |
314 | 338 |
|
315 | | -SOCIALACCOUNT_PROVIDERS = { |
316 | | - "github": { |
317 | | - "SCOPE": [ |
318 | | - "read:user", |
319 | | - "read:org", |
320 | | - ], |
321 | | - "APPS": [ |
322 | | - { |
323 | | - "client_id": get_secret("GH_CLIENT_ID"), |
324 | | - "secret": get_secret("GH_SECRET"), |
325 | | - "key": "", |
326 | | - } |
327 | | - ], |
328 | | - } |
329 | | -} |
330 | 339 |
|
331 | 340 | REST_FRAMEWORK = { |
332 | 341 | "DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"] |
|
0 commit comments