@squiz/dx-common-lib 1.71.1 → 1.72.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.
Files changed (32) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/lib/cache/applyDefaultRulesToCacheControlObject.d.ts +1 -1
  3. package/lib/index.d.ts +3 -0
  4. package/lib/index.js +3 -0
  5. package/lib/index.js.map +1 -1
  6. package/lib/secret-api-key-service/DevSecretApiKeyService.d.ts +25 -0
  7. package/lib/secret-api-key-service/DevSecretApiKeyService.js +35 -0
  8. package/lib/secret-api-key-service/DevSecretApiKeyService.js.map +1 -0
  9. package/lib/secret-api-key-service/DevSecretApiKeyService.spec.d.ts +1 -0
  10. package/lib/secret-api-key-service/DevSecretApiKeyService.spec.js +157 -0
  11. package/lib/secret-api-key-service/DevSecretApiKeyService.spec.js.map +1 -0
  12. package/lib/secret-api-key-service/SecretApiKeyService.d.ts +43 -0
  13. package/lib/secret-api-key-service/SecretApiKeyService.js +85 -0
  14. package/lib/secret-api-key-service/SecretApiKeyService.js.map +1 -0
  15. package/lib/secret-api-key-service/SecretApiKeyService.spec.d.ts +1 -0
  16. package/lib/secret-api-key-service/SecretApiKeyService.spec.js +280 -0
  17. package/lib/secret-api-key-service/SecretApiKeyService.spec.js.map +1 -0
  18. package/lib/secret-api-key-service/getSecretApiKeyService.d.ts +20 -0
  19. package/lib/secret-api-key-service/getSecretApiKeyService.js +41 -0
  20. package/lib/secret-api-key-service/getSecretApiKeyService.js.map +1 -0
  21. package/lib/secret-api-key-service/getSecretApiKeyService.spec.d.ts +1 -0
  22. package/lib/secret-api-key-service/getSecretApiKeyService.spec.js +313 -0
  23. package/lib/secret-api-key-service/getSecretApiKeyService.spec.js.map +1 -0
  24. package/package.json +4 -4
  25. package/src/index.ts +3 -0
  26. package/src/secret-api-key-service/DevSecretApiKeyService.spec.ts +211 -0
  27. package/src/secret-api-key-service/DevSecretApiKeyService.ts +36 -0
  28. package/src/secret-api-key-service/SecretApiKeyService.spec.ts +367 -0
  29. package/src/secret-api-key-service/SecretApiKeyService.ts +108 -0
  30. package/src/secret-api-key-service/getSecretApiKeyService.spec.ts +405 -0
  31. package/src/secret-api-key-service/getSecretApiKeyService.ts +45 -0
  32. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,313 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const getSecretApiKeyService_1 = require("./getSecretApiKeyService");
