@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 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.0.0",
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": "workspace:*",
41
- "@kustodian/plugins": "workspace:*",
42
- "@kustodian/schema": "workspace:*"
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
- ['secrets', 'download', '--project', project, '--config', config, '--format', 'json', '--no-file'],
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 { check_doppler_available, doppler_secret_get, doppler_secrets_download } from './executor.js';
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 { create_cache_key, type DopplerCacheKeyType, type DopplerPluginOptionsType } from './types.js';
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
- // Group substitutions by project/config to minimize API calls
22
- const groups = new Map<DopplerCacheKeyType, DopplerSubstitutionType[]>();
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
  /**