This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git


The following commit(s) were added to refs/heads/main by this push:
     new f38dac1  Add a migration to use a curated secrets state subdirectory
f38dac1 is described below

commit f38dac136f5e48dffd44d090bb6fcc20fa94a9fb
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon Jan 19 18:55:58 2026 +0000

    Add a migration to use a curated secrets state subdirectory
---
 atr/config.py | 51 ++++++++++++++++++++++++++++++++++-----------------
 atr/server.py |  3 +++
 2 files changed, 37 insertions(+), 17 deletions(-)

diff --git a/atr/config.py b/atr/config.py
index 4430757..3ef06c3 100644
--- a/atr/config.py
+++ b/atr/config.py
@@ -28,26 +28,43 @@ _RAT_VERSION: Final = "0.17"
 
 
 def _config_secrets(key: str, state_dir: str, default: str | None = None, 
cast: type = str) -> str | None:
-    secrets_path = os.path.join(state_dir, "secrets.ini")
+    secrets_path = os.path.join(state_dir, "secrets", "curated", "secrets.ini")
+
+    # This code is deprecated and will be removed
+    # TODO: Remove this once migrations are no longer likely2026-
+    deprecated_path = os.path.join(state_dir, "secrets.ini")
+    if os.path.exists(deprecated_path):
+        if os.path.exists(secrets_path):
+            raise RuntimeError(f"Conflicting secrets files exist: 
{deprecated_path} and {secrets_path}")
+        return _config_secrets_get(deprecated_path, key, default, cast, 
allow_not_found=False)
+
+    return _config_secrets_get(secrets_path, key, default, cast)
+
+
+def _config_secrets_get(
+    secrets_path: str, key: str, default: str | None = None, cast: type = str, 
allow_not_found: bool = True
+) -> str | None:
     try:
         repo_ini = decouple.RepositoryIni(secrets_path)
-        config_obj = decouple.Config(repo_ini)
-        sentinel = object()
-        # Using a cast here would also cast the default sentinel value
-        value = config_obj.get(key, default=sentinel)
-        if value is sentinel:
-            if default is None:
-                # We must return None separately because otherwise it may be 
cast
-                return decouple.config(key, default=None)
-            return decouple.config(key, default=default, cast=cast)
-        if isinstance(value, str) or (value is None):
-            return value
-        return None
     except FileNotFoundError:
-        if default is None:
-            # We must return None separately because otherwise it may be cast
-            return decouple.config(key, default=None)
-        return decouple.config(key, default=default, cast=cast)
+        if allow_not_found is False:
+            raise
+    else:
+        if key in repo_ini:
+            value = repo_ini[key]
+            return cast(value)
+
+    # There is no secrets file, or it does not contain the key
+    # Try getting the value from environment variables
+    sentinel = object()
+    # We do not use the cast keyword argument here
+    # If we did, it would also be applied to the default sentinel value
+    value = decouple.config(key, default=sentinel)
+    if value is sentinel:
+        return default
+    if not isinstance(value, str):
+        raise ValueError(f"Secret value for {key} is not a string")
+    return cast(value)
 
 
 class AppConfig:
diff --git a/atr/server.py b/atr/server.py
index 4c96c0a..e960539 100644
--- a/atr/server.py
+++ b/atr/server.py
@@ -78,6 +78,8 @@ _MIGRATIONS: Final[list[tuple[str, str]]] = [
     ("atr-worker-error.log", "logs/atr-worker-error.log"),
     ("keys_import.log", "logs/keys-import.log"),
     ("route-performance.log", "logs/route-performance.log"),
+    # Secrets
+    ("secrets.ini", "secrets/curated/secrets.ini"),
 ]
 
 _SWAGGER_UI_TEMPLATE: Final[str] = """<!DOCTYPE html>
@@ -144,6 +146,7 @@ def _app_dirs_setup(state_dir_str: str, hot_reload: bool) 
-> None:
         pathlib.Path(state_dir_str) / "external",
         pathlib.Path(state_dir_str) / "logs",
         pathlib.Path(state_dir_str) / "runtime",
+        pathlib.Path(state_dir_str) / "secrets" / "curated",
         util.get_downloads_dir(),
         util.get_finished_dir(),
         util.get_tmp_dir(),


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to