@kibibit/configit 2.12.2 → 2.13.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.
Files changed (38) hide show
  1. package/lib/config.service.d.ts +2 -1
  2. package/lib/config.service.d.ts.map +1 -1
  3. package/lib/config.service.js +5 -0
  4. package/lib/config.service.js.map +1 -1
  5. package/lib/tsconfig.tsbuildinfo +1 -1
  6. package/lib/vault/__tests__/vault-integration.test.d.ts.map +1 -1
  7. package/lib/vault/__tests__/vault-integration.test.js +124 -0
  8. package/lib/vault/__tests__/vault-integration.test.js.map +1 -1
  9. package/lib/vault/build-vault-config.d.ts +8 -0
  10. package/lib/vault/build-vault-config.d.ts.map +1 -0
  11. package/lib/vault/build-vault-config.js +41 -0
  12. package/lib/vault/build-vault-config.js.map +1 -0
  13. package/lib/vault/index.d.ts +2 -0
  14. package/lib/vault/index.d.ts.map +1 -1
  15. package/lib/vault/index.js +3 -1
  16. package/lib/vault/index.js.map +1 -1
  17. package/lib/vault/secret-refresh-manager.d.ts +6 -2
  18. package/lib/vault/secret-refresh-manager.d.ts.map +1 -1
  19. package/lib/vault/secret-refresh-manager.js +91 -27
  20. package/lib/vault/secret-refresh-manager.js.map +1 -1
  21. package/lib/vault/types.d.ts +9 -0
  22. package/lib/vault/types.d.ts.map +1 -1
  23. package/lib/vault/vault-integration.d.ts +2 -1
  24. package/lib/vault/vault-integration.d.ts.map +1 -1
  25. package/lib/vault/vault-integration.js +6 -0
  26. package/lib/vault/vault-integration.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/config.service.ts +21 -1
  29. package/src/config.service.vault.spec.ts +47 -1
  30. package/src/vault/__tests__/build-vault-config.spec.ts +116 -0
  31. package/src/vault/__tests__/secret-refresh-manager.spec.ts +328 -0
  32. package/src/vault/__tests__/vault-integration-callback.spec.ts +73 -0
  33. package/src/vault/__tests__/vault-integration.test.ts +174 -2
  34. package/src/vault/build-vault-config.ts +73 -0
  35. package/src/vault/index.ts +4 -0
  36. package/src/vault/secret-refresh-manager.ts +123 -71
  37. package/src/vault/types.ts +38 -0
  38. package/src/vault/vault-integration.ts +14 -1
