@claude-flow/security 3.0.0-alpha.1 → 3.0.0-alpha.11

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 (150) hide show
  1. package/README.md +292 -234
  2. package/__tests__/acceptance/security-compliance.test.ts +674 -674
  3. package/__tests__/authorization-propagator.test.ts +155 -0
  4. package/__tests__/credential-generator.test.ts +310 -310
  5. package/__tests__/fixtures/configurations.ts +425 -419
  6. package/__tests__/fixtures/index.ts +21 -21
  7. package/__tests__/helpers/create-mock.ts +469 -469
  8. package/__tests__/helpers/index.ts +32 -32
  9. package/__tests__/input-validator.test.ts +382 -381
  10. package/__tests__/integration/security-flow.test.ts +606 -606
  11. package/__tests__/keychain-adapter.test.ts +60 -0
  12. package/__tests__/oauth-browser.test.ts +13 -0
  13. package/__tests__/oauth-export-surface.test.ts +21 -0
  14. package/__tests__/oauth-pkce.test.ts +37 -0
  15. package/__tests__/password-hasher.test.ts +239 -239
  16. package/__tests__/path-validator.test.ts +302 -302
  17. package/__tests__/plugin-integrity-verifier.test.ts +199 -0
  18. package/__tests__/safe-executor.test.ts +292 -292
  19. package/__tests__/token-generator.test.ts +371 -371
  20. package/__tests__/tool-output-guardrail.test.ts +256 -0
  21. package/__tests__/unit/credential-generator.test.ts +182 -182
  22. package/__tests__/unit/password-hasher.test.ts +359 -359
  23. package/__tests__/unit/path-validator.test.ts +509 -509
  24. package/__tests__/unit/safe-executor.test.ts +667 -667
  25. package/__tests__/unit/token-generator.test.ts +310 -310
  26. package/dist/CVE-REMEDIATION.d.ts +17 -6
  27. package/dist/CVE-REMEDIATION.d.ts.map +1 -1
  28. package/dist/CVE-REMEDIATION.js +328 -12
  29. package/dist/CVE-REMEDIATION.js.map +1 -1
  30. package/dist/authorization/propagator.d.ts +148 -0
  31. package/dist/authorization/propagator.d.ts.map +1 -0
  32. package/dist/authorization/propagator.js +182 -0
  33. package/dist/authorization/propagator.js.map +1 -0
  34. package/dist/credential-generator.js +9 -9
  35. package/dist/domain/services/security-domain-service.js +1 -1
  36. package/dist/domain/services/security-domain-service.js.map +1 -1
  37. package/dist/index.d.ts +9 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +21 -1
  40. package/dist/index.js.map +1 -1
  41. package/dist/keychain-adapter.d.ts +48 -0
  42. package/dist/keychain-adapter.d.ts.map +1 -0
  43. package/dist/keychain-adapter.js +0 -0
  44. package/dist/keychain-adapter.js.map +1 -0
  45. package/dist/oauth/browser.d.ts +31 -0
  46. package/dist/oauth/browser.d.ts.map +1 -0
  47. package/dist/oauth/browser.js +55 -0
  48. package/dist/oauth/browser.js.map +1 -0
  49. package/dist/oauth/callback-server.d.ts +37 -0
  50. package/dist/oauth/callback-server.d.ts.map +1 -0
  51. package/dist/oauth/callback-server.js +86 -0
  52. package/dist/oauth/callback-server.js.map +1 -0
  53. package/dist/oauth/client.d.ts +57 -0
  54. package/dist/oauth/client.d.ts.map +1 -0
  55. package/dist/oauth/client.js +120 -0
  56. package/dist/oauth/client.js.map +1 -0
  57. package/dist/oauth/pkce.d.ts +25 -0
  58. package/dist/oauth/pkce.d.ts.map +1 -0
  59. package/dist/oauth/pkce.js +36 -0
  60. package/dist/oauth/pkce.js.map +1 -0
  61. package/dist/password-hasher.d.ts.map +1 -1
  62. package/dist/password-hasher.js +8 -1
  63. package/dist/password-hasher.js.map +1 -1
  64. package/dist/plugins/integrity-verifier.d.ts +125 -0
  65. package/dist/plugins/integrity-verifier.d.ts.map +1 -0
  66. package/dist/plugins/integrity-verifier.js +186 -0
  67. package/dist/plugins/integrity-verifier.js.map +1 -0
  68. package/dist/safe-executor.d.ts +7 -0
  69. package/dist/safe-executor.d.ts.map +1 -1
  70. package/dist/safe-executor.js +21 -1
  71. package/dist/safe-executor.js.map +1 -1
  72. package/dist/tool-output-guardrail.d.ts +126 -0
  73. package/dist/tool-output-guardrail.d.ts.map +1 -0
  74. package/dist/tool-output-guardrail.js +257 -0
  75. package/dist/tool-output-guardrail.js.map +1 -0
  76. package/node_modules-incomplete-release-test/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  77. package/package.json +33 -28
  78. package/scripts/verify-oauth-exports.mjs +29 -0
  79. package/src/CVE-REMEDIATION.ts +591 -251
  80. package/src/application/index.ts +10 -10
  81. package/src/application/services/security-application-service.ts +193 -193
  82. package/src/authorization/propagator.ts +279 -0
  83. package/src/credential-generator.ts +368 -368
  84. package/src/domain/entities/security-context.ts +173 -173
  85. package/src/domain/index.ts +17 -17
  86. package/src/domain/services/security-domain-service.ts +296 -296
  87. package/src/index.ts +340 -271
  88. package/src/input-validator.ts +466 -466
  89. package/src/keychain-adapter.ts +0 -0
  90. package/src/oauth/browser.ts +58 -0
  91. package/src/oauth/callback-server.ts +97 -0
  92. package/src/oauth/client.ts +153 -0
  93. package/src/oauth/pkce.ts +45 -0
  94. package/src/password-hasher.ts +277 -270
  95. package/src/path-validator.ts +525 -525
  96. package/src/plugins/integrity-verifier.ts +265 -0
  97. package/src/safe-executor.ts +546 -525
  98. package/src/token-generator.ts +463 -463
  99. package/src/tool-output-guardrail.ts +360 -0
  100. package/tmp.json +0 -0
  101. package/tsconfig.json +9 -9
  102. package/tsconfig.tsbuildinfo +1 -1
  103. package/vitest.config.ts +20 -0
  104. package/.agentic-flow/intelligence.json +0 -16
  105. package/__tests__/coverage/base.css +0 -224
  106. package/__tests__/coverage/block-navigation.js +0 -87
  107. package/__tests__/coverage/coverage-final.json +0 -11
  108. package/__tests__/coverage/favicon.png +0 -0
  109. package/__tests__/coverage/index.html +0 -161
  110. package/__tests__/coverage/lcov-report/base.css +0 -224
  111. package/__tests__/coverage/lcov-report/block-navigation.js +0 -87
  112. package/__tests__/coverage/lcov-report/favicon.png +0 -0
  113. package/__tests__/coverage/lcov-report/index.html +0 -161
  114. package/__tests__/coverage/lcov-report/prettify.css +0 -1
  115. package/__tests__/coverage/lcov-report/prettify.js +0 -2
  116. package/__tests__/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  117. package/__tests__/coverage/lcov-report/sorter.js +0 -210
  118. package/__tests__/coverage/lcov-report/src/CVE-REMEDIATION.ts.html +0 -838
  119. package/__tests__/coverage/lcov-report/src/application/services/index.html +0 -116
  120. package/__tests__/coverage/lcov-report/src/application/services/security-application-service.ts.html +0 -664
  121. package/__tests__/coverage/lcov-report/src/credential-generator.ts.html +0 -1189
  122. package/__tests__/coverage/lcov-report/src/domain/entities/index.html +0 -116
  123. package/__tests__/coverage/lcov-report/src/domain/entities/security-context.ts.html +0 -604
  124. package/__tests__/coverage/lcov-report/src/domain/services/index.html +0 -116
  125. package/__tests__/coverage/lcov-report/src/domain/services/security-domain-service.ts.html +0 -973
  126. package/__tests__/coverage/lcov-report/src/index.html +0 -206
  127. package/__tests__/coverage/lcov-report/src/input-validator.ts.html +0 -1483
  128. package/__tests__/coverage/lcov-report/src/password-hasher.ts.html +0 -895
  129. package/__tests__/coverage/lcov-report/src/path-validator.ts.html +0 -1660
  130. package/__tests__/coverage/lcov-report/src/safe-executor.ts.html +0 -1660
  131. package/__tests__/coverage/lcov-report/src/token-generator.ts.html +0 -1474
  132. package/__tests__/coverage/lcov.info +0 -3650
  133. package/__tests__/coverage/prettify.css +0 -1
  134. package/__tests__/coverage/prettify.js +0 -2
  135. package/__tests__/coverage/sort-arrow-sprite.png +0 -0
  136. package/__tests__/coverage/sorter.js +0 -210
  137. package/__tests__/coverage/src/CVE-REMEDIATION.ts.html +0 -838
  138. package/__tests__/coverage/src/application/services/index.html +0 -116
  139. package/__tests__/coverage/src/application/services/security-application-service.ts.html +0 -664
  140. package/__tests__/coverage/src/credential-generator.ts.html +0 -1189
  141. package/__tests__/coverage/src/domain/entities/index.html +0 -116
  142. package/__tests__/coverage/src/domain/entities/security-context.ts.html +0 -604
  143. package/__tests__/coverage/src/domain/services/index.html +0 -116
  144. package/__tests__/coverage/src/domain/services/security-domain-service.ts.html +0 -973
  145. package/__tests__/coverage/src/index.html +0 -206
  146. package/__tests__/coverage/src/input-validator.ts.html +0 -1483
  147. package/__tests__/coverage/src/password-hasher.ts.html +0 -895
  148. package/__tests__/coverage/src/path-validator.ts.html +0 -1660
  149. package/__tests__/coverage/src/safe-executor.ts.html +0 -1660
  150. package/__tests__/coverage/src/token-generator.ts.html +0 -1474
