From afbbcbc22dac4072fa6629e6f183b5b4612d67da Mon Sep 17 00:00:00 2001
From: Valentin Gagarin <valentin.gagarin@tweag.io>
Date: Wed, 19 Mar 2025 10:06:38 +0100
Subject: [PATCH] simplify configuration via environment

---
 panel/default.nix           |  7 ++++---
 panel/src/panel/settings.py | 30 +++++++++++++++++-------------
 2 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/panel/default.nix b/panel/default.nix
index a2ce856c..8179edb5 100644
--- a/panel/default.nix
+++ b/panel/default.nix
@@ -23,14 +23,15 @@ in
       NPINS_DIRECTORY = toString ../npins;
       # explicitly use nix, as e.g. lix does not have configurable-impure-env
       NIX_DIR = pkgs.nix;
+      REPO_DIR = toString ../.;
+      CREDENTIALS_DIRECTORY = builtins.toString ./.credentials;
+      DATABASE_URL = "sqlite:///${toString ./src}/db.sqlite3";
     };
     shellHook = ''
       # in production, secrets are passed via CREDENTIALS_DIRECTORY by systemd.
       # use this directory for testing with local secrets
-      mkdir -p .credentials
+      mkdir -p $CREDENTIALS_DIRECTORY
       echo secret > ${builtins.toString ./.credentials}/SECRET_KEY
-      export CREDENTIALS_DIRECTORY=${builtins.toString ./.credentials}
-      export DATABASE_URL="sqlite:///${toString ./src}/db.sqlite3"
     '';
   };
 
diff --git a/panel/src/panel/settings.py b/panel/src/panel/settings.py
index f289b0fc..4ca359c6 100644
--- a/panel/src/panel/settings.py
+++ b/panel/src/panel/settings.py
@@ -173,22 +173,26 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
 
 # Customization via user settings
 # This must be at the end, as it must be able to override the above
-# TODO: we may want to do this with a flat environment instead, and get all values from `os.environ.get()`.
-#       this would make it more obvious which moving parts there are, if that environment is specified for development/staging/production in a visible place.
-user_settings_file = env.get("USER_SETTINGS_FILE", None)
-if user_settings_file is not None:
-    spec = importlib.util.spec_from_file_location("user_settings", user_settings_file)
-    if spec is None or spec.loader is None:
-        raise RuntimeError("User settings specification failed!")
-    module = importlib.util.module_from_spec(spec)
-    spec.loader.exec_module(module)
-    sys.modules["user_settings"] = module
-    from user_settings import *  # noqa: F403 # pyright: ignore [reportMissingImports]
+# TODO(@fricklerhandwerk):
+#     we may want to do this with a flat environment instead, and get all values from `os.environ.get()`.
+#     this would make it more obvious which moving parts there are, if that environment is specified for development/staging/production in a visible place.
+user_settings_file = env["USER_SETTINGS_FILE"]
+spec = importlib.util.spec_from_file_location("user_settings", user_settings_file)
+if spec is None or spec.loader is None:
+    raise RuntimeError("User settings specification failed!")
+module = importlib.util.module_from_spec(spec)
+spec.loader.exec_module(module)
+sys.modules["user_settings"] = module
+from user_settings import *  # noqa: F403 # pyright: ignore [reportMissingImports]
 
 # non-Django application settings
 
+# TODO(@fricklerhandwerk):
+#     The correct thing to do here would be using a helper function such as with `get_secret()` that will catch the exception and explain what's wrong and where to put the right values.
+#     Replacing the `USER_SETTINGS_FILE` mechanism following the comment there would probably be a good thing.
+
 # a dir of nix supporting experimental feature `configurable-impure-env`.
-nix_bin_dir=f"{env.get("NIX_DIR")}/bin/"
+nix_bin_dir=f"{env['NIX_DIR']}/bin/"
 # path of the root flake to trigger nixops from, see #94.
 # to deploy this should be specified, for dev just use a relative path.
-repo_dir = env.get("REPO_DIR") or f"{os.getcwd()}/.."
+repo_dir = env["REPO_DIR"]