@@ -1 +1 @@
1
- {"version":3,"file":"vault-integration.js","sourceRoot":"","sources":["../../src/vault/vault-integration.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vault-integration.js","sourceRoot":"","sources":["../../src/vault/vault-integration.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kibibit/configit",
3
- "version": "2.12.2",
3
+ "version": "2.13.0",
4
4
  "description": "a general typescript configuration service",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -22,7 +22,7 @@ import * as nconfJsoncFormat from '@kibibit/nconf-jsonc';
22
22
  import { ConfigValidationError } from './config.errors';
23
23
  import { BaseConfig } from './config.model';
24
24
  import { getEnvironment, setEnvironment } from './environment.service';
25
- import { IVaultConfigOptions, VaultHealth, VaultIntegration } from './vault';
25
+ import { IVaultConfigOptions, SecretRefreshCallback, VaultHealth, VaultIntegration } from './vault';
26
26
 
27
27
  type INconfKibibitFormats = IFormats & {
28
28
  yaml: nconfYamlFormat;
@@ -299,6 +299,26 @@ export class ConfigService<T extends BaseConfig> {
299
299
  }
300
300
  }
301
301
 
302
+ /**
303
+ * Register a callback for when Vault secrets are refreshed.
304
+ * Fired once per Vault path after all properties from that path are updated.
305
+ * Config values are already set when the callback fires.
306
+ *
307
+ * Can be called before or after initializeVault().
308
+ *
309
+ * @example
310
+ * configService.onSecretRefreshed((event) => {
311
+ * if (event.properties.includes('DB_PASSWORD')) {
312
+ * // Reconnect database pool with fresh credentials
313
+ * }
314
+ * });
315
+ */
316
+ onSecretRefreshed(callback: SecretRefreshCallback): void {
317
+ if (this.vaultIntegration) {
318
+ this.vaultIntegration.onSecretRefreshed(callback);
319
+ }
320
+ }
321
+
302
322
  /**
303
323
  * Shutdown Vault integration gracefully
304
324
  */
@@ -77,7 +77,8 @@ describe('ConfigService + Vault Integration', () => {
77
77
  invalidateProperty: jest.fn(),
78
78
  shutdown: jest.fn(),
79
79
  isInitialized: jest.fn().mockReturnValue(true),
80
- getSecret: jest.fn().mockReturnValue(null)
80
+ getSecret: jest.fn().mockReturnValue(null),
81
+ onSecretRefreshed: jest.fn()
81
82
  } as unknown as jest.Mocked<VaultIntegration>;
82
83
 
83
84
  // Ensure the mock implementation returns our mock instance
@@ -858,4 +859,49 @@ describe('ConfigService + Vault Integration', () => {
858
859
  await expect(configService.initializeVault()).rejects.toThrow('Failed to load secrets');
859
860
  });
860
861
  });
862
+
863
+ describe('onSecretRefreshed', () => {
864
+ it('should delegate callback registration to vaultIntegration', async () => {
865
+ const vaultConfig: IVaultConfigOptions = {
866
+ endpoint: 'http://localhost:8200',
867
+ auth: {
868
+ methods: [
869
+ {
870
+ type: 'token',
871
+ config: {
872
+ type: 'token',
873
+ token: 'test-token'
874
+ }
875
+ }
876
+ ]
877
+ }
878
+ };
879
+
880
+ const configService = new ConfigService(TestVaultConfig, {
881
+ NODE_ENV: 'test',
882
+ REGULAR_CONFIG: 'regular'
883
+ } as any, {
884
+ vault: vaultConfig
885
+ });
886
+
887
+ await configService.initializeVault();
888
+
889
+ const callback = jest.fn();
890
+ configService.onSecretRefreshed(callback);
891
+
892
+ expect(mockVaultIntegration.onSecretRefreshed).toHaveBeenCalledWith(callback);
893
+ });
894
+
895
+ it('should be a no-op when vault is not configured', () => {
896
+ const configService = new ConfigService(TestRegularConfig, {
897
+ NODE_ENV: 'test',
898
+ REGULAR_CONFIG: 'test-value'
899
+ } as any);
900
+
901
+ const callback = jest.fn();
902
+ configService.onSecretRefreshed(callback);
903
+
904
+ expect(mockVaultIntegration.onSecretRefreshed).not.toHaveBeenCalled();
905
+ });
906
+ });
861
907
  });
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Unit tests for buildVaultConfigFromEnv helper.
3
+ * These are pure unit tests — no running Vault instance required.
4
+ */
5
+
6
+ import { buildVaultConfigFromEnv } from '../build-vault-config';
7
+
8
+ describe('buildVaultConfigFromEnv', () => {
9
+ const ENV_KEYS = ['VAULT_ADDR', 'VAULT_TOKEN', 'VAULT_GCP_ROLE'] as const;
10
+ const savedEnv: Record<string, string | undefined> = {};
11
+
12
+ beforeEach(() => {
13
+ for (const key of ENV_KEYS) {
14
+ savedEnv[key] = process.env[key];
15
+ delete process.env[key];
16
+ }
17
+ });
18
+
19
+ afterEach(() => {
20
+ for (const key of ENV_KEYS) {
21
+ if (savedEnv[key] !== undefined) {
22
+ process.env[key] = savedEnv[key];
23
+ } else {
24
+ delete process.env[key];
25
+ }
26
+ }
27
+ });
28
+
29
+ it('should return undefined when VAULT_ADDR is not set', () => {
30
+ expect(buildVaultConfigFromEnv()).toBeUndefined();
31
+ });
32
+
33
+ it('should return undefined when VAULT_ADDR is set but no auth env var is present', () => {
34
+ process.env.VAULT_ADDR = 'http://127.0.0.1:8200';
35
+ expect(buildVaultConfigFromEnv()).toBeUndefined();
36
+ });
37
+
38
+ describe('token auth (VAULT_TOKEN)', () => {
39
+ beforeEach(() => {
40
+ process.env.VAULT_ADDR = 'https://vault.example.com';
41
+ process.env.VAULT_TOKEN = 'my-dev-token';
42
+ });
43
+
44
+ it('should build config with token auth', () => {
45
+ const config = buildVaultConfigFromEnv();
46
+
47
+ expect(config).toBeDefined();
48
+ expect(config!.endpoint).toBe('https://vault.example.com');
49
+ expect(config!.auth).toEqual({ method: 'token', token: 'my-dev-token' });
50
+ });
51
+
52
+ it('should default refreshBuffer to 10 for token auth', () => {
53
+ const config = buildVaultConfigFromEnv();
54
+ expect(config!.refreshBuffer).toBe(10);
55
+ });
56
+
57
+ it('should allow overriding refreshBuffer', () => {
58
+ const config = buildVaultConfigFromEnv({ refreshBuffer: 45 });
59
+ expect(config!.refreshBuffer).toBe(45);
60
+ });
61
+
62
+ it('should apply default fallback config', () => {
63
+ const config = buildVaultConfigFromEnv();
64
+
65
+ expect(config!.fallback).toEqual({
66
+ required: false,
67
+ useCacheOnFailure: true,
68
+ maxCacheAge: 3600000,
69
+ failFast: false
70
+ });
71
+ });
72
+
73
+ it('should allow overriding fallback config', () => {
74
+ const customFallback = { required: true, useCacheOnFailure: false, maxCacheAge: 0, failFast: true };
75
+ const config = buildVaultConfigFromEnv({ fallback: customFallback });
76
+ expect(config!.fallback).toEqual(customFallback);
77
+ });
78
+
79
+ it('should wire through onSecretRefreshed callback', () => {
80
+ const callback = jest.fn();
81
+ const config = buildVaultConfigFromEnv({ onSecretRefreshed: callback });
82
+ expect(config!.onSecretRefreshed).toBe(callback);
83
+ });
84
+
85
+ it('should prefer VAULT_TOKEN over VAULT_GCP_ROLE when both are set', () => {
86
+ process.env.VAULT_GCP_ROLE = 'my-gcp-role';
87
+ const config = buildVaultConfigFromEnv();
88
+ expect((config!.auth as any).method).toBe('token');
89
+ });
90
+ });
91
+
92
+ describe('GCP auth (VAULT_GCP_ROLE)', () => {
93
+ beforeEach(() => {
94
+ process.env.VAULT_ADDR = 'https://vault.prod.example.com';
95
+ process.env.VAULT_GCP_ROLE = 'my-gcp-role';
96
+ });
97
+
98
+ it('should build config with GCP auth', () => {
99
+ const config = buildVaultConfigFromEnv();
100
+
101
+ expect(config).toBeDefined();
102
+ expect(config!.endpoint).toBe('https://vault.prod.example.com');
103
+ expect(config!.auth).toEqual({ method: 'gcp', role: 'my-gcp-role' });
104
+ });
105
+
106
+ it('should default refreshBuffer to 60 for GCP auth', () => {
107
+ const config = buildVaultConfigFromEnv();
108
+ expect(config!.refreshBuffer).toBe(60);
109
+ });
110
+
111
+ it('should allow overriding refreshBuffer', () => {
112
+ const config = buildVaultConfigFromEnv({ refreshBuffer: 120 });
113
+ expect(config!.refreshBuffer).toBe(120);
114
+ });
115
+ });
116
+ });
@@ -0,0 +1,328 @@
1
+ /**
2
+ * Unit tests for SecretRefreshManager
3
+ * Uses mocked VaultProvider and VaultCache — no running Vault required.
4
+ */
5
+
6
+ import { SecretRefreshManager } from '../secret-refresh-manager';
7
+ import { VaultCache } from '../vault-cache';
8
+ import { VaultProvider } from '../vault-provider';
9
+ import { IVaultSecret, SecretRefreshEvent, VaultCacheEntry, VaultPropertyMetadata } from '../types';
10
+
11
+ jest.mock('../vault-provider');
12
+ jest.mock('../vault-cache');
13
+
14
+ function makeMetadata(overrides: Partial<VaultPropertyMetadata> = {}): VaultPropertyMetadata {
15
+ return {
16
+ propertyName: 'PROP',
17
+ propertyType: 'string',
18
+ path: 'test/path',
19
+ key: 'value',
20
+ engine: 'kv-v2',
21
+ required: true,
22
+ ...overrides
23
+ };
24
+ }
25
+
26
+ function makeSecret(data: Record<string, string>, leaseDuration = 60): IVaultSecret {
27
+ return {
28
+ data,
29
+ leaseDuration,
30
+ leaseId: leaseDuration > 0 ? 'lease-123' : '',
31
+ renewable: leaseDuration > 0
32
+ };
33
+ }
34
+
35
+ function makeCacheEntry(vaultPath: string, refreshAtOffset = 30000): VaultCacheEntry {
36
+ const now = Date.now();
37
+ const secret = makeSecret({ value: 'cached' });
38
+ return {
39
+ value: 'cached',
40
+ secret,
41
+ vaultPath,
42
+ propertyName: 'PROP',
43
+ cachedAt: now,
44
+ expiresAt: now + 60000,
45
+ refreshAt: now + refreshAtOffset
46
+ };
47
+ }
48
+
49
+ describe('SecretRefreshManager', () => {
50
+ let manager: SecretRefreshManager;
51
+ let mockProvider: jest.Mocked<VaultProvider>;
52
+ let mockCache: jest.Mocked<VaultCache>;
53
+
54
+ beforeEach(() => {
55
+ jest.useFakeTimers();
56
+
57
+ mockProvider = new VaultProvider({} as any) as jest.Mocked<VaultProvider>;
58
+ mockCache = new VaultCache() as jest.Mocked<VaultCache>;
59
+
60
+ manager = new SecretRefreshManager(mockProvider, mockCache, 30);
61
+ });
62
+
63
+ afterEach(() => {
64
+ manager.shutdown();
65
+ jest.useRealTimers();
66
+ });
67
+
68
+ describe('onSecretRefreshed', () => {
69
+ it('should register a callback', () => {
70
+ const callback = jest.fn();
71
+ manager.onSecretRefreshed(callback);
72
+ expect(callback).not.toHaveBeenCalled();
73
+ });
74
+
75
+ it('should support multiple callbacks', () => {
76
+ const cb1 = jest.fn();
77
+ const cb2 = jest.fn();
78
+ manager.onSecretRefreshed(cb1);
79
+ manager.onSecretRefreshed(cb2);
80
+ expect(cb1).not.toHaveBeenCalled();
81
+ expect(cb2).not.toHaveBeenCalled();
82
+ });
83
+ });
84
+
85
+ describe('scheduleRefresh', () => {
86
+ it('should not schedule when cache entry is missing', () => {
87
+ mockCache.getEntry.mockReturnValue(null as any);
88
+ manager.scheduleRefresh('PROP', makeMetadata());
89
+ expect(mockCache.getEntry).toHaveBeenCalledWith('PROP');
90
+ });
91
+
92
+ it('should schedule a timer when cache entry has future refreshAt', () => {
93
+ mockCache.getEntry.mockReturnValue(makeCacheEntry('secret/data/test/path', 5000));
94
+ mockProvider.read.mockResolvedValue(makeSecret({ value: 'new' }));
95
+
96
+ manager.scheduleRefresh('PROP', makeMetadata());
97
+
98
+ expect(mockCache.getEntry).toHaveBeenCalledWith('PROP');
99
+ });
100
+
101
+ it('should execute immediately when refreshAt is in the past', () => {
102
+ mockCache.getEntry.mockReturnValue(makeCacheEntry('secret/data/test/path', -1000));
103
+ mockProvider.read.mockResolvedValue(makeSecret({ value: 'new' }));
104
+
105
+ manager.scheduleRefresh('PROP', makeMetadata());
106
+ });
107
+ });
108
+
109
+ describe('path-level atomic refresh', () => {
110
+ const SHARED_PATH = 'database/creds/my-role';
111
+
112
+ beforeEach(() => {
113
+ mockProvider.read.mockResolvedValue(makeSecret({
114
+ username: 'new-user',
115
+ password: 'new-pass'
116
+ }, 60));
117
+ });
118
+
119
+ it('should refresh all sibling properties from a single Vault read', async () => {
120
+ const entry = makeCacheEntry(SHARED_PATH, 100);
121
+ mockCache.getEntry.mockReturnValue(entry);
122
+
123
+ const metaUser = makeMetadata({ propertyName: 'DB_USERNAME', key: 'username', engine: 'database', path: 'creds/my-role' });
124
+ const metaPass = makeMetadata({ propertyName: 'DB_PASSWORD', key: 'password', engine: 'database', path: 'creds/my-role' });
125
+
126
+ const target = { DB_USERNAME: 'old-user', DB_PASSWORD: 'old-pass' };
127
+
128
+ manager.scheduleRefresh('DB_USERNAME', metaUser, target);
129
+ manager.scheduleRefresh('DB_PASSWORD', metaPass, target);
130
+
131
+ await jest.advanceTimersByTimeAsync(200);
132
+
133
+ expect(mockProvider.read).toHaveBeenCalledTimes(1);
134
+ expect(mockProvider.read).toHaveBeenCalledWith(SHARED_PATH);
135
+ });
136
+
137
+ it('should update target instance properties from the single read', async () => {
138
+ const entry = makeCacheEntry(SHARED_PATH, 100);
139
+ mockCache.getEntry.mockReturnValue(entry);
140
+
141
+ const metaUser = makeMetadata({ propertyName: 'DB_USERNAME', key: 'username', engine: 'database', path: 'creds/my-role' });
142
+ const metaPass = makeMetadata({ propertyName: 'DB_PASSWORD', key: 'password', engine: 'database', path: 'creds/my-role' });
143
+
144
+ const target = { DB_USERNAME: 'old-user', DB_PASSWORD: 'old-pass' };
145
+
146
+ manager.scheduleRefresh('DB_USERNAME', metaUser, target);
147
+ manager.scheduleRefresh('DB_PASSWORD', metaPass, target);
148
+
149
+ await jest.advanceTimersByTimeAsync(200);
150
+
151
+ expect(target.DB_USERNAME).toBe('new-user');
152
+ expect(target.DB_PASSWORD).toBe('new-pass');
153
+ });
154
+
155
+ it('should fire one callback per path with all affected properties', async () => {
156
+ const events: SecretRefreshEvent[] = [];
157
+ manager.onSecretRefreshed((e) => { events.push(e); });
158
+
159
+ const entry = makeCacheEntry(SHARED_PATH, 100);
160
+ mockCache.getEntry.mockReturnValue(entry);
161
+
162
+ const metaUser = makeMetadata({ propertyName: 'DB_USERNAME', key: 'username', engine: 'database', path: 'creds/my-role' });
163
+ const metaPass = makeMetadata({ propertyName: 'DB_PASSWORD', key: 'password', engine: 'database', path: 'creds/my-role' });
164
+
165
+ manager.scheduleRefresh('DB_USERNAME', metaUser);
166
+ manager.scheduleRefresh('DB_PASSWORD', metaPass);
167
+
168
+ await jest.advanceTimersByTimeAsync(200);
169
+
170
+ expect(events).toHaveLength(1);
171
+ expect(events[0].vaultPath).toBe(SHARED_PATH);
172
+ expect(events[0].properties).toContain('DB_USERNAME');
173
+ expect(events[0].properties).toContain('DB_PASSWORD');
174
+ expect(events[0].engine).toBe('database');
175
+ expect(events[0].refreshCount).toBe(1);
176
+ expect(events[0].timestamp).toBeDefined();
177
+ });
178
+
179
+ it('should increment refreshCount on subsequent refreshes', async () => {
180
+ const events: SecretRefreshEvent[] = [];
181
+ manager.onSecretRefreshed((e) => { events.push(e); });
182
+
183
+ const entry = makeCacheEntry(SHARED_PATH, -100);
184
+ mockCache.getEntry.mockReturnValue(entry);
185
+
186
+ const meta = makeMetadata({ propertyName: 'DB_USERNAME', key: 'username', engine: 'database', path: 'creds/my-role' });
187
+
188
+ manager.scheduleRefresh('DB_USERNAME', meta);
189
+ await jest.advanceTimersByTimeAsync(0);
190
+
191
+ manager.scheduleRefresh('DB_USERNAME', meta);
192
+ await jest.advanceTimersByTimeAsync(0);
193
+
194
+ expect(events).toHaveLength(2);
195
+ expect(events[0].refreshCount).toBe(1);
196
+ expect(events[1].refreshCount).toBe(2);
197
+ });
198
+ });
199
+
200
+ describe('callback error handling', () => {
201
+ it('should not throw when a sync callback throws', async () => {
202
+ const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
203
+
204
+ manager.onSecretRefreshed(() => { throw new Error('callback boom'); });
205
+
206
+ const entry = makeCacheEntry('secret/data/test', -100);
207
+ mockCache.getEntry.mockReturnValue(entry);
208
+ mockProvider.read.mockResolvedValue(makeSecret({ value: 'new' }));
209
+
210
+ manager.scheduleRefresh('PROP', makeMetadata());
211
+ await jest.advanceTimersByTimeAsync(0);
212
+
213
+ expect(consoleSpy).toHaveBeenCalledWith(
214
+ expect.stringContaining('callback boom')
215
+ );
216
+
217
+ consoleSpy.mockRestore();
218
+ });
219
+
220
+ it('should not throw when an async callback rejects', async () => {
221
+ const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
222
+
223
+ manager.onSecretRefreshed(async () => { throw new Error('async boom'); });
224
+
225
+ const entry = makeCacheEntry('secret/data/test', -100);
226
+ mockCache.getEntry.mockReturnValue(entry);
227
+ mockProvider.read.mockResolvedValue(makeSecret({ value: 'new' }));
228
+
229
+ manager.scheduleRefresh('PROP', makeMetadata());
230
+ await jest.advanceTimersByTimeAsync(0);
231
+
232
+ // Give the rejected promise a tick to log
233
+ await Promise.resolve();
234
+
235
+ expect(consoleSpy).toHaveBeenCalledWith(
236
+ expect.stringContaining('async boom')
237
+ );
238
+
239
+ consoleSpy.mockRestore();
240
+ });
241
+ });
242
+
243
+ describe('Vault read failure', () => {
244
+ it('should log error and schedule retry on read failure', async () => {
245
+ const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
246
+
247
+ const entry = makeCacheEntry('secret/data/test', -100);
248
+ mockCache.getEntry.mockReturnValue(entry);
249
+ mockProvider.read.mockRejectedValue(new Error('Vault unavailable'));
250
+
251
+ manager.scheduleRefresh('PROP', makeMetadata());
252
+ await jest.advanceTimersByTimeAsync(0);
253
+
254
+ expect(consoleSpy).toHaveBeenCalledWith(
255
+ expect.stringContaining('Failed to refresh secrets')
256
+ );
257
+
258
+ consoleSpy.mockRestore();
259
+ });
260
+ });
261
+
262
+ describe('cancelRefresh', () => {
263
+ it('should cancel a scheduled refresh', () => {
264
+ mockCache.getEntry.mockReturnValue(makeCacheEntry('secret/data/test', 30000));
265
+ manager.scheduleRefresh('PROP', makeMetadata());
266
+ manager.cancelRefresh('PROP');
267
+ // No error thrown, timer cleared
268
+ });
269
+
270
+ it('should be a no-op for non-existent property', () => {
271
+ manager.cancelRefresh('NON_EXISTENT');
272
+ });
273
+ });
274
+
275
+ describe('getRefreshStatus', () => {
276
+ it('should return empty array when nothing is cached', () => {
277
+ mockCache.getCachedProperties.mockReturnValue([]);
278
+ expect(manager.getRefreshStatus()).toEqual([]);
279
+ });
280
+
281
+ it('should return status for cached properties', () => {
282
+ const entry = makeCacheEntry('secret/data/test', 30000);
283
+ mockCache.getCachedProperties.mockReturnValue(['PROP']);
284
+ mockCache.getEntry.mockReturnValue(entry);
285
+
286
+ manager.scheduleRefresh('PROP', makeMetadata());
287
+
288
+ const statuses = manager.getRefreshStatus();
289
+ expect(statuses).toHaveLength(1);
290
+ expect(statuses[0].propertyName).toBe('PROP');
291
+ expect(statuses[0].vaultPath).toBe('secret/data/test');
292
+ expect(statuses[0].scheduled).toBe(true);
293
+ });
294
+ });
295
+
296
+ describe('getRefreshStatusForProperty', () => {
297
+ it('should return null for uncached property', () => {
298
+ mockCache.getEntry.mockReturnValue(null as any);
299
+ expect(manager.getRefreshStatusForProperty('MISSING')).toBeNull();
300
+ });
301
+
302
+ it('should return status for a cached property', () => {
303
+ const entry = makeCacheEntry('secret/data/test', 30000);
304
+ mockCache.getEntry.mockReturnValue(entry);
305
+
306
+ manager.scheduleRefresh('PROP', makeMetadata());
307
+
308
+ const status = manager.getRefreshStatusForProperty('PROP');
309
+ expect(status).toBeDefined();
310
+ expect(status!.propertyName).toBe('PROP');
311
+ expect(status!.scheduled).toBe(true);
312
+ expect(status!.refreshCount).toBe(0);
313
+ });
314
+ });
315
+
316
+ describe('shutdown', () => {
317
+ it('should clear all timers and callbacks', () => {
318
+ const cb = jest.fn();
319
+ manager.onSecretRefreshed(cb);
320
+
321
+ mockCache.getEntry.mockReturnValue(makeCacheEntry('secret/data/test', 30000));
322
+ manager.scheduleRefresh('PROP', makeMetadata());
323
+
324
+ manager.shutdown();
325
+ // After shutdown, advancing time should not trigger anything
326
+ });
327
+ });
328
+ });
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Unit tests for VaultIntegration callback wiring.
3
+ * Mocks VaultProvider, VaultCache, and SecretRefreshManager — no Vault required.
4
+ */
5
+
6
+ import { SecretRefreshManager } from '../secret-refresh-manager';
7
+ import { VaultIntegration } from '../vault-integration';
8
+ import { VaultCache } from '../vault-cache';
9
+ import { VaultProvider } from '../vault-provider';
10
+ import { IVaultConfigOptions } from '../types';
11
+
12
+ jest.mock('../vault-provider');
13
+ jest.mock('../vault-cache');
14
+ jest.mock('../secret-refresh-manager');
15
+
16
+ const BASE_CONFIG: IVaultConfigOptions = {
17
+ endpoint: 'http://127.0.0.1:8200',
18
+ auth: { method: 'token' as const, token: 'test-token' }
19
+ };
20
+
21
+ describe('VaultIntegration callback wiring', () => {
22
+ let mockRefreshManager: jest.Mocked<SecretRefreshManager>;
23
+
24
+ beforeEach(() => {
25
+ jest.clearAllMocks();
26
+
27
+ mockRefreshManager = {
28
+ onSecretRefreshed: jest.fn(),
29
+ scheduleRefresh: jest.fn(),
30
+ cancelRefresh: jest.fn(),
31
+ getRefreshStatus: jest.fn().mockReturnValue([]),
32
+ getRefreshStatusForProperty: jest.fn().mockReturnValue(null),
33
+ shutdown: jest.fn()
34
+ } as unknown as jest.Mocked<SecretRefreshManager>;
35
+
36
+ (SecretRefreshManager as jest.MockedClass<typeof SecretRefreshManager>)
37
+ .mockImplementation(() => mockRefreshManager);
38
+ });
39
+
40
+ it('should register onSecretRefreshed from config in constructor', () => {
41
+ const callback = jest.fn();
42
+ new VaultIntegration({ ...BASE_CONFIG, onSecretRefreshed: callback });
43
+
44
+ expect(mockRefreshManager.onSecretRefreshed).toHaveBeenCalledWith(callback);
45
+ });
46
+
47
+ it('should not call onSecretRefreshed when not provided in config', () => {
48
+ new VaultIntegration(BASE_CONFIG);
49
+
50
+ expect(mockRefreshManager.onSecretRefreshed).not.toHaveBeenCalled();
51
+ });
52
+
53
+ it('should delegate runtime onSecretRefreshed to refreshManager', () => {
54
+ const integration = new VaultIntegration(BASE_CONFIG);
55
+ const runtimeCallback = jest.fn();
56
+
57
+ integration.onSecretRefreshed(runtimeCallback);
58
+
59
+ expect(mockRefreshManager.onSecretRefreshed).toHaveBeenCalledWith(runtimeCallback);
60
+ });
61
+
62
+ it('should support both constructor and runtime callbacks', () => {
63
+ const constructorCb = jest.fn();
64
+ const runtimeCb = jest.fn();
65
+
66
+ const integration = new VaultIntegration({ ...BASE_CONFIG, onSecretRefreshed: constructorCb });
67
+ integration.onSecretRefreshed(runtimeCb);
68
+
69
+ expect(mockRefreshManager.onSecretRefreshed).toHaveBeenCalledTimes(2);
70
+ expect(mockRefreshManager.onSecretRefreshed).toHaveBeenCalledWith(constructorCb);
71
+ expect(mockRefreshManager.onSecretRefreshed).toHaveBeenCalledWith(runtimeCb);
72
+ });
73
+ });