@@ -1,310 +1,310 @@
1
- /**
2
- * Credential Generator Tests - CVE-3 Remediation Validation
3
- *
4
- * Tests verify:
5
- * - Cryptographically secure random generation
6
- * - No hardcoded defaults
7
- * - Proper entropy levels
8
- * - Unique credentials per generation
9
- */
10
-
11
- import { describe, it, expect, beforeEach } from 'vitest';
12
- import {
13
- CredentialGenerator,
14
- CredentialGeneratorError,
15
- createCredentialGenerator,
16
- generateCredentials,
17
- } from '../../security/credential-generator.js';
18
-
19
- describe('CredentialGenerator', () => {
20
- let generator: CredentialGenerator;
21
-
22
- beforeEach(() => {
23
- generator = new CredentialGenerator();
24
- });
25
-
26
- describe('Configuration', () => {
27
- it('should use default configuration', () => {
28
- expect(() => new CredentialGenerator()).not.toThrow();
29
- });
30
-
31
- it('should reject password length below 16', () => {
32
- expect(() => new CredentialGenerator({
33
- passwordLength: 8,
34
- })).toThrow(CredentialGeneratorError);
35
- });
36
-
37
- it('should reject API key length below 32', () => {
38
- expect(() => new CredentialGenerator({
39
- apiKeyLength: 16,
40
- })).toThrow(CredentialGeneratorError);
41
- });
42
-
43
- it('should reject secret length below 32', () => {
44
- expect(() => new CredentialGenerator({
45
- secretLength: 16,
46
- })).toThrow(CredentialGeneratorError);
47
- });
48
- });
49
-
50
- describe('Password Generation', () => {
51
- it('should generate password of specified length', () => {
52
- const password = generator.generatePassword();
53
- expect(password.length).toBeGreaterThanOrEqual(32);
54
- });
55
-
56
- it('should generate unique passwords', () => {
57
- const passwords = new Set<string>();
58
- for (let i = 0; i < 100; i++) {
59
- passwords.add(generator.generatePassword());
60
- }
61
- expect(passwords.size).toBe(100);
62
- });
63
-
64
- it('should include required character types', () => {
65
- for (let i = 0; i < 10; i++) {
66
- const password = generator.generatePassword();
67
- expect(password).toMatch(/[A-Z]/); // Uppercase
68
- expect(password).toMatch(/[a-z]/); // Lowercase
69
- expect(password).toMatch(/\d/); // Digit
70
- expect(password).toMatch(/[!@#$%^&*()_+\-=\[\]{}|;:,.<>?]/); // Special
71
- }
72
- });
73
- });
74
-
75
- describe('API Key Generation', () => {
76
- it('should generate API key with prefix', () => {
77
- const { key, prefix } = generator.generateApiKey('cf_');
78
- expect(key.startsWith('cf_')).toBe(true);
79
- expect(prefix).toBe('cf_');
80
- });
81
-
82
- it('should generate unique keys', () => {
83
- const keys = new Set<string>();
84
- for (let i = 0; i < 100; i++) {
85
- keys.add(generator.generateApiKey().key);
86
- }
87
- expect(keys.size).toBe(100);
88
- });
89
-
90
- it('should include keyId', () => {
91
- const { keyId } = generator.generateApiKey();
92
- // Should be a valid UUID
93
- expect(keyId).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i);
94
- });
95
-
96
- it('should include createdAt timestamp', () => {
97
- const { createdAt } = generator.generateApiKey();
98
- expect(createdAt).toBeInstanceOf(Date);
99
- });
100
- });
101
-
102
- describe('Secret Generation', () => {
103
- it('should generate hex-encoded secret', () => {
104
- const secret = generator.generateSecret();
105
- expect(secret).toMatch(/^[0-9a-f]+$/);
106
- });
107
-
108
- it('should generate secret of specified length', () => {
109
- const secret = generator.generateSecret(64);
110
- expect(secret.length).toBe(64);
111
- });
112
-
113
- it('should generate unique secrets', () => {
114
- const secrets = new Set<string>();
115
- for (let i = 0; i < 100; i++) {
116
- secrets.add(generator.generateSecret());
117
- }
118
- expect(secrets.size).toBe(100);
119
- });
120
- });
121
-
122
- describe('Encryption Key Generation', () => {
123
- it('should generate 32-byte (256-bit) key as hex', () => {
124
- const key = generator.generateEncryptionKey();
125
- // 32 bytes = 64 hex characters
126
- expect(key.length).toBe(64);
127
- expect(key).toMatch(/^[0-9a-f]+$/);
128
- });
129
-
130
- it('should generate unique keys', () => {
131
- const keys = new Set<string>();
132
- for (let i = 0; i < 100; i++) {
133
- keys.add(generator.generateEncryptionKey());
134
- }
135
- expect(keys.size).toBe(100);
136
- });
137
- });
138
-
139
- describe('Installation Credentials', () => {
140
- it('should generate complete credential set', () => {
141
- const credentials = generator.generateInstallationCredentials();
142
-
143
- expect(credentials.adminPassword).toBeDefined();
144
- expect(credentials.servicePassword).toBeDefined();
145
- expect(credentials.jwtSecret).toBeDefined();
146
- expect(credentials.sessionSecret).toBeDefined();
147
- expect(credentials.encryptionKey).toBeDefined();
148
- expect(credentials.generatedAt).toBeInstanceOf(Date);
149
- });
150
-
151
- it('should set expiration when specified', () => {
152
- const credentials = generator.generateInstallationCredentials(30);
153
-
154
- expect(credentials.expiresAt).toBeInstanceOf(Date);
155
-
156
- // Should be approximately 30 days in the future
157
- const expectedExpiration = Date.now() + 30 * 24 * 60 * 60 * 1000;
158
- const actualExpiration = credentials.expiresAt!.getTime();
159
- expect(Math.abs(actualExpiration - expectedExpiration)).toBeLessThan(1000);
160
- });
161
-
162
- it('should generate unique credentials each time', () => {
163
- const cred1 = generator.generateInstallationCredentials();
164
- const cred2 = generator.generateInstallationCredentials();
165
-
166
- expect(cred1.adminPassword).not.toBe(cred2.adminPassword);
167
- expect(cred1.servicePassword).not.toBe(cred2.servicePassword);
168
- expect(cred1.jwtSecret).not.toBe(cred2.jwtSecret);
169
- });
170
- });
171
-
172
- describe('Token Generation', () => {
173
- it('should generate session token', () => {
174
- const token = generator.generateSessionToken();
175
- expect(token).toBeDefined();
176
- expect(token.length).toBeGreaterThan(0);
177
- });
178
-
179
- it('should generate CSRF token', () => {
180
- const token = generator.generateCsrfToken();
181
- expect(token).toBeDefined();
182
- // Base64url encoded
183
- expect(token).toMatch(/^[A-Za-z0-9_-]+$/);
184
- });
185
-
186
- it('should generate nonce', () => {
187
- const nonce = generator.generateNonce();
188
- expect(nonce).toBeDefined();
189
- // Hex encoded, 16 bytes = 32 chars
190
- expect(nonce.length).toBe(32);
191
- expect(nonce).toMatch(/^[0-9a-f]+$/);
192
- });
193
- });
194
-
195
- describe('Environment Script Generation', () => {
196
- it('should generate valid shell script', () => {
197
- const credentials = generator.generateInstallationCredentials();
198
- const script = generator.createEnvScript(credentials);
199
-
200
- expect(script).toContain('export CLAUDE_FLOW_ADMIN_PASSWORD=');
201
- expect(script).toContain('export CLAUDE_FLOW_SERVICE_PASSWORD=');
202
- expect(script).toContain('export CLAUDE_FLOW_JWT_SECRET=');
203
- expect(script).toContain('export CLAUDE_FLOW_SESSION_SECRET=');
204
- expect(script).toContain('export CLAUDE_FLOW_ENCRYPTION_KEY=');
205
- });
206
-
207
- it('should include warning comment', () => {
208
- const credentials = generator.generateInstallationCredentials();
209
- const script = generator.createEnvScript(credentials);
210
-
211
- expect(script).toContain('Store these securely');
212
- });
213
- });
214
-
215
- describe('JSON Config Generation', () => {
216
- it('should generate valid JSON', () => {
217
- const credentials = generator.generateInstallationCredentials();
218
- const json = generator.createJsonConfig(credentials);
219
-
220
- expect(() => JSON.parse(json)).not.toThrow();
221
- });
222
-
223
- it('should include all credentials', () => {
224
- const credentials = generator.generateInstallationCredentials();
225
- const json = generator.createJsonConfig(credentials);
226
- const parsed = JSON.parse(json);
227
-
228
- expect(parsed['claude-flow/admin-password']).toBe(credentials.adminPassword);
229
- expect(parsed['claude-flow/service-password']).toBe(credentials.servicePassword);
230
- expect(parsed['claude-flow/jwt-secret']).toBe(credentials.jwtSecret);
231
- expect(parsed['claude-flow/session-secret']).toBe(credentials.sessionSecret);
232
- expect(parsed['claude-flow/encryption-key']).toBe(credentials.encryptionKey);
233
- });
234
- });
235
-
236
- describe('Factory Functions', () => {
237
- it('should create generator with factory function', () => {
238
- const gen = createCredentialGenerator();
239
- expect(gen).toBeInstanceOf(CredentialGenerator);
240
- });
241
-
242
- it('should generate credentials with quick function', () => {
243
- const credentials = generateCredentials();
244
- expect(credentials.adminPassword).toBeDefined();
245
- expect(credentials.jwtSecret).toBeDefined();
246
- });
247
- });
248
-
249
- describe('CVE-3 Security Verification', () => {
250
- it('should NOT produce hardcoded admin123 password', () => {
251
- for (let i = 0; i < 100; i++) {
252
- const credentials = generator.generateInstallationCredentials();
253
- expect(credentials.adminPassword).not.toBe('admin123');
254
- expect(credentials.servicePassword).not.toBe('service123');
255
- }
256
- });
257
-
258
- it('should NOT produce predictable patterns', () => {
259
- const passwords = new Set<string>();
260
- for (let i = 0; i < 1000; i++) {
261
- passwords.add(generator.generatePassword());
262
- }
263
-
264
- // All should be unique
265
- expect(passwords.size).toBe(1000);
266
-
267
- // None should match common patterns
268
- const commonPatterns = ['password', 'admin', 'service', '123456', 'qwerty'];
269
- for (const password of passwords) {
270
- for (const pattern of commonPatterns) {
271
- expect(password.toLowerCase()).not.toContain(pattern);
272
- }
273
- }
274
- });
275
-
276
- it('should use cryptographically secure random', () => {
277
- // Generate many passwords and verify entropy
278
- const passwords: string[] = [];
279
- for (let i = 0; i < 100; i++) {
280
- passwords.push(generator.generatePassword());
281
- }
282
-
283
- // Calculate average character distribution
284
- const charCounts = new Map<string, number>();
285
- for (const password of passwords) {
286
- for (const char of password) {
287
- charCounts.set(char, (charCounts.get(char) || 0) + 1);
288
- }
289
- }
290
-
291
- // Should have good distribution (many different characters)
292
- expect(charCounts.size).toBeGreaterThan(30);
293
- });
294
-
295
- it('should generate installation credentials with sufficient entropy', () => {
296
- const credentials = generator.generateInstallationCredentials();
297
-
298
- // Password should be at least 256 bits of entropy at minimum
299
- expect(credentials.adminPassword.length).toBeGreaterThanOrEqual(32);
300
- expect(credentials.servicePassword.length).toBeGreaterThanOrEqual(32);
301
-
302
- // Secrets should be 512 bits
303
- expect(credentials.jwtSecret.length).toBeGreaterThanOrEqual(64);
304
- expect(credentials.sessionSecret.length).toBeGreaterThanOrEqual(64);
305
-
306
- // Encryption key should be exactly 256 bits (64 hex chars)
307
- expect(credentials.encryptionKey.length).toBe(64);
308
- });
309
- });
310
- });
1
+ /**
2
+ * Credential Generator Tests - CVE-3 Remediation Validation
3
+ *
4
+ * Tests verify:
5
+ * - Cryptographically secure random generation
6
+ * - No hardcoded defaults
7
+ * - Proper entropy levels
8
+ * - Unique credentials per generation
9
+ */
10
+
11
+ import { describe, it, expect, beforeEach } from 'vitest';
12
+ import {
13
+ CredentialGenerator,
14
+ CredentialGeneratorError,
15
+ createCredentialGenerator,
16
+ generateCredentials,
17
+ } from '../src/credential-generator.js';
18
+
19
+ describe('CredentialGenerator', () => {
20
+ let generator: CredentialGenerator;
21
+
22
+ beforeEach(() => {
23
+ generator = new CredentialGenerator();
24
+ });
25
+
26
+ describe('Configuration', () => {
27
+ it('should use default configuration', () => {
28
+ expect(() => new CredentialGenerator()).not.toThrow();
29
+ });
30
+
31
+ it('should reject password length below 16', () => {
32
+ expect(() => new CredentialGenerator({
33
+ passwordLength: 8,
34
+ })).toThrow(CredentialGeneratorError);
35
+ });
36
+
37
+ it('should reject API key length below 32', () => {
38
+ expect(() => new CredentialGenerator({
39
+ apiKeyLength: 16,
40
+ })).toThrow(CredentialGeneratorError);
41
+ });
42
+
43
+ it('should reject secret length below 32', () => {
44
+ expect(() => new CredentialGenerator({
45
+ secretLength: 16,
46
+ })).toThrow(CredentialGeneratorError);
47
+ });
48
+ });
49
+
50
+ describe('Password Generation', () => {
51
+ it('should generate password of specified length', () => {
52
+ const password = generator.generatePassword();
53
+ expect(password.length).toBeGreaterThanOrEqual(32);
54
+ });
55
+
56
+ it('should generate unique passwords', () => {
57
+ const passwords = new Set<string>();
58
+ for (let i = 0; i < 100; i++) {
59
+ passwords.add(generator.generatePassword());
60
+ }
61
+ expect(passwords.size).toBe(100);
62
+ });
63
+
64
+ it('should include required character types', () => {
65
+ for (let i = 0; i < 10; i++) {
66
+ const password = generator.generatePassword();
67
+ expect(password).toMatch(/[A-Z]/); // Uppercase
68
+ expect(password).toMatch(/[a-z]/); // Lowercase
69
+ expect(password).toMatch(/\d/); // Digit
70
+ expect(password).toMatch(/[!@#$%^&*()_+\-=\[\]{}|;:,.<>?]/); // Special
71
+ }
72
+ });
73
+ });
74
+
75
+ describe('API Key Generation', () => {
76
+ it('should generate API key with prefix', () => {
77
+ const { key, prefix } = generator.generateApiKey('cf_');
78
+ expect(key.startsWith('cf_')).toBe(true);
79
+ expect(prefix).toBe('cf_');
80
+ });
81
+
82
+ it('should generate unique keys', () => {
83
+ const keys = new Set<string>();
84
+ for (let i = 0; i < 100; i++) {
85
+ keys.add(generator.generateApiKey().key);
86
+ }
87
+ expect(keys.size).toBe(100);
88
+ });
89
+
90
+ it('should include keyId', () => {
91
+ const { keyId } = generator.generateApiKey();
92
+ // Should be a valid UUID
93
+ expect(keyId).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i);
94
+ });
95
+
96
+ it('should include createdAt timestamp', () => {
97
+ const { createdAt } = generator.generateApiKey();
98
+ expect(createdAt).toBeInstanceOf(Date);
99
+ });
100
+ });
101
+
102
+ describe('Secret Generation', () => {
103
+ it('should generate hex-encoded secret', () => {
104
+ const secret = generator.generateSecret();
105
+ expect(secret).toMatch(/^[0-9a-f]+$/);
106
+ });
107
+
108
+ it('should generate secret of specified length', () => {
109
+ const secret = generator.generateSecret(64);
110
+ expect(secret.length).toBe(64);
111
+ });
112
+
113
+ it('should generate unique secrets', () => {
114
+ const secrets = new Set<string>();
115
+ for (let i = 0; i < 100; i++) {
116
+ secrets.add(generator.generateSecret());
117
+ }
118
+ expect(secrets.size).toBe(100);
119
+ });
120
+ });
121
+
122
+ describe('Encryption Key Generation', () => {
123
+ it('should generate 32-byte (256-bit) key as hex', () => {
124
+ const key = generator.generateEncryptionKey();
125
+ // 32 bytes = 64 hex characters
126
+ expect(key.length).toBe(64);
127
+ expect(key).toMatch(/^[0-9a-f]+$/);
128
+ });
129
+
130
+ it('should generate unique keys', () => {
131
+ const keys = new Set<string>();
132
+ for (let i = 0; i < 100; i++) {
133
+ keys.add(generator.generateEncryptionKey());
134
+ }
135
+ expect(keys.size).toBe(100);
136
+ });
137
+ });
138
+
139
+ describe('Installation Credentials', () => {
140
+ it('should generate complete credential set', () => {
141
+ const credentials = generator.generateInstallationCredentials();
142
+
143
+ expect(credentials.adminPassword).toBeDefined();
144
+ expect(credentials.servicePassword).toBeDefined();
145
+ expect(credentials.jwtSecret).toBeDefined();
146
+ expect(credentials.sessionSecret).toBeDefined();
147
+ expect(credentials.encryptionKey).toBeDefined();
148
+ expect(credentials.generatedAt).toBeInstanceOf(Date);
149
+ });
150
+
151
+ it('should set expiration when specified', () => {
152
+ const credentials = generator.generateInstallationCredentials(30);
153
+
154
+ expect(credentials.expiresAt).toBeInstanceOf(Date);
155
+
156
+ // Should be approximately 30 days in the future
157
+ const expectedExpiration = Date.now() + 30 * 24 * 60 * 60 * 1000;
158
+ const actualExpiration = credentials.expiresAt!.getTime();
159
+ expect(Math.abs(actualExpiration - expectedExpiration)).toBeLessThan(1000);
160
+ });
161
+
162
+ it('should generate unique credentials each time', () => {
163
+ const cred1 = generator.generateInstallationCredentials();
164
+ const cred2 = generator.generateInstallationCredentials();
165
+
166
+ expect(cred1.adminPassword).not.toBe(cred2.adminPassword);
167
+ expect(cred1.servicePassword).not.toBe(cred2.servicePassword);
168
+ expect(cred1.jwtSecret).not.toBe(cred2.jwtSecret);
169
+ });
170
+ });
171
+
172
+ describe('Token Generation', () => {
173
+ it('should generate session token', () => {
174
+ const token = generator.generateSessionToken();
175
+ expect(token).toBeDefined();
176
+ expect(token.length).toBeGreaterThan(0);
177
+ });
178
+
179
+ it('should generate CSRF token', () => {
180
+ const token = generator.generateCsrfToken();
181
+ expect(token).toBeDefined();
182
+ // Base64url encoded
183
+ expect(token).toMatch(/^[A-Za-z0-9_-]+$/);
184
+ });
185
+
186
+ it('should generate nonce', () => {
187
+ const nonce = generator.generateNonce();
188
+ expect(nonce).toBeDefined();
189
+ // Hex encoded, 16 bytes = 32 chars
190
+ expect(nonce.length).toBe(32);
191
+ expect(nonce).toMatch(/^[0-9a-f]+$/);
192
+ });
193
+ });
194
+
195
+ describe('Environment Script Generation', () => {
196
+ it('should generate valid shell script', () => {
197
+ const credentials = generator.generateInstallationCredentials();
198
+ const script = generator.createEnvScript(credentials);
199
+
200
+ expect(script).toContain('export CLAUDE_FLOW_ADMIN_PASSWORD=');
201
+ expect(script).toContain('export CLAUDE_FLOW_SERVICE_PASSWORD=');
202
+ expect(script).toContain('export CLAUDE_FLOW_JWT_SECRET=');
203
+ expect(script).toContain('export CLAUDE_FLOW_SESSION_SECRET=');
204
+ expect(script).toContain('export CLAUDE_FLOW_ENCRYPTION_KEY=');
205
+ });
206
+
207
+ it('should include warning comment', () => {
208
+ const credentials = generator.generateInstallationCredentials();
209
+ const script = generator.createEnvScript(credentials);
210
+
211
+ expect(script).toContain('Store these securely');
212
+ });
213
+ });
214
+
215
+ describe('JSON Config Generation', () => {
216
+ it('should generate valid JSON', () => {
217
+ const credentials = generator.generateInstallationCredentials();
218
+ const json = generator.createJsonConfig(credentials);
219
+
220
+ expect(() => JSON.parse(json)).not.toThrow();
221
+ });
222
+
223
+ it('should include all credentials', () => {
224
+ const credentials = generator.generateInstallationCredentials();
225
+ const json = generator.createJsonConfig(credentials);
226
+ const parsed = JSON.parse(json);
227
+
228
+ expect(parsed['claude-flow/admin-password']).toBe(credentials.adminPassword);
229
+ expect(parsed['claude-flow/service-password']).toBe(credentials.servicePassword);
230
+ expect(parsed['claude-flow/jwt-secret']).toBe(credentials.jwtSecret);
231
+ expect(parsed['claude-flow/session-secret']).toBe(credentials.sessionSecret);
232
+ expect(parsed['claude-flow/encryption-key']).toBe(credentials.encryptionKey);
233
+ });
234
+ });
235
+
236
+ describe('Factory Functions', () => {
237
+ it('should create generator with factory function', () => {
238
+ const gen = createCredentialGenerator();
239
+ expect(gen).toBeInstanceOf(CredentialGenerator);
240
+ });
241
+
242
+ it('should generate credentials with quick function', () => {
243
+ const credentials = generateCredentials();
244
+ expect(credentials.adminPassword).toBeDefined();
245
+ expect(credentials.jwtSecret).toBeDefined();
246
+ });
247
+ });
248
+
249
+ describe('CVE-3 Security Verification', () => {
250
+ it('should NOT produce hardcoded admin123 password', () => {
251
+ for (let i = 0; i < 100; i++) {
252
+ const credentials = generator.generateInstallationCredentials();
253
+ expect(credentials.adminPassword).not.toBe('admin123');
254
+ expect(credentials.servicePassword).not.toBe('service123');
255
+ }
256
+ });
257
+
258
+ it('should NOT produce predictable patterns', () => {
259
+ const passwords = new Set<string>();
260
+ for (let i = 0; i < 1000; i++) {
261
+ passwords.add(generator.generatePassword());
262
+ }
263
+
264
+ // All should be unique
265
+ expect(passwords.size).toBe(1000);
266
+
267
+ // None should match common patterns
268
+ const commonPatterns = ['password', 'admin', 'service', '123456', 'qwerty'];
269
+ for (const password of passwords) {
270
+ for (const pattern of commonPatterns) {
271
+ expect(password.toLowerCase()).not.toContain(pattern);
272
+ }
273
+ }
274
+ });
275
+
276
+ it('should use cryptographically secure random', () => {
277
+ // Generate many passwords and verify entropy
278
+ const passwords: string[] = [];
279
+ for (let i = 0; i < 100; i++) {
280
+ passwords.push(generator.generatePassword());
281
+ }
282
+
283
+ // Calculate average character distribution
284
+ const charCounts = new Map<string, number>();
285
+ for (const password of passwords) {
286
+ for (const char of password) {
287
+ charCounts.set(char, (charCounts.get(char) || 0) + 1);
288
+ }
289
+ }
290
+
291
+ // Should have good distribution (many different characters)
292
+ expect(charCounts.size).toBeGreaterThan(30);
293
+ });
294
+
295
+ it('should generate installation credentials with sufficient entropy', () => {
296
+ const credentials = generator.generateInstallationCredentials();
297
+
298
+ // Password should be at least 256 bits of entropy at minimum
299
+ expect(credentials.adminPassword.length).toBeGreaterThanOrEqual(32);
300
+ expect(credentials.servicePassword.length).toBeGreaterThanOrEqual(32);
301
+
302
+ // Secrets should be 512 bits
303
+ expect(credentials.jwtSecret.length).toBeGreaterThanOrEqual(64);
304
+ expect(credentials.sessionSecret.length).toBeGreaterThanOrEqual(64);
305
+
306
+ // Encryption key should be exactly 256 bits (64 hex chars)
307
+ expect(credentials.encryptionKey.length).toBe(64);
308
+ });
309
+ });
310
+ });