@toeichust/common 0.0.13 → 1.0.1

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.
@@ -11,7 +11,7 @@ exports.SWAGGER_DESCRIPTION = `<table border="0">
11
11
  <h3>Giới thiệu</h3>
12
12
  <ul>
13
13
  <li>Đây là API cho <code>${process.env.NAME_SERVICE || 'Tên mặc định'}</code></li>
14
- <li><a href="https://github.com/ToeicHUST/${process.env.NAME_SERVICE || 'Tên mặc định'}">Xem thông tin github</a></li>
14
+ <li><a href="https://github.com/${process.env.NAME_SERVICE || 'Tên mặc định'}">Xem thông tin github</a></li>
15
15
  </ul>
16
16
  <h3>JSON và YAML docs:</h3>
17
17
  <ul>
@@ -1 +1 @@
1
- {"version":3,"file":"swagger.constant.js","sourceRoot":"","sources":["../../src/constants/swagger.constant.ts"],"names":[],"mappings":";;;AAAa,QAAA,iBAAiB,GAAG,MAAM,CAAC;AAC3B,QAAA,gBAAgB,GAAG,YAAY,CAAC;AAChC,QAAA,cAAc,GACzB,0DAA0D,CAAC;AAChD,QAAA,sBAAsB,GACjC,wGAAwG,CAAC;AAC9F,QAAA,mBAAmB,GAAG;;;;;mCAKA,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,cAAc;oDACzB,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,cAAc;;;;wBAItE,yBAAiB;wBACjB,yBAAiB;;;;kBAIvB,8BAAsB;;;SAG/B,CAAC"}
1
+ {"version":3,"file":"swagger.constant.js","sourceRoot":"","sources":["../../src/constants/swagger.constant.ts"],"names":[],"mappings":";;;AAAa,QAAA,iBAAiB,GAAG,MAAM,CAAC;AAC3B,QAAA,gBAAgB,GAAG,YAAY,CAAC;AAChC,QAAA,cAAc,GACzB,0DAA0D,CAAC;AAChD,QAAA,sBAAsB,GACjC,wGAAwG,CAAC;AAC9F,QAAA,mBAAmB,GAAG;;;;;mCAKA,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,cAAc;0CACnC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,cAAc;;;;wBAI5D,yBAAiB;wBACjB,yBAAiB;;;;kBAIvB,8BAAsB;;;SAG/B,CAAC"}
package/dist/index.d.ts CHANGED
@@ -2,3 +2,6 @@ export * from './constants/swagger.constant';
2
2
  export * from './helpers/bootstrap.helper';
3
3
  export * from './helpers/swagger.helper';
4
4
  export * from './middlewares/logger.middleware';
5
+ export * from './modules/vault/vault.module';
6
+ export * from './modules/vault/vault.service.spec';
7
+ export * from './modules/vault/vault.service';
package/dist/index.js CHANGED
@@ -18,4 +18,7 @@ __exportStar(require("./constants/swagger.constant"), exports);
18
18
  __exportStar(require("./helpers/bootstrap.helper"), exports);
19
19
  __exportStar(require("./helpers/swagger.helper"), exports);
20
20
  __exportStar(require("./middlewares/logger.middleware"), exports);
21
+ __exportStar(require("./modules/vault/vault.module"), exports);
22
+ __exportStar(require("./modules/vault/vault.service.spec"), exports);
23
+ __exportStar(require("./modules/vault/vault.service"), exports);
21
24
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAIA,+DAA6C;AAC7C,6DAA2C;AAC3C,2DAAyC;AACzC,kEAAgD"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAIA,+DAA6C;AAC7C,6DAA2C;AAC3C,2DAAyC;AACzC,kEAAgD;AAChD,+DAA6C;AAC7C,qEAAmD;AACnD,gEAA8C"}
@@ -0,0 +1,2 @@
1
+ export declare class VaultModule {
2
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.VaultModule = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const vault_service_1 = require("./vault.service");
12
+ const config_1 = require("@nestjs/config");
13
+ let VaultModule = class VaultModule {
14
+ };
15
+ exports.VaultModule = VaultModule;
16
+ exports.VaultModule = VaultModule = __decorate([
17
+ (0, common_1.Global)(),
18
+ (0, common_1.Module)({
19
+ imports: [config_1.ConfigModule],
20
+ providers: [
21
+ {
22
+ provide: vault_service_1.VaultService,
23
+ useFactory: async (configService) => {
24
+ const vaultService = new vault_service_1.VaultService(configService);
25
+ await vaultService.loadSecrets();
26
+ return vaultService;
27
+ },
28
+ inject: [config_1.ConfigService],
29
+ },
30
+ ],
31
+ exports: [vault_service_1.VaultService],
32
+ })
33
+ ], VaultModule);
34
+ //# sourceMappingURL=vault.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.module.js","sourceRoot":"","sources":["../../../src/modules/vault/vault.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAgD;AAChD,mDAA+C;AAC/C,2CAA6D;AAoBtD,IAAM,WAAW,GAAjB,MAAM,WAAW;CAAG,CAAA;AAAd,kCAAW;sBAAX,WAAW;IAlBvB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,qBAAY,CAAC;QACvB,SAAS,EAAE;YACT;gBACE,OAAO,EAAE,4BAAY;gBACrB,UAAU,EAAE,KAAK,EAAE,aAA4B,EAAE,EAAE;oBACjD,MAAM,YAAY,GAAG,IAAI,4BAAY,CAAC,aAAa,CAAC,CAAC;oBAErD,MAAM,YAAY,CAAC,WAAW,EAAE,CAAC;oBAEjC,OAAO,YAAY,CAAC;gBACtB,CAAC;gBACD,MAAM,EAAE,CAAC,sBAAa,CAAC;aACxB;SACF;QACD,OAAO,EAAE,CAAC,4BAAY,CAAC;KACxB,CAAC;GACW,WAAW,CAAG"}
@@ -0,0 +1,10 @@
1
+ import { ConfigService } from '@nestjs/config';
2
+ export declare class VaultService {
3
+ private configService;
4
+ constructor(configService: ConfigService);
5
+ private readonly logger;
6
+ private vaultClient;
7
+ private secrets;
8
+ loadSecrets(): Promise<void>;
9
+ get<T = string>(key: string): T;
10
+ }
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ var VaultService_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.VaultService = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const config_1 = require("@nestjs/config");
19
+ const node_vault_1 = __importDefault(require("node-vault"));
20
+ let VaultService = VaultService_1 = class VaultService {
21
+ configService;
22
+ constructor(configService) {
23
+ this.configService = configService;
24
+ }
25
+ logger = new common_1.Logger(VaultService_1.name);
26
+ vaultClient;
27
+ secrets = {};
28
+ async loadSecrets() {
29
+ this.logger.log('Đang kết nối tới Vault...');
30
+ const NODE_ENV = this.configService.get('NODE_ENV');
31
+ const isDevelopment = NODE_ENV === 'development';
32
+ const VAULT_ADDR = this.configService.get('VAULT_ADDR');
33
+ const VAULT_ROLE_ID = this.configService.get('VAULT_ROLE_ID');
34
+ const VAULT_SECRET_ID = this.configService.get('VAULT_SECRET_ID');
35
+ const VAULT_DATA_PATH = this.configService.get('VAULT_DATA_PATH');
36
+ if (!VAULT_ADDR || !VAULT_ROLE_ID || !VAULT_SECRET_ID) {
37
+ this.logger.error('Thiếu cấu hình Vault (ADDR, ROLE_ID hoặc SECRET_ID)');
38
+ throw new Error('Missing Vault configuration');
39
+ }
40
+ this.vaultClient = (0, node_vault_1.default)({
41
+ apiVersion: 'v1',
42
+ endpoint: VAULT_ADDR,
43
+ });
44
+ try {
45
+ const loginResult = await this.vaultClient.approleLogin({
46
+ role_id: VAULT_ROLE_ID,
47
+ secret_id: VAULT_SECRET_ID,
48
+ });
49
+ this.vaultClient.token = loginResult.auth.client_token;
50
+ const vaultPath = VAULT_DATA_PATH || 'secret/data/myapp';
51
+ const response = await this.vaultClient.read(vaultPath);
52
+ let fetchedSecrets = {};
53
+ if (response.data && response.data.data && response.data.metadata) {
54
+ fetchedSecrets = response.data.data;
55
+ }
56
+ else {
57
+ fetchedSecrets = response.data || {};
58
+ }
59
+ if (isDevelopment) {
60
+ const overriddenKeys = [];
61
+ Object.keys(fetchedSecrets).forEach((key) => {
62
+ const envValue = this.configService.get(key);
63
+ if (envValue !== undefined && envValue !== null && envValue !== '') {
64
+ fetchedSecrets[key] = envValue;
65
+ overriddenKeys.push(key);
66
+ }
67
+ });
68
+ this.secrets = fetchedSecrets;
69
+ if (overriddenKeys.length > 0) {
70
+ this.logger.warn(`⚠️ Các biến sau đây đang sử dụng giá trị từ ENV (ghi đè Vault): ${overriddenKeys.join(', ')}`);
71
+ }
72
+ }
73
+ else {
74
+ this.secrets = fetchedSecrets;
75
+ }
76
+ this.logger.log('Đã kết nối và lấy dữ liệu thành công từ Vault');
77
+ }
78
+ catch (error) {
79
+ this.logger.error(`Lỗi kết nối Vault: ${error.message}`, error.stack);
80
+ throw error;
81
+ }
82
+ }
83
+ get(key) {
84
+ return this.secrets[key];
85
+ }
86
+ };
87
+ exports.VaultService = VaultService;
88
+ exports.VaultService = VaultService = VaultService_1 = __decorate([
89
+ (0, common_1.Injectable)(),
90
+ __metadata("design:paramtypes", [config_1.ConfigService])
91
+ ], VaultService);
92
+ //# sourceMappingURL=vault.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.service.js","sourceRoot":"","sources":["../../../src/modules/vault/vault.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,300 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const testing_1 = require("@nestjs/testing");
7
+ const config_1 = require("@nestjs/config");
8
+ const vault_service_1 = require("./vault.service");
9
+ const node_vault_1 = __importDefault(require("node-vault"));
10
+ jest.mock('node-vault');
11
+ describe('VaultService', () => {
12
+ let service;
13
+ let configService;
14
+ let mockVaultClient;
15
+ beforeEach(async () => {
16
+ mockVaultClient = {
17
+ approleLogin: jest.fn(),
18
+ read: jest.fn(),
19
+ token: null,
20
+ };
21
+ node_vault_1.default.mockReturnValue(mockVaultClient);
22
+ const module = await testing_1.Test.createTestingModule({
23
+ providers: [
24
+ vault_service_1.VaultService,
25
+ {
26
+ provide: config_1.ConfigService,
27
+ useValue: {
28
+ get: jest.fn(),
29
+ },
30
+ },
31
+ ],
32
+ }).compile();
33
+ service = module.get(vault_service_1.VaultService);
34
+ configService = module.get(config_1.ConfigService);
35
+ });
36
+ it('should be defined', () => {
37
+ expect(service).toBeDefined();
38
+ });
39
+ describe('loadSecrets', () => {
40
+ it('should throw error when VAULT_ADDR is missing', async () => {
41
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
42
+ if (key === 'VAULT_ROLE_ID')
43
+ return 'test-role-id';
44
+ if (key === 'VAULT_SECRET_ID')
45
+ return 'test-secret-id';
46
+ return undefined;
47
+ });
48
+ await expect(service.loadSecrets()).rejects.toThrow('Missing Vault configuration');
49
+ });
50
+ it('should throw error when VAULT_ROLE_ID is missing', async () => {
51
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
52
+ if (key === 'VAULT_ADDR')
53
+ return 'http://localhost:8200';
54
+ if (key === 'VAULT_SECRET_ID')
55
+ return 'test-secret-id';
56
+ return undefined;
57
+ });
58
+ await expect(service.loadSecrets()).rejects.toThrow('Missing Vault configuration');
59
+ });
60
+ it('should throw error when VAULT_SECRET_ID is missing', async () => {
61
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
62
+ if (key === 'VAULT_ADDR')
63
+ return 'http://localhost:8200';
64
+ if (key === 'VAULT_ROLE_ID')
65
+ return 'test-role-id';
66
+ return undefined;
67
+ });
68
+ await expect(service.loadSecrets()).rejects.toThrow('Missing Vault configuration');
69
+ });
70
+ it('should successfully connect to Vault and fetch secrets with KV v2 engine', async () => {
71
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
72
+ const config = {
73
+ NODE_ENV: 'production',
74
+ VAULT_ADDR: 'http://localhost:8200',
75
+ VAULT_ROLE_ID: 'test-role-id',
76
+ VAULT_SECRET_ID: 'test-secret-id',
77
+ VAULT_DATA_PATH: 'secret/data/myapp',
78
+ };
79
+ return config[key];
80
+ });
81
+ mockVaultClient.approleLogin.mockResolvedValue({
82
+ auth: { client_token: 'test-token' },
83
+ });
84
+ mockVaultClient.read.mockResolvedValue({
85
+ data: {
86
+ data: { DB_HOST: 'localhost', DB_PORT: '5432' },
87
+ metadata: { version: 1 },
88
+ },
89
+ });
90
+ await service.loadSecrets();
91
+ expect(mockVaultClient.approleLogin).toHaveBeenCalledWith({
92
+ role_id: 'test-role-id',
93
+ secret_id: 'test-secret-id',
94
+ });
95
+ expect(mockVaultClient.token).toBe('test-token');
96
+ expect(mockVaultClient.read).toHaveBeenCalledWith('secret/data/myapp');
97
+ });
98
+ it('should successfully fetch secrets with KV v1 engine', async () => {
99
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
100
+ const config = {
101
+ NODE_ENV: 'production',
102
+ VAULT_ADDR: 'http://localhost:8200',
103
+ VAULT_ROLE_ID: 'test-role-id',
104
+ VAULT_SECRET_ID: 'test-secret-id',
105
+ VAULT_DATA_PATH: 'secret/myapp',
106
+ };
107
+ return config[key];
108
+ });
109
+ mockVaultClient.approleLogin.mockResolvedValue({
110
+ auth: { client_token: 'test-token' },
111
+ });
112
+ mockVaultClient.read.mockResolvedValue({
113
+ data: { API_KEY: 'secret-key', DB_PASSWORD: 'password123' },
114
+ });
115
+ await service.loadSecrets();
116
+ expect(service.get('API_KEY')).toBe('secret-key');
117
+ expect(service.get('DB_PASSWORD')).toBe('password123');
118
+ });
119
+ it('should override Vault secrets with ENV variables in development mode', async () => {
120
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
121
+ const config = {
122
+ NODE_ENV: 'development',
123
+ VAULT_ADDR: 'http://localhost:8200',
124
+ VAULT_ROLE_ID: 'test-role-id',
125
+ VAULT_SECRET_ID: 'test-secret-id',
126
+ VAULT_DATA_PATH: 'secret/data/myapp',
127
+ DB_HOST: 'localhost-override',
128
+ };
129
+ return config[key];
130
+ });
131
+ mockVaultClient.approleLogin.mockResolvedValue({
132
+ auth: { client_token: 'test-token' },
133
+ });
134
+ mockVaultClient.read.mockResolvedValue({
135
+ data: {
136
+ data: { DB_HOST: 'vault-host', DB_PORT: '5432' },
137
+ metadata: { version: 1 },
138
+ },
139
+ });
140
+ await service.loadSecrets();
141
+ expect(service.get('DB_HOST')).toBe('localhost-override');
142
+ expect(service.get('DB_PORT')).toBe('5432');
143
+ });
144
+ it('should not override Vault secrets with empty ENV variables in development mode', async () => {
145
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
146
+ const config = {
147
+ NODE_ENV: 'development',
148
+ VAULT_ADDR: 'http://localhost:8200',
149
+ VAULT_ROLE_ID: 'test-role-id',
150
+ VAULT_SECRET_ID: 'test-secret-id',
151
+ DB_HOST: '',
152
+ };
153
+ return config[key];
154
+ });
155
+ mockVaultClient.approleLogin.mockResolvedValue({
156
+ auth: { client_token: 'test-token' },
157
+ });
158
+ mockVaultClient.read.mockResolvedValue({
159
+ data: {
160
+ data: { DB_HOST: 'vault-host' },
161
+ metadata: { version: 1 },
162
+ },
163
+ });
164
+ await service.loadSecrets();
165
+ expect(service.get('DB_HOST')).toBe('vault-host');
166
+ });
167
+ it('should throw error when Vault login fails', async () => {
168
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
169
+ const config = {
170
+ VAULT_ADDR: 'http://localhost:8200',
171
+ VAULT_ROLE_ID: 'test-role-id',
172
+ VAULT_SECRET_ID: 'test-secret-id',
173
+ };
174
+ return config[key];
175
+ });
176
+ mockVaultClient.approleLogin.mockRejectedValue(new Error('Authentication failed'));
177
+ await expect(service.loadSecrets()).rejects.toThrow('Authentication failed');
178
+ });
179
+ it('should throw error when reading Vault path fails', async () => {
180
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
181
+ const config = {
182
+ VAULT_ADDR: 'http://localhost:8200',
183
+ VAULT_ROLE_ID: 'test-role-id',
184
+ VAULT_SECRET_ID: 'test-secret-id',
185
+ VAULT_DATA_PATH: 'secret/data/myapp',
186
+ };
187
+ return config[key];
188
+ });
189
+ mockVaultClient.approleLogin.mockResolvedValue({
190
+ auth: { client_token: 'test-token' },
191
+ });
192
+ mockVaultClient.read.mockRejectedValue(new Error('Path not found'));
193
+ await expect(service.loadSecrets()).rejects.toThrow('Path not found');
194
+ });
195
+ it('should use default VAULT_DATA_PATH when not provided', async () => {
196
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
197
+ const config = {
198
+ VAULT_ADDR: 'http://localhost:8200',
199
+ VAULT_ROLE_ID: 'test-role-id',
200
+ VAULT_SECRET_ID: 'test-secret-id',
201
+ };
202
+ return config[key];
203
+ });
204
+ mockVaultClient.approleLogin.mockResolvedValue({
205
+ auth: { client_token: 'test-token' },
206
+ });
207
+ mockVaultClient.read.mockResolvedValue({
208
+ data: { data: {}, metadata: { version: 1 } },
209
+ });
210
+ await service.loadSecrets();
211
+ expect(mockVaultClient.read).toHaveBeenCalledWith('secret/data/myapp');
212
+ });
213
+ });
214
+ describe('get', () => {
215
+ it('should return secret value for existing key', async () => {
216
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
217
+ const config = {
218
+ NODE_ENV: 'production',
219
+ VAULT_ADDR: 'http://localhost:8200',
220
+ VAULT_ROLE_ID: 'test-role-id',
221
+ VAULT_SECRET_ID: 'test-secret-id',
222
+ };
223
+ return config[key];
224
+ });
225
+ mockVaultClient.approleLogin.mockResolvedValue({
226
+ auth: { client_token: 'test-token' },
227
+ });
228
+ mockVaultClient.read.mockResolvedValue({
229
+ data: {
230
+ data: { API_KEY: 'my-secret-key' },
231
+ metadata: { version: 1 },
232
+ },
233
+ });
234
+ await service.loadSecrets();
235
+ expect(service.get('API_KEY')).toBe('my-secret-key');
236
+ });
237
+ it('should return undefined for non-existing key', async () => {
238
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
239
+ const config = {
240
+ NODE_ENV: 'production',
241
+ VAULT_ADDR: 'http://localhost:8200',
242
+ VAULT_ROLE_ID: 'test-role-id',
243
+ VAULT_SECRET_ID: 'test-secret-id',
244
+ };
245
+ return config[key];
246
+ });
247
+ mockVaultClient.approleLogin.mockResolvedValue({
248
+ auth: { client_token: 'test-token' },
249
+ });
250
+ mockVaultClient.read.mockResolvedValue({
251
+ data: { data: {}, metadata: { version: 1 } },
252
+ });
253
+ await service.loadSecrets();
254
+ expect(service.get('NON_EXISTING_KEY')).toBeUndefined();
255
+ });
256
+ it('should return typed value when type parameter is provided', async () => {
257
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
258
+ const config = {
259
+ NODE_ENV: 'production',
260
+ VAULT_ADDR: 'http://localhost:8200',
261
+ VAULT_ROLE_ID: 'test-role-id',
262
+ VAULT_SECRET_ID: 'test-secret-id',
263
+ };
264
+ return config[key];
265
+ });
266
+ mockVaultClient.approleLogin.mockResolvedValue({
267
+ auth: { client_token: 'test-token' },
268
+ });
269
+ mockVaultClient.read.mockResolvedValue({
270
+ data: {
271
+ data: { PORT: '3000', IS_ENABLED: 'true' },
272
+ metadata: { version: 1 },
273
+ },
274
+ });
275
+ await service.loadSecrets();
276
+ const port = service.get('PORT');
277
+ const isEnabled = service.get('IS_ENABLED');
278
+ expect(port).toBe('3000');
279
+ expect(isEnabled).toBe('true');
280
+ });
281
+ it('should fallback to empty object when response.data is null in KV v1', async () => {
282
+ jest.spyOn(configService, 'get').mockImplementation((key) => {
283
+ if (key === 'VAULT_ADDR')
284
+ return 'http://localhost:8200';
285
+ if (key === 'VAULT_ROLE_ID')
286
+ return 'test-role-id';
287
+ if (key === 'VAULT_SECRET_ID')
288
+ return 'test-secret-id';
289
+ return undefined;
290
+ });
291
+ mockVaultClient.approleLogin.mockResolvedValue({
292
+ auth: { client_token: 'test-token' },
293
+ });
294
+ mockVaultClient.read.mockResolvedValue({ data: null });
295
+ await service.loadSecrets();
296
+ expect(service.get('ANY_KEY')).toBeUndefined();
297
+ });
298
+ });
299
+ });
300
+ //# sourceMappingURL=vault.service.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.service.spec.js","sourceRoot":"","sources":["../../../src/modules/vault/vault.service.spec.ts"],"names":[],"mappings":"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"}