From a2e8ab9989c8dedfa523482b9c45649117015a96 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Fri, 1 Nov 2024 06:17:37 +0100 Subject: [PATCH 01/27] refactor(frontend): define and use createProxyConfig convenience function --- frontend/vite.config.ts | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 81fe8f4..dc12ed7 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -6,6 +6,12 @@ export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd()) const baseUrl = (env.VITE_BASE_URL || "/").replace(/\/?$/, "/") + const createProxyConfig = (endpoint) => ({ + target: `https://${env.VITE_BACKEND_API}`, + changeOrigin: false, + rewrite: (path) => path.replace(new RegExp(`^${baseUrl}`), "/"), + }) + return { base: baseUrl, plugins: [react()], @@ -17,29 +23,9 @@ export default defineConfig(({ mode }) => { host: true, port: Number(env.VITE_PORT) || 5173, proxy: { - [`${baseUrl}graphql`]: { - target: `ws://${env.VITE_BACKEND_API}`, - changeOrigin: false, - secure: false, - ws: true, - rewriteWsOrigin: false, - // REMOVEME: The API will have a base path similar to the frontend at some point - rewrite: (path) => path.replace(new RegExp(`^${baseUrl}`), "/"), - }, - [`${baseUrl}oauth`]: { - target: `http://${env.VITE_BACKEND_API}`, - changeOrigin: false, - secure: false, - // REMOVEME: The API will have a base path similar to the frontend at some point - rewrite: (path) => path.replace(new RegExp(`^${baseUrl}`), "/"), - }, - [`${baseUrl}metadata`]: { - target: `http://${env.VITE_BACKEND_API}`, - changeOrigin: false, - secure: false, - // REMOVEME: The API will have a base path similar to the frontend at some point - rewrite: (path) => path.replace(new RegExp(`^${baseUrl}`), "/"), - }, + [`${baseUrl}graphql`]: createProxyConfig('graphql'), + [`${baseUrl}oauth`]: createProxyConfig('oauth'), + [`${baseUrl}metadata`]: createProxyConfig('metadata'), }, }, test: { From 549b1c42deb8026435fcbf6a76410c46a0c61c75 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Fri, 1 Nov 2024 06:18:57 +0100 Subject: [PATCH 02/27] feat(frontend/mtls): try to load and enable mtls for proxied backend routes --- frontend/vite.config.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index dc12ed7..0d01afc 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,14 +1,32 @@ import { defineConfig, loadEnv } from "vite" import path from "path" import react from "@vitejs/plugin-react" +import fs from "fs" export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd()) const baseUrl = (env.VITE_BASE_URL || "/").replace(/\/?$/, "/") + let sslConfig = null + if (env.VITE_MTLS_KEY && env.VITE_MTLS_CLIENT && env.VITE_MTLS_CA) { + const keyPath = path.resolve(__dirname, env.VITE_MTLS_KEY) + const certPath = path.resolve(__dirname, env.VITE_MTLS_CLIENT) + const caPath = path.resolve(__dirname, env.VITE_MTLS_CA) + + if (fs.existsSync(keyPath) && fs.existsSync(certPath) && fs.existsSync(caPath)) { + sslConfig = { + key: fs.readFileSync(keyPath), + cert: fs.readFileSync(certPath), + ca: fs.readFileSync(caPath), + } + } + } + const createProxyConfig = (endpoint) => ({ target: `https://${env.VITE_BACKEND_API}`, changeOrigin: false, + secure: sslConfig ? true : false, + ssl: sslConfig, rewrite: (path) => path.replace(new RegExp(`^${baseUrl}`), "/"), }) From 4782ab8499119af3c0ca22e7df41df2c2b25f43c Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:29:35 +0100 Subject: [PATCH 03/27] feat(api/mtls): add mtls support --- api/src/damnit_api/main.py | 5 +++++ api/src/damnit_api/settings.py | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/api/src/damnit_api/main.py b/api/src/damnit_api/main.py index 782e891..16ff12d 100644 --- a/api/src/damnit_api/main.py +++ b/api/src/damnit_api/main.py @@ -76,6 +76,11 @@ async def http_exception_handler(request: Request, exc: HTTPException): logger.info("Starting uvicorn with settings", **settings.uvicorn.model_dump()) + if settings.uvicorn.ssl_cert_reqs != 2: + logger.warning( + "Not configured to require mTLS. This is not recommended for production." + ) + uvicorn.run( "damnit_api.main:create_app", **settings.uvicorn.model_dump(), diff --git a/api/src/damnit_api/settings.py b/api/src/damnit_api/settings.py index 87540b9..6a8b206 100644 --- a/api/src/damnit_api/settings.py +++ b/api/src/damnit_api/settings.py @@ -8,6 +8,7 @@ SecretStr, UrlConstraints, field_validator, + model_validator, ) from pydantic_settings import BaseSettings, SettingsConfigDict @@ -24,6 +25,25 @@ class UvicornSettings(BaseModel): reload: bool = True factory: bool = True + ssl_keyfile: Path | None = None + ssl_certfile: Path | None = None + ssl_ca_certs: Path | None = None + ssl_cert_reqs: int | None = None + + @model_validator(mode="after") + def ssl_all_if_one(self): + """Ensure all SSL settings are set if one is set.""" + files = [self.ssl_keyfile, self.ssl_certfile, self.ssl_ca_certs] + if any(files) and not all(files): + msg = "ssl_keyfile, ssl_certfile, and ssl_ca_certs must all be set" + raise ValueError(msg) + + if all(files): + # Default to 2 (require mTLS) if any SSL settings are set + self.ssl_cert_reqs = self.ssl_cert_reqs or 2 + + return self + @field_validator("factory", mode="after") @classmethod def factory_must_be_true(cls, v, values): From a6061e30764007c66dce8c514aa6976ef5094d74 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:20:28 +0100 Subject: [PATCH 04/27] deploy(api): userns_mode should be host not keep-id --- api/compose.dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/compose.dev.yml b/api/compose.dev.yml index f3cdc30..9959a51 100644 --- a/api/compose.dev.yml +++ b/api/compose.dev.yml @@ -2,7 +2,7 @@ name: damnit-web-dev services: api: - userns_mode: keep-id + userns_mode: host ports: - 8123:8000 volumes: From ac9122bb6207a9b8a806471696e43f4695d1d778 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:28:27 +0100 Subject: [PATCH 05/27] deploy(api/mtls): mount certs directory into container --- api/compose.dev.yml | 1 + api/compose.yml | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/api/compose.dev.yml b/api/compose.dev.yml index 9959a51..380d31b 100644 --- a/api/compose.dev.yml +++ b/api/compose.dev.yml @@ -6,6 +6,7 @@ services: ports: - 8123:8000 volumes: + - ./certs:./certs - /gpfs/exfel/data/scratch/xdana/tmp/damnit-web:/var/tmp - /gpfs:/gpfs - /pnfs:/pnfs diff --git a/api/compose.yml b/api/compose.yml index 57b7c52..359b1d8 100644 --- a/api/compose.yml +++ b/api/compose.yml @@ -7,5 +7,10 @@ services: - .env ports: - 8000 + environment: + DW_API_MTLS__CLIENT_CERT: /certs/server.crt + DW_API_MTLS__CLIENT_KEY: /certs/server.key + DW_API_MTLS__ROOT_CERT: /certs/root_ca.crt volumes: - ./tmp-damnit-web/:/tmp/damnit-web/ + - ./certs:/certs From c4d9040dfbffa62f82331370871992124c00c177 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:31:39 +0100 Subject: [PATCH 06/27] feat(frontend/mtls): configure mtls by settings proxy options.agent --- frontend/vite.config.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 0d01afc..8463d5c 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -2,6 +2,7 @@ import { defineConfig, loadEnv } from "vite" import path from "path" import react from "@vitejs/plugin-react" import fs from "fs" +import https from 'https'; export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd()) @@ -25,9 +26,14 @@ export default defineConfig(({ mode }) => { const createProxyConfig = (endpoint) => ({ target: `https://${env.VITE_BACKEND_API}`, changeOrigin: false, - secure: sslConfig ? true : false, - ssl: sslConfig, rewrite: (path) => path.replace(new RegExp(`^${baseUrl}`), "/"), + secure: sslConfig ? true : false, + configure: (proxy, _options) => { + if (sslConfig) { + const httpsAgent = new https.Agent(sslConfig); + _options.agent = httpsAgent; + } + }, }) return { From 72d1b7f8b67dbd7e139709ad10b7e5cc0bd734f7 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:19:03 +0100 Subject: [PATCH 07/27] deploy(api): explicitly map host/container port --- api/compose.yml | 2 +- frontend/vite.config.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/compose.yml b/api/compose.yml index 359b1d8..ddbfbb6 100644 --- a/api/compose.yml +++ b/api/compose.yml @@ -6,7 +6,7 @@ services: env_file: - .env ports: - - 8000 + - 8000:8000 environment: DW_API_MTLS__CLIENT_CERT: /certs/server.crt DW_API_MTLS__CLIENT_KEY: /certs/server.key diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 8463d5c..066a093 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -47,9 +47,9 @@ export default defineConfig(({ mode }) => { host: true, port: Number(env.VITE_PORT) || 5173, proxy: { - [`${baseUrl}graphql`]: createProxyConfig('graphql'), - [`${baseUrl}oauth`]: createProxyConfig('oauth'), - [`${baseUrl}metadata`]: createProxyConfig('metadata'), + [`${baseUrl}graphql`]: createProxyConfig({ws: true}), + [`${baseUrl}oauth`]: createProxyConfig(), + [`${baseUrl}metadata`]: createProxyConfig(), }, }, test: { From 36c02e588e448d1bfa5e8301238cc214117b008a Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Fri, 1 Nov 2024 06:20:04 +0100 Subject: [PATCH 08/27] chore: add mtls files to gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 26f3b6e..d85f138 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ .vscode damnit_proposals.json +certs/ +*.crt +*.key +*.pem \ No newline at end of file From f9d9e97fde698190b4cdbadddfce7710c95e18b5 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Tue, 5 Nov 2024 06:35:48 +0100 Subject: [PATCH 09/27] build(api): start via python module call not uvicorn --- api/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/Dockerfile b/api/Dockerfile index 3b91d8c..7bb98df 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -31,4 +31,4 @@ COPY ./README.md ./README.md EXPOSE 8000 -CMD ["poetry", "run", "uvicorn", "damnit_api.main:app", "--host", "0.0.0.0", "--port", "8000"] +CMD ["poetry", "run", "python3", "-m", "damnit_api.main"] From 6cc972db535ba233368a843376be1ff04e3120e9 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Tue, 5 Nov 2024 06:36:39 +0100 Subject: [PATCH 10/27] build(api): fix certs mount target --- api/compose.dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/compose.dev.yml b/api/compose.dev.yml index 380d31b..ed1c7e3 100644 --- a/api/compose.dev.yml +++ b/api/compose.dev.yml @@ -6,7 +6,7 @@ services: ports: - 8123:8000 volumes: - - ./certs:./certs + - ./certs:/certs - /gpfs/exfel/data/scratch/xdana/tmp/damnit-web:/var/tmp - /gpfs:/gpfs - /pnfs:/pnfs From 58ee7376e048ee805ec1bb99103a7e5c7120cb11 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Tue, 5 Nov 2024 06:41:00 +0100 Subject: [PATCH 11/27] fix(frontend): apply override proxy configs previously websockets true flag was ignored --- frontend/vite.config.ts | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 066a093..233bac8 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -23,18 +23,22 @@ export default defineConfig(({ mode }) => { } } - const createProxyConfig = (endpoint) => ({ - target: `https://${env.VITE_BACKEND_API}`, - changeOrigin: false, - rewrite: (path) => path.replace(new RegExp(`^${baseUrl}`), "/"), - secure: sslConfig ? true : false, - configure: (proxy, _options) => { - if (sslConfig) { - const httpsAgent = new https.Agent(sslConfig); - _options.agent = httpsAgent; - } - }, - }) + function createProxyConfig(overrides){ + const defaults = { + target: `https://${env.VITE_BACKEND_API}`, + changeOrigin: false, + rewrite: (path) => path.replace(new RegExp(`^${baseUrl}`), "/"), + secure: sslConfig ? true : false, + configure: (proxy, _options) => { + if (sslConfig) { + const httpsAgent = new https.Agent(sslConfig); + _options.agent = httpsAgent; + } + }, + } + + return {...defaults, ...overrides} + } return { base: baseUrl, @@ -48,8 +52,8 @@ export default defineConfig(({ mode }) => { port: Number(env.VITE_PORT) || 5173, proxy: { [`${baseUrl}graphql`]: createProxyConfig({ws: true}), - [`${baseUrl}oauth`]: createProxyConfig(), - [`${baseUrl}metadata`]: createProxyConfig(), + [`${baseUrl}oauth`]: createProxyConfig({}), + [`${baseUrl}metadata`]: createProxyConfig({}), }, }, test: { From 7ae418fe3149b4c31cab716f39c70454e2726bbf Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Tue, 5 Nov 2024 09:34:56 +0100 Subject: [PATCH 12/27] deploy(frontend): set node extra ca certs env var for mtls, mount certs dir --- frontend/compose.dev.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/compose.dev.yml b/frontend/compose.dev.yml index 19a0015..370ac87 100644 --- a/frontend/compose.dev.yml +++ b/frontend/compose.dev.yml @@ -6,6 +6,10 @@ networks: services: frontend: + environment: + - NODE_EXTRA_CA_CERTS=/certs/root_ca.crt + volumes: + - ./certs:/certs networks: - proxy labels: From 40189164d44f25489c0f9abcd64afc7820af0daf Mon Sep 17 00:00:00 2001 From: Cammille Carinan Date: Thu, 14 Nov 2024 17:22:04 +0100 Subject: [PATCH 13/27] build: update poetry.lock file --- api/poetry.lock | 85 ++----------------------------------------------- 1 file changed, 3 insertions(+), 82 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index 69f0550..c3a6345 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -38,7 +38,6 @@ files = [ ] [package.dependencies] -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" @@ -58,9 +57,6 @@ files = [ {file = "async_lru-2.0.4-py3-none-any.whl", hash = "sha256:ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} - [[package]] name = "authlib" version = "1.3.2" @@ -437,20 +433,6 @@ files = [ docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] tests = ["pytest", "pytest-cov", "pytest-xdist"] -[[package]] -name = "exceptiongroup" -version = "1.2.2" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, -] - -[package.extras] -test = ["pytest (>=6)"] - [[package]] name = "fastapi" version = "0.104.1" @@ -796,28 +778,6 @@ files = [ [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] -[[package]] -name = "importlib-resources" -version = "6.4.5" -description = "Read resources from Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717"}, - {file = "importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065"}, -] - -[package.dependencies] -zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] -type = ["pytest-mypy"] - [[package]] name = "iniconfig" version = "2.0.0" @@ -1094,7 +1054,6 @@ files = [ contourpy = ">=1.0.1" cycler = ">=0.10" fonttools = ">=4.22.0" -importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} kiwisolver = ">=1.3.1" numpy = ">=1.23" packaging = ">=20.0" @@ -1301,11 +1260,7 @@ files = [ ] [package.dependencies] -numpy = [ - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, - {version = ">=1.22.4", markers = "python_version < \"3.11\""}, - {version = ">=1.23.2", markers = "python_version == \"3.11\""}, -] +numpy = {version = ">=1.26.0", markers = "python_version >= \"3.12\""} python-dateutil = ">=2.8.2" pytz = ">=2020.1" tzdata = ">=2022.7" @@ -1674,11 +1629,9 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] @@ -2074,7 +2027,6 @@ files = [ [package.dependencies] anyio = ">=3.4.0,<5" -typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} [package.extras] full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyaml"] @@ -2137,17 +2089,6 @@ docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphi tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] typing = ["mypy (>=1.4)", "rich", "twisted"] -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - [[package]] name = "typer" version = "0.12.5" @@ -2222,7 +2163,6 @@ h11 = ">=0.8" httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} -typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} @@ -2464,26 +2404,7 @@ files = [ {file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"}, ] -[[package]] -name = "zipp" -version = "3.20.2" -description = "Backport of pathlib-compatible object wrapper for zip files" -optional = false -python-versions = ">=3.8" -files = [ - {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, - {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, -] - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] -type = ["pytest-mypy"] - [metadata] lock-version = "2.0" -python-versions = "^3.9" -content-hash = "1b04d19cf36c5332efcd1946e0b7d0e6b9dc157f6908fdd6fccf392c0d2268f3" +python-versions = "^3.12" +content-hash = "52cc0d52a785920625a96b4b10a94bea35da65f842c1e3d5c6ed3e7a8d52d82b" From c6dcf33158af4eae8620c83ad9810d3eb7d404b5 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Fri, 6 Dec 2024 14:05:28 +0100 Subject: [PATCH 14/27] style(frontend): run prettier auto-format --- frontend/vite.config.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 233bac8..331cae2 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -2,7 +2,7 @@ import { defineConfig, loadEnv } from "vite" import path from "path" import react from "@vitejs/plugin-react" import fs from "fs" -import https from 'https'; +import https from "https" export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd()) @@ -14,7 +14,11 @@ export default defineConfig(({ mode }) => { const certPath = path.resolve(__dirname, env.VITE_MTLS_CLIENT) const caPath = path.resolve(__dirname, env.VITE_MTLS_CA) - if (fs.existsSync(keyPath) && fs.existsSync(certPath) && fs.existsSync(caPath)) { + if ( + fs.existsSync(keyPath) && + fs.existsSync(certPath) && + fs.existsSync(caPath) + ) { sslConfig = { key: fs.readFileSync(keyPath), cert: fs.readFileSync(certPath), @@ -23,7 +27,7 @@ export default defineConfig(({ mode }) => { } } - function createProxyConfig(overrides){ + function createProxyConfig(overrides) { const defaults = { target: `https://${env.VITE_BACKEND_API}`, changeOrigin: false, @@ -31,13 +35,13 @@ export default defineConfig(({ mode }) => { secure: sslConfig ? true : false, configure: (proxy, _options) => { if (sslConfig) { - const httpsAgent = new https.Agent(sslConfig); - _options.agent = httpsAgent; + const httpsAgent = new https.Agent(sslConfig) + _options.agent = httpsAgent } }, } - return {...defaults, ...overrides} + return { ...defaults, ...overrides } } return { @@ -51,7 +55,7 @@ export default defineConfig(({ mode }) => { host: true, port: Number(env.VITE_PORT) || 5173, proxy: { - [`${baseUrl}graphql`]: createProxyConfig({ws: true}), + [`${baseUrl}graphql`]: createProxyConfig({ ws: true }), [`${baseUrl}oauth`]: createProxyConfig({}), [`${baseUrl}metadata`]: createProxyConfig({}), }, From 36c1b8774e40913dfa4c38af26af179fe838ce48 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:36:16 +0100 Subject: [PATCH 15/27] refactor(frontend/config): rename variables --- frontend/vite.config.ts | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 331cae2..5215229 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -6,13 +6,20 @@ import https from "https" export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd()) - const baseUrl = (env.VITE_BASE_URL || "/").replace(/\/?$/, "/") + const { + VITE_BACKEND_API, + VITE_BASE_URL, + VITE_MTLS_CA, + VITE_MTLS_CLIENT, + VITE_MTLS_KEY, + VITE_PORT, + } = env let sslConfig = null - if (env.VITE_MTLS_KEY && env.VITE_MTLS_CLIENT && env.VITE_MTLS_CA) { - const keyPath = path.resolve(__dirname, env.VITE_MTLS_KEY) - const certPath = path.resolve(__dirname, env.VITE_MTLS_CLIENT) - const caPath = path.resolve(__dirname, env.VITE_MTLS_CA) + if (VITE_MTLS_KEY && VITE_MTLS_CLIENT && VITE_MTLS_CA) { + const keyPath = path.resolve(__dirname, VITE_MTLS_KEY) + const certPath = path.resolve(__dirname, VITE_MTLS_CLIENT) + const caPath = path.resolve(__dirname, VITE_MTLS_CA) if ( fs.existsSync(keyPath) && @@ -27,9 +34,11 @@ export default defineConfig(({ mode }) => { } } + const baseUrl = (VITE_BASE_URL || "/").replace(/\/?$/, "/") + function createProxyConfig(overrides) { const defaults = { - target: `https://${env.VITE_BACKEND_API}`, + target: `https://${VITE_BACKEND_API}`, changeOrigin: false, rewrite: (path) => path.replace(new RegExp(`^${baseUrl}`), "/"), secure: sslConfig ? true : false, @@ -53,7 +62,7 @@ export default defineConfig(({ mode }) => { // REMOVEME: Use proxy to handle CORS for the meantime server: { host: true, - port: Number(env.VITE_PORT) || 5173, + port: Number(VITE_PORT) || 5173, proxy: { [`${baseUrl}graphql`]: createProxyConfig({ ws: true }), [`${baseUrl}oauth`]: createProxyConfig({}), From 8f1b402c444772f70a673431caef9ed049f2b4a2 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:49:27 +0100 Subject: [PATCH 16/27] refactor(frontend/config): remove need for ssl config function, throw errors --- frontend/vite.config.ts | 42 ++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 5215229..5513bba 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -10,31 +10,36 @@ export default defineConfig(({ mode }) => { VITE_BACKEND_API, VITE_BASE_URL, VITE_MTLS_CA, - VITE_MTLS_CLIENT, + VITE_MTLS_CERT, VITE_MTLS_KEY, VITE_PORT, } = env - let sslConfig = null - if (VITE_MTLS_KEY && VITE_MTLS_CLIENT && VITE_MTLS_CA) { - const keyPath = path.resolve(__dirname, VITE_MTLS_KEY) - const certPath = path.resolve(__dirname, VITE_MTLS_CLIENT) - const caPath = path.resolve(__dirname, VITE_MTLS_CA) + const baseUrl = (VITE_BASE_URL || "/").replace(/\/?$/, "/") - if ( - fs.existsSync(keyPath) && - fs.existsSync(certPath) && - fs.existsSync(caPath) - ) { - sslConfig = { - key: fs.readFileSync(keyPath), - cert: fs.readFileSync(certPath), - ca: fs.readFileSync(caPath), - } - } + const mtlsAll = Boolean(VITE_MTLS_KEY && VITE_MTLS_CERT && VITE_MTLS_CA) + const mtlsAny = Boolean(VITE_MTLS_KEY || VITE_MTLS_CERT || VITE_MTLS_CA) + + if (mtlsAny && !mtlsAll) { + throw new Error("mTLS configuration requires all of key, cert, and ca") } - const baseUrl = (VITE_BASE_URL || "/").replace(/\/?$/, "/") + const mtlsEnabled = mtlsAll + + const sslConfig = mtlsEnabled + ? { + key: fs.readFileSync(path.resolve(__dirname, VITE_MTLS_KEY)), + cert: fs.readFileSync(path.resolve(__dirname, VITE_MTLS_CERT)), + ca: fs.readFileSync(path.resolve(__dirname, VITE_MTLS_CA)), + } + : null + + const httpsAgent = sslConfig ? new https.Agent(sslConfig) : null + + // If the API server is HTTPS, mTLS configuration is required + if (VITE_BACKEND_API.startsWith("https:") && !sslConfig) { + throw new Error("HTTPS API requires mTLS configuration") + } function createProxyConfig(overrides) { const defaults = { @@ -44,7 +49,6 @@ export default defineConfig(({ mode }) => { secure: sslConfig ? true : false, configure: (proxy, _options) => { if (sslConfig) { - const httpsAgent = new https.Agent(sslConfig) _options.agent = httpsAgent } }, From 4e19f3db7177e07450587d7149768d4f0a09db0b Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:54:54 +0100 Subject: [PATCH 17/27] refactor(frontend/config): simplify mTLS config check --- frontend/vite.config.ts | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 5513bba..5236afd 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -17,23 +17,17 @@ export default defineConfig(({ mode }) => { const baseUrl = (VITE_BASE_URL || "/").replace(/\/?$/, "/") - const mtlsAll = Boolean(VITE_MTLS_KEY && VITE_MTLS_CERT && VITE_MTLS_CA) - const mtlsAny = Boolean(VITE_MTLS_KEY || VITE_MTLS_CERT || VITE_MTLS_CA) - - if (mtlsAny && !mtlsAll) { + let sslConfig = null + if (VITE_MTLS_KEY && VITE_MTLS_CERT && VITE_MTLS_CA) { + sslConfig = { + key: fs.readFileSync(path.resolve(__dirname, VITE_MTLS_KEY)), + cert: fs.readFileSync(path.resolve(__dirname, VITE_MTLS_CERT)), + ca: fs.readFileSync(path.resolve(__dirname, VITE_MTLS_CA)), + } + } else if (VITE_MTLS_KEY || VITE_MTLS_CERT || VITE_MTLS_CA) { throw new Error("mTLS configuration requires all of key, cert, and ca") } - const mtlsEnabled = mtlsAll - - const sslConfig = mtlsEnabled - ? { - key: fs.readFileSync(path.resolve(__dirname, VITE_MTLS_KEY)), - cert: fs.readFileSync(path.resolve(__dirname, VITE_MTLS_CERT)), - ca: fs.readFileSync(path.resolve(__dirname, VITE_MTLS_CA)), - } - : null - const httpsAgent = sslConfig ? new https.Agent(sslConfig) : null // If the API server is HTTPS, mTLS configuration is required From bcb42eb9a3a1a27ce8f3a03aa4dccc0fa01be6ca Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:55:34 +0100 Subject: [PATCH 18/27] refactor(frontend/config): set httpsAgent to undefined instead of null --- frontend/vite.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 5236afd..f4abbca 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -28,7 +28,7 @@ export default defineConfig(({ mode }) => { throw new Error("mTLS configuration requires all of key, cert, and ca") } - const httpsAgent = sslConfig ? new https.Agent(sslConfig) : null + const httpsAgent = sslConfig ? new https.Agent(sslConfig) : undefined // If the API server is HTTPS, mTLS configuration is required if (VITE_BACKEND_API.startsWith("https:") && !sslConfig) { From 7714480125041e6a2e0f71b6278066ba6fcdf1f0 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:57:17 +0100 Subject: [PATCH 19/27] refactor(frontend/config): simplify defaultProxyConfig assignment --- frontend/vite.config.ts | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index f4abbca..f8236dd 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -35,20 +35,15 @@ export default defineConfig(({ mode }) => { throw new Error("HTTPS API requires mTLS configuration") } - function createProxyConfig(overrides) { - const defaults = { - target: `https://${VITE_BACKEND_API}`, - changeOrigin: false, - rewrite: (path) => path.replace(new RegExp(`^${baseUrl}`), "/"), - secure: sslConfig ? true : false, - configure: (proxy, _options) => { - if (sslConfig) { - _options.agent = httpsAgent - } - }, - } - - return { ...defaults, ...overrides } + const defaultProxyConfig = { + target: VITE_BACKEND_API, + secure: !!sslConfig, + changeOrigin: false, + configure: (proxy: any, options: { agent?: https.Agent }) => { + if (sslConfig) { + options.agent = httpsAgent + } + }, } return { @@ -62,9 +57,9 @@ export default defineConfig(({ mode }) => { host: true, port: Number(VITE_PORT) || 5173, proxy: { - [`${baseUrl}graphql`]: createProxyConfig({ ws: true }), - [`${baseUrl}oauth`]: createProxyConfig({}), - [`${baseUrl}metadata`]: createProxyConfig({}), + [`${baseUrl}graphql`]: { ...defaultProxyConfig, ws: true }, + [`${baseUrl}oauth`]: { ...defaultProxyConfig }, + [`${baseUrl}metadata`]: { ...defaultProxyConfig }, }, }, test: { From 4c32dcbeca40e2ce59c69ed5d5d113e39fb9516c Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:57:38 +0100 Subject: [PATCH 20/27] refactor(frontend/config): explode all proxy configs for consistency --- frontend/vite.config.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index f8236dd..a490906 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -57,9 +57,9 @@ export default defineConfig(({ mode }) => { host: true, port: Number(VITE_PORT) || 5173, proxy: { - [`${baseUrl}graphql`]: { ...defaultProxyConfig, ws: true }, - [`${baseUrl}oauth`]: { ...defaultProxyConfig }, - [`${baseUrl}metadata`]: { ...defaultProxyConfig }, + "/graphql": { ...defaultProxyConfig, ws: true }, + "/oauth": { ...defaultProxyConfig }, + "/metadata": { ...defaultProxyConfig }, }, }, test: { From 515d3b0bf90af3cfac4bde8e862fb84eaa007fdd Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:28:31 +0100 Subject: [PATCH 21/27] feat(frontend/config): exit early if url/api url missing --- frontend/vite.config.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index a490906..aba67c8 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -15,6 +15,12 @@ export default defineConfig(({ mode }) => { VITE_PORT, } = env + if (!VITE_BASE_URL || !VITE_BACKEND_API) { + throw new Error( + "Missing required environment variables: VITE_URL and/or VITE_API", + ) + } + const baseUrl = (VITE_BASE_URL || "/").replace(/\/?$/, "/") let sslConfig = null From a7881fd7b931bb6aebb317d01c591c9582eff06b Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:30:24 +0100 Subject: [PATCH 22/27] feat(frontend/config): simplify some checks, better errors/comments --- frontend/vite.config.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index aba67c8..a95162b 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,6 +1,6 @@ import { defineConfig, loadEnv } from "vite" -import path from "path" import react from "@vitejs/plugin-react" +import path from "path" import fs from "fs" import https from "https" @@ -23,7 +23,7 @@ export default defineConfig(({ mode }) => { const baseUrl = (VITE_BASE_URL || "/").replace(/\/?$/, "/") - let sslConfig = null + let sslConfig if (VITE_MTLS_KEY && VITE_MTLS_CERT && VITE_MTLS_CA) { sslConfig = { key: fs.readFileSync(path.resolve(__dirname, VITE_MTLS_KEY)), @@ -31,7 +31,10 @@ export default defineConfig(({ mode }) => { ca: fs.readFileSync(path.resolve(__dirname, VITE_MTLS_CA)), } } else if (VITE_MTLS_KEY || VITE_MTLS_CERT || VITE_MTLS_CA) { - throw new Error("mTLS configuration requires all of key, cert, and ca") + // If partial mTLS variables are set, that's invalid. + throw new Error( + "mTLS configuration is incomplete. Please provide all three: key, cert, and ca.", + ) } const httpsAgent = sslConfig ? new https.Agent(sslConfig) : undefined @@ -45,7 +48,7 @@ export default defineConfig(({ mode }) => { target: VITE_BACKEND_API, secure: !!sslConfig, changeOrigin: false, - configure: (proxy: any, options: { agent?: https.Agent }) => { + configure: (proxy, options) => { if (sslConfig) { options.agent = httpsAgent } @@ -58,7 +61,6 @@ export default defineConfig(({ mode }) => { build: { outDir: "build", }, - // REMOVEME: Use proxy to handle CORS for the meantime server: { host: true, port: Number(VITE_PORT) || 5173, From ea4c8c88a2e0285183fa939b6b8c2158a759386e Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:13:44 +0100 Subject: [PATCH 23/27] refactor(frontend/config): use URL object for API/URL --- frontend/vite.config.ts | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index a95162b..1d6af07 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -6,22 +6,18 @@ import https from "https" export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd()) - const { - VITE_BACKEND_API, - VITE_BASE_URL, - VITE_MTLS_CA, - VITE_MTLS_CERT, - VITE_MTLS_KEY, - VITE_PORT, - } = env - if (!VITE_BASE_URL || !VITE_BACKEND_API) { + const { VITE_MTLS_KEY, VITE_MTLS_CERT, VITE_MTLS_CA, VITE_URL, VITE_API } = + env + + if (!VITE_URL || !VITE_API) { throw new Error( "Missing required environment variables: VITE_URL and/or VITE_API", ) } - const baseUrl = (VITE_BASE_URL || "/").replace(/\/?$/, "/") + const baseURL = new URL(VITE_URL) + const apiURL = new URL(VITE_API) let sslConfig if (VITE_MTLS_KEY && VITE_MTLS_CERT && VITE_MTLS_CA) { @@ -40,12 +36,12 @@ export default defineConfig(({ mode }) => { const httpsAgent = sslConfig ? new https.Agent(sslConfig) : undefined // If the API server is HTTPS, mTLS configuration is required - if (VITE_BACKEND_API.startsWith("https:") && !sslConfig) { + if (apiURL.protocol === "https:" && !sslConfig) { throw new Error("HTTPS API requires mTLS configuration") } const defaultProxyConfig = { - target: VITE_BACKEND_API, + target: apiURL.origin, secure: !!sslConfig, changeOrigin: false, configure: (proxy, options) => { @@ -56,14 +52,14 @@ export default defineConfig(({ mode }) => { } return { - base: baseUrl, + base: baseURL.href, plugins: [react()], build: { outDir: "build", }, server: { host: true, - port: Number(VITE_PORT) || 5173, + port: baseURL.port ? Number(baseURL.port) : 5173, proxy: { "/graphql": { ...defaultProxyConfig, ws: true }, "/oauth": { ...defaultProxyConfig }, From be4620fd695cb5a0946b8eb083a4a05f7fc8ea4d Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:16:25 +0100 Subject: [PATCH 24/27] feat(refactor/config): reuse mtls config for https --- frontend/vite.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 1d6af07..2453b68 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -65,6 +65,7 @@ export default defineConfig(({ mode }) => { "/oauth": { ...defaultProxyConfig }, "/metadata": { ...defaultProxyConfig }, }, + https: sslConfig, }, test: { globals: true, From 5448d097147baea7201275bc1cd12ac30acea0e8 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Fri, 13 Dec 2024 12:41:37 +0100 Subject: [PATCH 25/27] fix(api/settings): update env var names Co-authored-by: Cammille Carinan --- api/compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/compose.yml b/api/compose.yml index ddbfbb6..64b566e 100644 --- a/api/compose.yml +++ b/api/compose.yml @@ -8,9 +8,9 @@ services: ports: - 8000:8000 environment: - DW_API_MTLS__CLIENT_CERT: /certs/server.crt - DW_API_MTLS__CLIENT_KEY: /certs/server.key - DW_API_MTLS__ROOT_CERT: /certs/root_ca.crt + DW_API_UVICORN__SSL_CERTFILE: /certs/server.crt + DW_API_UVICORN__SSL_KEYFILE: /certs/server.key + DW_API_UVICORN__SSL_CA_CERTS: /certs/root_ca.crt volumes: - ./tmp-damnit-web/:/tmp/damnit-web/ - ./certs:/certs From 52b04fc78cf9bd5b61424bb21927837269eae663 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Fri, 13 Dec 2024 12:38:21 +0100 Subject: [PATCH 26/27] chore(api/settings): use UTC timezone --- api/src/damnit_api/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/damnit_api/settings.py b/api/src/damnit_api/settings.py index 6a8b206..5136032 100644 --- a/api/src/damnit_api/settings.py +++ b/api/src/damnit_api/settings.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime from pathlib import Path from typing import Annotated @@ -72,7 +72,7 @@ class MyMdCCredentials(BaseSettings): base_url: HttpUrl _access_token: str = "" - _expires_at: datetime = datetime.fromisocalendar(1970, 1, 1).astimezone(timezone.utc) + _expires_at: datetime = datetime.fromisocalendar(1970, 1, 1).astimezone(UTC) class Settings(BaseSettings): From d2ab49964e4797e97c2577043e8881094ee798b7 Mon Sep 17 00:00:00 2001 From: Robert Rosca <32569096+RobertRosca@users.noreply.github.com> Date: Fri, 13 Dec 2024 12:46:01 +0100 Subject: [PATCH 27/27] chore(api/settings): use FilePath for cert config Ensures that the file exists --- api/src/damnit_api/settings.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/api/src/damnit_api/settings.py b/api/src/damnit_api/settings.py index 5136032..aeb52b1 100644 --- a/api/src/damnit_api/settings.py +++ b/api/src/damnit_api/settings.py @@ -4,6 +4,7 @@ from pydantic import ( BaseModel, + FilePath, HttpUrl, SecretStr, UrlConstraints, @@ -25,9 +26,9 @@ class UvicornSettings(BaseModel): reload: bool = True factory: bool = True - ssl_keyfile: Path | None = None - ssl_certfile: Path | None = None - ssl_ca_certs: Path | None = None + ssl_keyfile: FilePath | None = None + ssl_certfile: FilePath | None = None + ssl_ca_certs: FilePath | None = None ssl_cert_reqs: int | None = None @model_validator(mode="after")