4
+ const DevSecretApiKeyService_1 = require("./DevSecretApiKeyService");
5
+ const SecretApiKeyService_1 = require("./SecretApiKeyService");
6
+ // Mock the util module
7
+ jest.mock('../util', () => ({
8
+ getNodeEnv: jest.fn(),
9
+ never: jest.fn((value) => {
10
+ throw new Error(`Unexpected value: ${value}`);
11
+ }),
12
+ }));
13
+ // Import the mocked function
14
+ const util_1 = require("../util");
15
+ const mockGetNodeEnv = util_1.getNodeEnv;
16
+ describe('getSecretApiKeyService', () => {
17
+ beforeEach(() => {
18
+ jest.clearAllMocks();
19
+ });
20
+ describe('Development Environment', () => {
21
+ beforeEach(() => {
22
+ mockGetNodeEnv.mockReturnValue('development');
23
+ });
24
+ it('should return EnvApiKeyService when environment is development', () => {
25
+ const envVars = {
26
+ deploymentEnvironment: 'dev',
27
+ apiKey: 'test-dev-api-key',
28
+ };
29
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
30
+ expect(service).toBeInstanceOf(DevSecretApiKeyService_1.DevSecretApiKeyService);
31
+ });
32
+ it('should pass API key to EnvApiKeyService', async () => {
33
+ const apiKey = 'my-dev-api-key-123';
34
+ const envVars = {
35
+ deploymentEnvironment: 'dev',
36
+ apiKey,
37
+ };
38
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
39
+ const result = await service.getApiKey();
40
+ expect(result).toBe(apiKey);
41
+ });
42
+ it('should create EnvApiKeyService even when awsRegion is provided', () => {
43
+ const envVars = {
44
+ deploymentEnvironment: 'dev',
45
+ apiKey: 'dev-key',
46
+ awsRegion: 'us-east-1', // This should be ignored in dev
47
+ secretName: 'some-secret', // This should also be ignored
48
+ };
49
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
50
+ expect(service).toBeInstanceOf(DevSecretApiKeyService_1.DevSecretApiKeyService);
51
+ });
52
+ it('should throw error if apiKey is empty in development', () => {
53
+ const envVars = {
54
+ deploymentEnvironment: 'dev',
55
+ apiKey: '',
56
+ };
57
+ expect(() => (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars)).toThrow('API key must be a non-empty string');
58
+ });
59
+ it('should throw error if apiKey is undefined in development', () => {
60
+ const envVars = {
61
+ deploymentEnvironment: 'dev',
62
+ apiKey: undefined,
63
+ };
64
+ // TypeScript will complain, but at runtime this could happen
65
+ expect(() => (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars)).toThrow();
66
+ });
67
+ it('should handle whitespace-only apiKey in development', () => {
68
+ const envVars = {
69
+ deploymentEnvironment: 'dev',
70
+ apiKey: ' ',
71
+ };
72
+ expect(() => (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars)).toThrow('API key must be a non-empty string');
73
+ });
74
+ });
75
+ describe('Production Environment', () => {
76
+ beforeEach(() => {
77
+ mockGetNodeEnv.mockReturnValue('production');
78
+ });
79
+ it('should return SecretApiKeyService when environment is production', () => {
80
+ const envVars = {
81
+ deploymentEnvironment: 'prod',
82
+ secretName: 'my-secret-name',
83
+ awsRegion: 'us-east-1',
84
+ };
85
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
86
+ expect(service).toBeInstanceOf(SecretApiKeyService_1.SecretApiKeyService);
87
+ });
88
+ it('should pass secretName and awsRegion to SecretApiKeyService', () => {
89
+ const secretName = '/servicekeys-prod-us/metrics-api';
90
+ const awsRegion = 'ap-southeast-2';
91
+ const envVars = {
92
+ deploymentEnvironment: 'prod',
93
+ secretName,
94
+ awsRegion,
95
+ };
96
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
97
+ expect(service).toBeInstanceOf(SecretApiKeyService_1.SecretApiKeyService);
98
+ // We can't directly inspect the private properties, but we can verify the type
99
+ });
100
+ it('should create SecretApiKeyService even when apiKey is provided', () => {
101
+ const envVars = {
102
+ deploymentEnvironment: 'prod',
103
+ apiKey: 'some-key', // This should be ignored in prod
104
+ secretName: 'my-secret',
105
+ awsRegion: 'us-west-2',
106
+ };
107
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
108
+ expect(service).toBeInstanceOf(SecretApiKeyService_1.SecretApiKeyService);
109
+ });
110
+ it('should handle production with various AWS regions', () => {
111
+ const regions = ['us-east-1', 'us-west-2', 'eu-west-1', 'ap-southeast-2', 'ap-northeast-1'];
112
+ regions.forEach((region) => {
113
+ const envVars = {
114
+ deploymentEnvironment: 'prod',
115
+ secretName: 'test-secret',
116
+ awsRegion: region,
117
+ };
118
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
119
+ expect(service).toBeInstanceOf(SecretApiKeyService_1.SecretApiKeyService);
120
+ });
121
+ });
122
+ it('should handle production with various secret name formats', () => {
123
+ const secretNames = [
124
+ '/servicekeys-prod-us/metrics',
125
+ 'servicekeys-dev-au/feaas-metrics',
126
+ 'arn:aws:secretsmanager:us-east-1:123456789:secret:metrics-key',
127
+ 'simple-secret-name',
128
+ ];
129
+ secretNames.forEach((secretName) => {
130
+ const envVars = {
131
+ deploymentEnvironment: 'prod',
132
+ secretName,
133
+ awsRegion: 'us-east-1',
134
+ };
135
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
136
+ expect(service).toBeInstanceOf(SecretApiKeyService_1.SecretApiKeyService);
137
+ });
138
+ });
139
+ });
140
+ describe('Invalid Environment', () => {
141
+ it('should throw error for test environment', () => {
142
+ mockGetNodeEnv.mockReturnValue('test');
143
+ const envVars = {
144
+ deploymentEnvironment: 'test',
145
+ apiKey: 'test-key',
146
+ };
147
+ expect(() => (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars)).toThrow();
148
+ });
149
+ it('should throw error for staging environment', () => {
150
+ mockGetNodeEnv.mockReturnValue('staging');
151
+ const envVars = {
152
+ deploymentEnvironment: 'staging',
153
+ apiKey: 'staging-key',
154
+ };
155
+ expect(() => (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars)).toThrow();
156
+ });
157
+ it('should throw error for unknown environment', () => {
158
+ mockGetNodeEnv.mockReturnValue('unknown');
159
+ const envVars = {
160
+ deploymentEnvironment: 'unknown',
161
+ apiKey: 'unknown-key',
162
+ };
163
+ expect(() => (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars)).toThrow();
164
+ });
165
+ it('should throw error for empty string environment', () => {
166
+ mockGetNodeEnv.mockReturnValue('');
167
+ const envVars = {
168
+ deploymentEnvironment: '',
169
+ apiKey: 'test-key',
170
+ };
171
+ expect(() => (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars)).toThrow();
172
+ });
173
+ });
174
+ describe('Environment Variables Validation', () => {
175
+ it('should handle envVars with all possible fields in development', () => {
176
+ mockGetNodeEnv.mockReturnValue('development');
177
+ const envVars = {
178
+ deploymentEnvironment: 'dev',
179
+ apiKey: 'dev-key',
180
+ awsRegion: 'us-east-1',
181
+ secretName: 'secret-name',
182
+ };
183
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
184
+ expect(service).toBeInstanceOf(DevSecretApiKeyService_1.DevSecretApiKeyService);
185
+ });
186
+ it('should handle envVars with only required fields for production', () => {
187
+ mockGetNodeEnv.mockReturnValue('production');
188
+ const envVars = {
189
+ deploymentEnvironment: 'prod',
190
+ secretName: 'secret-name',
191
+ awsRegion: 'us-east-1',
192
+ };
193
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
194
+ expect(service).toBeInstanceOf(SecretApiKeyService_1.SecretApiKeyService);
195
+ });
196
+ it('should handle different deployment environments', () => {
197
+ mockGetNodeEnv.mockReturnValue('development');
198
+ const deploymentEnvs = ['dev', 'development', 'local', 'dev-au', 'dev-us'];
199
+ deploymentEnvs.forEach((deploymentEnv) => {
200
+ const envVars = {
201
+ deploymentEnvironment: deploymentEnv,
202
+ apiKey: 'test-key',
203
+ };
204
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
205
+ expect(service).toBeInstanceOf(DevSecretApiKeyService_1.DevSecretApiKeyService);
206
+ });
207
+ });
208
+ });
209
+ describe('Real-world Scenarios', () => {
210
+ it('should handle local development scenario', async () => {
211
+ mockGetNodeEnv.mockReturnValue('development');
212
+ const envVars = {
213
+ deploymentEnvironment: 'dev-au',
214
+ apiKey: 'local-dev-metrics-api-key-12345',
215
+ };
216
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
217
+ const apiKey = await service.getApiKey();
218
+ expect(service).toBeInstanceOf(DevSecretApiKeyService_1.DevSecretApiKeyService);
219
+ expect(apiKey).toBe('local-dev-metrics-api-key-12345');
220
+ });
221
+ it('should handle production AWS scenario', () => {
222
+ mockGetNodeEnv.mockReturnValue('production');
223
+ const envVars = {
224
+ deploymentEnvironment: 'prod-us',
225
+ secretName: '/servicekeys-prod-us/feaas-metrics',
226
+ awsRegion: 'us-east-1',
227
+ };
228
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
229
+ expect(service).toBeInstanceOf(SecretApiKeyService_1.SecretApiKeyService);
230
+ });
231
+ it('should handle Australian region production scenario', () => {
232
+ mockGetNodeEnv.mockReturnValue('production');
233
+ const envVars = {
234
+ deploymentEnvironment: 'prod-au',
235
+ secretName: '/servicekeys-prod-au/feaas-metrics',
236
+ awsRegion: 'ap-southeast-2',
237
+ };
238
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
239
+ expect(service).toBeInstanceOf(SecretApiKeyService_1.SecretApiKeyService);
240
+ });
241
+ it('should create different instances for different calls', () => {
242
+ mockGetNodeEnv.mockReturnValue('development');
243
+ const envVars1 = {
244
+ deploymentEnvironment: 'dev',
245
+ apiKey: 'key-1',
246
+ };
247
+ const envVars2 = {
248
+ deploymentEnvironment: 'dev',
249
+ apiKey: 'key-2',
250
+ };
251
+ const service1 = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars1);
252
+ const service2 = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars2);
253
+ // Should be different instances
254
+ expect(service1).not.toBe(service2);
255
+ });
256
+ });
257
+ describe('Edge Cases', () => {
258
+ it('should handle very long secret names in production', () => {
259
+ mockGetNodeEnv.mockReturnValue('production');
260
+ const envVars = {
261
+ deploymentEnvironment: 'prod',
262
+ secretName: '/very/long/secret/path/with/many/segments/'.repeat(10),
263
+ awsRegion: 'us-east-1',
264
+ };
265
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
266
+ expect(service).toBeInstanceOf(SecretApiKeyService_1.SecretApiKeyService);
267
+ });
268
+ it('should handle very long API keys in development', () => {
269
+ mockGetNodeEnv.mockReturnValue('development');
270
+ const envVars = {
271
+ deploymentEnvironment: 'dev',
272
+ apiKey: 'x'.repeat(1000),
273
+ };
274
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
275
+ expect(service).toBeInstanceOf(DevSecretApiKeyService_1.DevSecretApiKeyService);
276
+ });
277
+ it('should handle special characters in secretName', () => {
278
+ mockGetNodeEnv.mockReturnValue('production');
279
+ const envVars = {
280
+ deploymentEnvironment: 'prod',
281
+ secretName: '/servicekeys-prod_us/feaas.metrics-api',
282
+ awsRegion: 'us-east-1',
283
+ };
284
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
285
+ expect(service).toBeInstanceOf(SecretApiKeyService_1.SecretApiKeyService);
286
+ });
287
+ });
288
+ describe('Type Safety', () => {
289
+ it('should accept all valid envVars properties', () => {
290
+ mockGetNodeEnv.mockReturnValue('development');
291
+ const envVars = {
292
+ deploymentEnvironment: 'dev',
293
+ apiKey: 'key',
294
+ awsRegion: undefined,
295
+ secretName: 'secret',
296
+ };
297
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
298
+ expect(service).toBeInstanceOf(DevSecretApiKeyService_1.DevSecretApiKeyService);
299
+ });
300
+ it('should handle optional undefined properties correctly', () => {
301
+ mockGetNodeEnv.mockReturnValue('production');
302
+ const envVars = {
303
+ deploymentEnvironment: 'prod',
304
+ apiKey: undefined,
305
+ awsRegion: 'us-east-1',
306
+ secretName: 'secret-name',
307
+ };
308
+ const service = (0, getSecretApiKeyService_1.getSecretApiKeyService)(envVars);
309
+ expect(service).toBeInstanceOf(SecretApiKeyService_1.SecretApiKeyService);
310
+ });
311
+ });
312
+ });
313
+ //# sourceMappingURL=getSecretApiKeyService.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getSecretApiKeyService.spec.js","sourceRoot":"","sources":["../../src/secret-api-key-service/getSecretApiKeyService.spec.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squiz/dx-common-lib",
3
- "version": "1.71.1",
3
+ "version": "1.72.1",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "private": false,
@@ -26,12 +26,12 @@
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/archiver": "6.0.3",
29
- "@types/express": "4.17.17",
29
+ "@types/express": "4.17.23",
30
30
  "@types/fs-extra": "11.0.1",
