@kustodian/plugin-doppler 1.0.0 → 1.1.0
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.
- package/README.md +75 -0
- package/package.json +4 -4
- package/src/executor.ts +11 -1
- package/src/plugin.ts +5 -1
- package/src/resolver.ts +33 -4
- package/src/types.ts +12 -0
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# @kustodian/plugin-doppler
|
|
2
|
+
|
|
3
|
+
Doppler secret provider plugin for [Kustodian](https://github.com/lucasilverentand/kustodian). Enables seamless integration with [Doppler](https://www.doppler.com/) for secure secret management in your Kubernetes configurations.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @kustodian/plugin-doppler
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
- [Doppler CLI](https://docs.doppler.com/docs/install-cli) installed and available in your PATH
|
|
14
|
+
- Authentication configured via `doppler login` or `DOPPLER_TOKEN` environment variable
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { create_doppler_plugin } from '@kustodian/plugin-doppler';
|
|
20
|
+
|
|
21
|
+
// Create with default options
|
|
22
|
+
const plugin = create_doppler_plugin();
|
|
23
|
+
|
|
24
|
+
// Or with custom options
|
|
25
|
+
const plugin = create_doppler_plugin({
|
|
26
|
+
token: process.env.DOPPLER_TOKEN, // Optional: override token
|
|
27
|
+
timeout: 30000, // Optional: CLI timeout in ms
|
|
28
|
+
fail_on_missing: true, // Optional: fail if secrets are missing
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### CLI Commands
|
|
33
|
+
|
|
34
|
+
The plugin provides CLI commands for working with Doppler:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Check Doppler CLI availability
|
|
38
|
+
kustodian doppler check
|
|
39
|
+
|
|
40
|
+
# Test reading a secret
|
|
41
|
+
kustodian doppler test <project> <config> <secret>
|
|
42
|
+
|
|
43
|
+
# List available secrets in a config
|
|
44
|
+
kustodian doppler list-secrets <project> <config>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Programmatic API
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import {
|
|
51
|
+
check_doppler_available,
|
|
52
|
+
doppler_secret_get,
|
|
53
|
+
doppler_secrets_download,
|
|
54
|
+
resolve_doppler_substitutions,
|
|
55
|
+
} from '@kustodian/plugin-doppler';
|
|
56
|
+
|
|
57
|
+
// Check if Doppler CLI is available
|
|
58
|
+
const available = await check_doppler_available();
|
|
59
|
+
|
|
60
|
+
// Get a single secret
|
|
61
|
+
const secret = await doppler_secret_get('my-project', 'production', 'API_KEY');
|
|
62
|
+
|
|
63
|
+
// Download all secrets for a project/config
|
|
64
|
+
const secrets = await doppler_secrets_download('my-project', 'production');
|
|
65
|
+
|
|
66
|
+
// Resolve substitutions (batched by project/config for efficiency)
|
|
67
|
+
const resolved = await resolve_doppler_substitutions([
|
|
68
|
+
{ name: 'api_key', project: 'my-project', config: 'production', secret: 'API_KEY' },
|
|
69
|
+
{ name: 'db_url', project: 'my-project', config: 'production', secret: 'DATABASE_URL' },
|
|
70
|
+
]);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kustodian/plugin-doppler",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Doppler secret provider plugin for Kustodian",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
"registry": "https://npm.pkg.github.com"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@kustodian/core": "
|
|
41
|
-
"@kustodian/plugins": "
|
|
42
|
-
"@kustodian/schema": "
|
|
40
|
+
"@kustodian/core": "1.1.0",
|
|
41
|
+
"@kustodian/plugins": "1.0.1",
|
|
42
|
+
"@kustodian/schema": "1.3.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {}
|
|
45
45
|
}
|
package/src/executor.ts
CHANGED
|
@@ -120,7 +120,17 @@ export async function doppler_secrets_download(
|
|
|
120
120
|
|
|
121
121
|
const result = await exec_command(
|
|
122
122
|
'doppler',
|
|
123
|
-
[
|
|
123
|
+
[
|
|
124
|
+
'secrets',
|
|
125
|
+
'download',
|
|
126
|
+
'--project',
|
|
127
|
+
project,
|
|
128
|
+
'--config',
|
|
129
|
+
config,
|
|
130
|
+
'--format',
|
|
131
|
+
'json',
|
|
132
|
+
'--no-file',
|
|
133
|
+
],
|
|
124
134
|
{
|
|
125
135
|
timeout,
|
|
126
136
|
env,
|
package/src/plugin.ts
CHANGED
|
@@ -9,7 +9,11 @@ import type {
|
|
|
9
9
|
PluginManifestType,
|
|
10
10
|
} from '@kustodian/plugins';
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
check_doppler_available,
|
|
14
|
+
doppler_secret_get,
|
|
15
|
+
doppler_secrets_download,
|
|
16
|
+
} from './executor.js';
|
|
13
17
|
import type { DopplerPluginOptionsType } from './types.js';
|
|
14
18
|
|
|
15
19
|
/**
|
package/src/resolver.ts
CHANGED
|
@@ -3,11 +3,16 @@ import type { KustodianErrorType } from '@kustodian/core';
|
|
|
3
3
|
import type { DopplerSubstitutionType } from '@kustodian/schema';
|
|
4
4
|
|
|
5
5
|
import { doppler_secrets_download } from './executor.js';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
type DopplerCacheKeyType,
|
|
8
|
+
type DopplerPluginOptionsType,
|
|
9
|
+
create_cache_key,
|
|
10
|
+
} from './types.js';
|
|
7
11
|
|
|
8
12
|
/**
|
|
9
13
|
* Resolves Doppler substitutions to actual secret values.
|
|
10
14
|
* Groups by project/config to minimize API calls.
|
|
15
|
+
* Uses cluster-level defaults when project/config are not specified.
|
|
11
16
|
* Returns a map from substitution name to resolved value.
|
|
12
17
|
*/
|
|
13
18
|
export async function resolve_doppler_substitutions(
|
|
@@ -18,10 +23,31 @@ export async function resolve_doppler_substitutions(
|
|
|
18
23
|
return success({});
|
|
19
24
|
}
|
|
20
25
|
|
|
21
|
-
//
|
|
22
|
-
const
|
|
26
|
+
// Validate and apply cluster defaults
|
|
27
|
+
const resolved_subs: Array<DopplerSubstitutionType & { project: string; config: string }> = [];
|
|
23
28
|
|
|
24
29
|
for (const sub of substitutions) {
|
|
30
|
+
const project = sub.project ?? options.cluster_defaults?.project;
|
|
31
|
+
const config = sub.config ?? options.cluster_defaults?.config;
|
|
32
|
+
|
|
33
|
+
if (!project || !config) {
|
|
34
|
+
return failure({
|
|
35
|
+
code: 'MISSING_DOPPLER_CONFIG',
|
|
36
|
+
message: `Doppler substitution '${sub.name}' missing project/config and no cluster defaults configured`,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
resolved_subs.push({
|
|
41
|
+
...sub,
|
|
42
|
+
project,
|
|
43
|
+
config,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Group substitutions by project/config to minimize API calls
|
|
48
|
+
const groups = new Map<DopplerCacheKeyType, typeof resolved_subs>();
|
|
49
|
+
|
|
50
|
+
for (const sub of resolved_subs) {
|
|
25
51
|
const key = create_cache_key(sub.project, sub.config);
|
|
26
52
|
const group = groups.get(key) ?? [];
|
|
27
53
|
group.push(sub);
|
|
@@ -36,7 +62,10 @@ export async function resolve_doppler_substitutions(
|
|
|
36
62
|
// Fetch secrets for each group
|
|
37
63
|
for (const [key, subs] of groups) {
|
|
38
64
|
// Get project and config from the first substitution in the group
|
|
39
|
-
const first = subs[0]
|
|
65
|
+
const first = subs[0];
|
|
66
|
+
if (!first) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
40
69
|
|
|
41
70
|
// Check if we already have the secrets cached
|
|
42
71
|
let secrets = secrets_cache.get(key);
|
package/src/types.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cluster-level Doppler defaults.
|
|
3
|
+
*/
|
|
4
|
+
export interface DopplerClusterDefaultsType {
|
|
5
|
+
/** Default project name */
|
|
6
|
+
project?: string | undefined;
|
|
7
|
+
/** Default config name */
|
|
8
|
+
config?: string | undefined;
|
|
9
|
+
}
|
|
10
|
+
|
|
1
11
|
/**
|
|
2
12
|
* Options for the Doppler plugin.
|
|
3
13
|
*/
|
|
@@ -8,6 +18,8 @@ export interface DopplerPluginOptionsType {
|
|
|
8
18
|
timeout?: number | undefined;
|
|
9
19
|
/** Whether to fail on missing secrets (default: true) */
|
|
10
20
|
fail_on_missing?: boolean | undefined;
|
|
21
|
+
/** Cluster-level defaults for project/config */
|
|
22
|
+
cluster_defaults?: DopplerClusterDefaultsType | undefined;
|
|
11
23
|
}
|
|
12
24
|
|
|
13
25
|
/**
|