fujin-secrets-doppler 0.16.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.3
2
+ Name: fujin-secrets-doppler
3
+ Version: 0.16.0
4
+ Summary: Doppler secret adapter for Fujin
5
+ Author: Tobi
6
+ Author-email: Tobi <tobidegnon@proton.me>
7
+ Classifier: Programming Language :: Python :: 3 :: Only
8
+ Classifier: Programming Language :: Python :: 3.10
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Requires-Dist: fujin-cli>=0.16
14
+ Requires-Dist: python-dotenv>=1.0.1
15
+ Requires-Python: >=3.10
16
+ Project-URL: Homepage, https://github.com/Tobi-De/fujin
17
+ Project-URL: Issues, https://github.com/Tobi-De/fujin/issues
18
+ Project-URL: Source, https://github.com/Tobi-De/fujin
19
+ Description-Content-Type: text/markdown
20
+
21
+ # Fujin Secrets - Doppler
22
+
23
+ Doppler secret adapter for Fujin deployment tool.
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pip install fujin-secrets-doppler
29
+ ```
30
+
31
+ Or with uv:
32
+
33
+ ```bash
34
+ uv pip install fujin-secrets-doppler
35
+ ```
36
+
37
+ ## Prerequisites
38
+
39
+ Download and install the [Doppler CLI](https://docs.doppler.com/docs/cli) and sign in to your account.
40
+
41
+ Move to your project root directory and run `doppler setup` to configure your project.
42
+
43
+ ## Configuration
44
+
45
+ Add the following to your `fujin.toml` file:
46
+
47
+ ```toml
48
+ [secrets]
49
+ adapter = "doppler"
50
+ ```
51
+
52
+ ## Usage
53
+
54
+ In your environment file (`.env` or configured via `envfile` in `fujin.toml`), prefix secret values with `$`:
55
+
56
+ ```env
57
+ DEBUG=False
58
+ AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID
59
+ AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY
60
+ ```
61
+
62
+ The `$` sign indicates to Fujin that it is a secret that should be resolved using the configured adapter.
63
+
64
+ ## How it Works
65
+
66
+ The adapter:
67
+ 1. Uses the Doppler CLI configuration from your project setup
68
+ 2. Resolves all secrets concurrently using `doppler run --command "echo $<name>"`
69
+ 3. Returns the resolved environment variables
70
+
71
+ ## Related
72
+
73
+ - [Fujin Documentation](https://github.com/Tobi-De/fujin)
74
+ - [Doppler CLI Documentation](https://docs.doppler.com/docs/cli)
@@ -0,0 +1,54 @@
1
+ # Fujin Secrets - Doppler
2
+
3
+ Doppler secret adapter for Fujin deployment tool.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install fujin-secrets-doppler
9
+ ```
10
+
11
+ Or with uv:
12
+
13
+ ```bash
14
+ uv pip install fujin-secrets-doppler
15
+ ```
16
+
17
+ ## Prerequisites
18
+
19
+ Download and install the [Doppler CLI](https://docs.doppler.com/docs/cli) and sign in to your account.
20
+
21
+ Move to your project root directory and run `doppler setup` to configure your project.
22
+
23
+ ## Configuration
24
+
25
+ Add the following to your `fujin.toml` file:
26
+
27
+ ```toml
28
+ [secrets]
29
+ adapter = "doppler"
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ In your environment file (`.env` or configured via `envfile` in `fujin.toml`), prefix secret values with `$`:
35
+
36
+ ```env
37
+ DEBUG=False
38
+ AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID
39
+ AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY
40
+ ```
41
+
42
+ The `$` sign indicates to Fujin that it is a secret that should be resolved using the configured adapter.
43
+
44
+ ## How it Works
45
+
46
+ The adapter:
47
+ 1. Uses the Doppler CLI configuration from your project setup
48
+ 2. Resolves all secrets concurrently using `doppler run --command "echo $<name>"`
49
+ 3. Returns the resolved environment variables
50
+
51
+ ## Related
52
+
53
+ - [Fujin Documentation](https://github.com/Tobi-De/fujin)
54
+ - [Doppler CLI Documentation](https://docs.doppler.com/docs/cli)
@@ -0,0 +1,33 @@
1
+ [build-system]
2
+ build-backend = "uv_build"
3
+ requires = [ "uv-build>=0.9.18,<0.10" ]
4
+
5
+ [project]
6
+ name = "fujin-secrets-doppler"
7
+ version = "0.16.0"
8
+ description = "Doppler secret adapter for Fujin"
9
+ readme = "README.md"
10
+ authors = [
11
+ { name = "Tobi", email = "tobidegnon@proton.me" },
12
+ ]
13
+ requires-python = ">=3.10"
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3 :: Only",
16
+ "Programming Language :: Python :: 3.10",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
19
+ "Programming Language :: Python :: 3.13",
20
+ "Programming Language :: Python :: 3.14",
21
+ ]
22
+ dependencies = [
23
+ "fujin-cli>=0.16",
24
+ "python-dotenv>=1.0.1",
25
+ ]
26
+
27
+ urls.Homepage = "https://github.com/Tobi-De/fujin"
28
+ urls.Issues = "https://github.com/Tobi-De/fujin/issues"
29
+ urls.Source = "https://github.com/Tobi-De/fujin"
30
+ entry-points."fujin.secrets".doppler = "fujin_secrets_doppler:doppler"
31
+
32
+ [tool.uv.sources]
33
+ fujin-cli = { workspace = true }
@@ -0,0 +1,96 @@
1
+ """Doppler secret adapter for Fujin."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import subprocess
6
+ from concurrent.futures import ThreadPoolExecutor, as_completed
7
+ from contextlib import closing
8
+ from io import StringIO
9
+
10
+ from dotenv import dotenv_values
11
+ from fujin.config import SecretConfig
12
+ from fujin.errors import SecretResolutionError
13
+
14
+ __version__ = "0.1.0"
15
+
16
+
17
+ def doppler(env_content: str, secret_config: SecretConfig) -> str:
18
+ """Doppler secret adapter.
19
+
20
+ Retrieves secrets from Doppler using the `doppler` CLI.
21
+ Handles concurrent resolution of multiple secrets for performance.
22
+
23
+ Requires `doppler setup` to be run in project root first.
24
+
25
+ Configuration:
26
+ adapter = "doppler"
27
+
28
+ Args:
29
+ env_content: Raw environment file content
30
+ secret_config: Secret configuration (unused for doppler)
31
+
32
+ Returns:
33
+ Resolved environment content with secrets replaced
34
+
35
+ Raises:
36
+ SecretResolutionError: If secret not found or CLI fails
37
+ """
38
+ # Parse env file
39
+ with closing(StringIO(env_content)) as buffer:
40
+ env_dict = dotenv_values(stream=buffer)
41
+
42
+ # Identify secrets (values starting with $)
43
+ secrets = {
44
+ key: value for key, value in env_dict.items() if value and value.startswith("$")
45
+ }
46
+
47
+ if not secrets:
48
+ return env_content
49
+
50
+ # Resolve secrets concurrently
51
+ resolved_secrets = {}
52
+ with ThreadPoolExecutor() as executor:
53
+ future_to_key = {
54
+ executor.submit(_read_secret, secret[1:]): key
55
+ for key, secret in secrets.items()
56
+ }
57
+
58
+ for future in as_completed(future_to_key):
59
+ key = future_to_key[future]
60
+ try:
61
+ resolved_secrets[key] = future.result()
62
+ except Exception as e:
63
+ raise SecretResolutionError(
64
+ f"Failed to retrieve secret for {key}: {e}",
65
+ adapter="doppler",
66
+ key=key,
67
+ ) from e
68
+
69
+ # Merge resolved secrets back into env dict
70
+ env_dict.update(resolved_secrets)
71
+
72
+ return "\n".join(f'{key}="{value}"' for key, value in env_dict.items())
73
+
74
+
75
+ def _read_secret(name: str) -> str:
76
+ """Read a single secret from Doppler.
77
+
78
+ Args:
79
+ name: Secret/variable name
80
+
81
+ Returns:
82
+ Secret value
83
+
84
+ Raises:
85
+ SecretResolutionError: If secret not found
86
+ """
87
+ result = subprocess.run(
88
+ ["doppler", "run", "--command", f"echo ${name}"],
89
+ capture_output=True,
90
+ text=True,
91
+ )
92
+
93
+ if result.returncode != 0:
94
+ raise SecretResolutionError(result.stderr, adapter="doppler", key=name)
95
+
96
+ return result.stdout.strip()