31
31
  "@types/jest": "28.1.8",
32
- "@types/lodash.clonedeep": "4.5.7",
32
+ "@types/lodash.clonedeep": "4.5.9",
33
33
  "@types/node": "22.10.5",
34
- "dotenv": "16.0.3",
34
+ "dotenv": "16.6.1",
35
35
  "jest": "29.4.1",
36
36
  "ts-jest": "29.0.5",
37
37
  "typescript": "^5.7.2"
package/src/index.ts CHANGED
@@ -15,3 +15,6 @@ export * from './edge-components-secret-key-service/ProductionEdgeComponentsSecr
15
15
  export * from './edge-components-secret-key-service/EdgeComponentsSecretKeyService';
16
16
  export * from './edge-components-secret-key-service/getEdgeComponentsSecretService';
17
17
  export * from './esi-mac-token-generator/EsiMacTokenGenerator';
18
+ export * from './secret-api-key-service/SecretApiKeyService';
19
+ export * from './secret-api-key-service/DevSecretApiKeyService';
20
+ export * from './secret-api-key-service/getSecretApiKeyService';
@@ -0,0 +1,211 @@
1
+ import { DevSecretApiKeyService } from './DevSecretApiKeyService';
2
+
3
+ describe('DevSecretApiKeyService', () => {
4
+ describe('Constructor', () => {
5
+ it('should successfully create service with valid API key', () => {
6
+ const apiKey = 'test-api-key-12345';
7
+ const service = new DevSecretApiKeyService(apiKey);
8
+
9
+ expect(service).toBeInstanceOf(DevSecretApiKeyService);
10
+ });
11
+
12
+ it('should throw error when API key is empty string', () => {
13
+ expect(() => new DevSecretApiKeyService('')).toThrow('API key must be a non-empty string');
14
+ });
15
+
16
+ it('should throw error when API key is whitespace only', () => {
17
+ expect(() => new DevSecretApiKeyService(' ')).toThrow('API key must be a non-empty string');
18
+ });
19
+
20
+ it('should throw error when API key is only tabs', () => {
21
+ expect(() => new DevSecretApiKeyService('\t\t')).toThrow('API key must be a non-empty string');
22
+ });
23
+
24
+ it('should throw error when API key is only newlines', () => {
25
+ expect(() => new DevSecretApiKeyService('\n\n')).toThrow('API key must be a non-empty string');
26
+ });
27
+
28
+ it('should accept API key with surrounding whitespace', () => {
29
+ // Note: The constructor checks trimmed length, but stores the original value
30
+ const apiKey = ' valid-key ';
31
+ expect(() => new DevSecretApiKeyService(apiKey)).not.toThrow();
32
+ });
33
+ });
34
+
35
+ describe('getApiKey', () => {
36
+ it('should return the API key provided in constructor', async () => {
37
+ const apiKey = 'test-api-key-xyz';
38
+ const service = new DevSecretApiKeyService(apiKey);
39
+
40
+ const result = await service.getApiKey();
41
+
42
+ expect(result).toBe(apiKey);
43
+ });
44
+
45
+ it('should return same API key on multiple calls', async () => {
46
+ const apiKey = 'consistent-api-key';
47
+ const service = new DevSecretApiKeyService(apiKey);
48
+
49
+ const result1 = await service.getApiKey();
50
+ const result2 = await service.getApiKey();
51
+ const result3 = await service.getApiKey();
52
+
53
+ expect(result1).toBe(apiKey);
54
+ expect(result2).toBe(apiKey);
55
+ expect(result3).toBe(apiKey);
56
+ });
57
+
58
+ it('should handle concurrent calls efficiently', async () => {
59
+ const apiKey = 'concurrent-test-key';
60
+ const service = new DevSecretApiKeyService(apiKey);
61
+
62
+ // Make multiple concurrent calls
63
+ const promises = Array(10)
64
+ .fill(null)
65
+ .map(() => service.getApiKey());
66
+
67
+ const results = await Promise.all(promises);
68
+
69
+ // All should return the same key
70
+ expect(results).toEqual(Array(10).fill(apiKey));
71
+ });
72
+ });
73
+
74
+ describe('Edge Cases', () => {
75
+ it('should handle very long API keys', async () => {
76
+ const apiKey = 'x'.repeat(1000); // 1000 character API key
77
+ const service = new DevSecretApiKeyService(apiKey);
78
+
79
+ const result = await service.getApiKey();
80
+
81
+ expect(result).toBe(apiKey);
82
+ });
83
+
84
+ it('should handle special characters in API key', async () => {
85
+ const apiKey = 'test-key-!@#$%^&*()_+-=[]{}|;:"<>,.?/~`';
86
+ const service = new DevSecretApiKeyService(apiKey);
87
+
88
+ const result = await service.getApiKey();
89
+
90
+ expect(result).toBe(apiKey);
91
+ });
92
+
93
+ it('should handle unicode characters in API key', async () => {
94
+ const apiKey = 'test-key-你好-مرحبا-🔑';
95
+ const service = new DevSecretApiKeyService(apiKey);
96
+
97
+ const result = await service.getApiKey();
98
+
99
+ expect(result).toBe(apiKey);
100
+ });
101
+
102
+ it('should handle API key with line breaks', async () => {
103
+ const apiKey = 'key-with\nline\nbreaks';
104
+ const service = new DevSecretApiKeyService(apiKey);
105
+
106
+ const result = await service.getApiKey();
107
+
108
+ expect(result).toBe(apiKey);
109
+ });
110
+
111
+ it('should handle base64-like API keys', async () => {
112
+ const apiKey =
113
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
114
+ const service = new DevSecretApiKeyService(apiKey);
115
+
116
+ const result = await service.getApiKey();
117
+
118
+ expect(result).toBe(apiKey);
119
+ });
120
+
121
+ it('should handle UUID-format API keys', async () => {
122
+ const apiKey = '550e8400-e29b-41d4-a716-446655440000';
123
+ const service = new DevSecretApiKeyService(apiKey);
124
+
125
+ const result = await service.getApiKey();
126
+
127
+ expect(result).toBe(apiKey);
128
+ });
129
+
130
+ it('should handle hexadecimal API keys', async () => {
131
+ const apiKey = 'a1b2c3d4e5f6789012345678901234567890abcdef';
132
+ const service = new DevSecretApiKeyService(apiKey);
133
+
134
+ const result = await service.getApiKey();
135
+
136
+ expect(result).toBe(apiKey);
137
+ });
138
+ });
139
+
140
+ describe('Interface Compliance', () => {
141
+ it('should implement SecretApiKeyServiceInterface', async () => {
142
+ const service = new DevSecretApiKeyService('test-key');
143
+
144
+ // Check that the required methods exist
145
+ expect(typeof service.getApiKey).toBe('function');
146
+ });
147
+
148
+ it('should return a Promise from getApiKey', () => {
149
+ const service = new DevSecretApiKeyService('test-key');
150
+ const result = service.getApiKey();
151
+
152
+ expect(result).toBeInstanceOf(Promise);
153
+ });
154
+ });
155
+
156
+ describe('Memory and Performance', () => {
157
+ it('should not modify the API key after construction', async () => {
158
+ const originalKey = 'immutable-key-123';
159
+ const service = new DevSecretApiKeyService(originalKey);
160
+
161
+ // Get the key multiple times
162
+ await service.getApiKey();
163
+ await service.getApiKey();
164
+ await service.getApiKey();
165
+
166
+ // Key should still be the same
167
+ const result = await service.getApiKey();
168
+ expect(result).toBe(originalKey);
169
+ });
170
+
171
+ it('should handle rapid sequential calls', async () => {
172
+ const apiKey = 'rapid-call-key';
173
+ const service = new DevSecretApiKeyService(apiKey);
174
+
175
+ // Make rapid sequential calls
176
+ for (let i = 0; i < 100; i++) {
177
+ const result = await service.getApiKey();
178
+ expect(result).toBe(apiKey);
179
+ }
180
+ });
181
+ });
182
+
183
+ describe('Real-world Scenarios', () => {
184
+ it('should work with typical metrics service API key format', async () => {
185
+ const apiKey = 'metrics-api-key-prod-abc123def456';
186
+ const service = new DevSecretApiKeyService(apiKey);
187
+
188
+ const result = await service.getApiKey();
189
+
190
+ expect(result).toBe(apiKey);
191
+ });
192
+
193
+ it('should work with AWS-style secret format', async () => {
194
+ const apiKey = 'aws-secret-key-AKIAIOSFODNN7EXAMPLE';
195
+ const service = new DevSecretApiKeyService(apiKey);
196
+
197
+ const result = await service.getApiKey();
198
+
199
+ expect(result).toBe(apiKey);
200
+ });
201
+
202
+ it('should work with Bearer token format', async () => {
203
+ const apiKey = 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9';
204
+ const service = new DevSecretApiKeyService(apiKey);
205
+
206
+ const result = await service.getApiKey();
207
+
208
+ expect(result).toBe(apiKey);
209
+ });
210
+ });
211
+ });
@@ -0,0 +1,36 @@
1
+ /*!
2
+ * @file EnvApiKeyService.ts
3
+ * @description Retrieves API key from environment variable (for local development).
4
+ * @author Squiz
5
+ * @copyright 2025 Squiz
6
+ * @license MIT
7
+ */
8
+
9
+ import { SecretApiKeyServiceInterface } from './SecretApiKeyService';
10
+
11
+ /**
12
+ * Service for retrieving API keys from environment variables.
13
+ * Used for local development as an alternative to AWS Secrets Manager.
14
+ */
15
+ export class DevSecretApiKeyService implements SecretApiKeyServiceInterface {
16
+ private readonly apiKey: string;
17
+
18
+ /**
19
+ * Constructor for EnvApiKeyService
20
+ * @param apiKey The API key value from environment variable
21
+ */
22
+ constructor(apiKey: string) {
23
+ if (!apiKey || apiKey.trim().length === 0) {
24
+ throw new Error('API key must be a non-empty string');
25
+ }
26
+ this.apiKey = apiKey;
27
+ }
28
+
29
+ /**
30
+ * Returns the API key.
31
+ * @returns The API key string
32
+ */
33
+ public async getApiKey(): Promise<string> {
34
+ return this.apiKey;
35
+ }
36
+ }