@sparkleideas/security 3.0.0-alpha.10

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 (34) hide show
  1. package/README.md +234 -0
  2. package/__tests__/acceptance/security-compliance.test.ts +674 -0
  3. package/__tests__/credential-generator.test.ts +310 -0
  4. package/__tests__/fixtures/configurations.ts +419 -0
  5. package/__tests__/fixtures/index.ts +21 -0
  6. package/__tests__/helpers/create-mock.ts +469 -0
  7. package/__tests__/helpers/index.ts +32 -0
  8. package/__tests__/input-validator.test.ts +381 -0
  9. package/__tests__/integration/security-flow.test.ts +606 -0
  10. package/__tests__/password-hasher.test.ts +239 -0
  11. package/__tests__/path-validator.test.ts +302 -0
  12. package/__tests__/safe-executor.test.ts +292 -0
  13. package/__tests__/token-generator.test.ts +371 -0
  14. package/__tests__/unit/credential-generator.test.ts +182 -0
  15. package/__tests__/unit/password-hasher.test.ts +359 -0
  16. package/__tests__/unit/path-validator.test.ts +509 -0
  17. package/__tests__/unit/safe-executor.test.ts +667 -0
  18. package/__tests__/unit/token-generator.test.ts +310 -0
  19. package/package.json +28 -0
  20. package/src/CVE-REMEDIATION.ts +251 -0
  21. package/src/application/index.ts +10 -0
  22. package/src/application/services/security-application-service.ts +193 -0
  23. package/src/credential-generator.ts +368 -0
  24. package/src/domain/entities/security-context.ts +173 -0
  25. package/src/domain/index.ts +17 -0
  26. package/src/domain/services/security-domain-service.ts +296 -0
  27. package/src/index.ts +271 -0
  28. package/src/input-validator.ts +466 -0
  29. package/src/password-hasher.ts +270 -0
  30. package/src/path-validator.ts +525 -0
  31. package/src/safe-executor.ts +525 -0
  32. package/src/token-generator.ts +463 -0
  33. package/tmp.json +0 -0
  34. package/tsconfig.json +9 -0
@@ -0,0 +1,674 @@
1
+ /**
2
+ * V3 Claude-Flow Security Compliance Acceptance Tests
3
+ *
4
+ * Acceptance tests for security requirements
5
+ * Tests CVE prevention and security compliance
6
+ */
7
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
8
+ import { createMock, type MockedInterface } from '../helpers/create-mock';
9
+ import { securityConfigs } from '../fixtures/configurations';
10
+
11
+ /**
12
+ * Security compliance checker interface
13
+ */
14
+ interface ISecurityComplianceChecker {
15
+ checkPathTraversal(path: string): ComplianceResult;
16
+ checkCommandInjection(command: string, args: string[]): ComplianceResult;
17
+ checkNullByteInjection(input: string): ComplianceResult;
18
+ checkPasswordPolicy(password: string): ComplianceResult;
19
+ runFullAudit(): Promise<AuditResult>;
20
+ }
21
+
22
+ /**
23
+ * CVE scanner interface
24
+ */
25
+ interface ICVEScanner {
26
+ scan(code: string): Promise<CVEScanResult>;
27
+ getKnownCVEs(): CVEInfo[];
28
+ validateFix(cveId: string): Promise<boolean>;
29
+ }
30
+
31
+ /**
32
+ * Security policy enforcer interface
33
+ */
34
+ interface ISecurityPolicyEnforcer {
35
+ enforcePathPolicy(path: string): EnforcementResult;
36
+ enforceCommandPolicy(command: string): EnforcementResult;
37
+ enforceInputPolicy(input: string): EnforcementResult;
38
+ getViolations(): PolicyViolation[];
39
+ }
40
+
41
+ interface ComplianceResult {
42
+ compliant: boolean;
43
+ violations: string[];
44
+ severity: 'critical' | 'high' | 'medium' | 'low' | 'none';
45
+ recommendations: string[];
46
+ }
47
+
48
+ interface AuditResult {
49
+ passed: boolean;
50
+ checks: AuditCheck[];
51
+ overallScore: number;
52
+ timestamp: Date;
53
+ }
54
+
55
+ interface AuditCheck {
56
+ name: string;
57
+ passed: boolean;
58
+ details: string;
59
+ }
60
+
61
+ interface CVEScanResult {
62
+ vulnerabilities: CVEInfo[];
63
+ riskScore: number;
64
+ remediation: string[];
65
+ }
66
+
67
+ interface CVEInfo {
68
+ id: string;
69
+ severity: 'critical' | 'high' | 'medium' | 'low';
70
+ description: string;
71
+ affectedVersions: string[];
72
+ fixedIn?: string;
73
+ }
74
+
75
+ interface EnforcementResult {
76
+ allowed: boolean;
77
+ reason?: string;
78
+ sanitized?: string;
79
+ }
80
+
81
+ interface PolicyViolation {
82
+ type: string;
83
+ input: string;
84
+ timestamp: Date;
85
+ severity: string;
86
+ }
87
+
88
+ /**
89
+ * Security compliance checker implementation
90
+ */
91
+ class SecurityComplianceChecker implements ISecurityComplianceChecker {
92
+ constructor(private readonly config: typeof securityConfigs.strict) {}
93
+
94
+ checkPathTraversal(path: string): ComplianceResult {
95
+ const violations: string[] = [];
96
+ const recommendations: string[] = [];
97
+
98
+ // Check for directory traversal patterns
99
+ const traversalPatterns = ['../', '..\\', '%2e%2e%2f', '%2e%2e/'];
100
+ for (const pattern of traversalPatterns) {
101
+ if (path.toLowerCase().includes(pattern.toLowerCase())) {
102
+ violations.push(`Path contains traversal pattern: ${pattern}`);
103
+ }
104
+ }
105
+
106
+ // Check for blocked patterns from config
107
+ for (const pattern of this.config.paths.blockedPatterns) {
108
+ if (path.includes(pattern)) {
109
+ violations.push(`Path contains blocked pattern: ${pattern}`);
110
+ }
111
+ }
112
+
113
+ // Check for null bytes
114
+ if (path.includes('\0')) {
115
+ violations.push('Path contains null byte');
116
+ }
117
+
118
+ if (violations.length > 0) {
119
+ recommendations.push('Sanitize path input');
120
+ recommendations.push('Use allowlist for valid paths');
121
+ recommendations.push('Validate against allowed directories');
122
+ }
123
+
124
+ return {
125
+ compliant: violations.length === 0,
126
+ violations,
127
+ severity: violations.length > 0 ? 'critical' : 'none',
128
+ recommendations,
129
+ };
130
+ }
131
+
132
+ checkCommandInjection(command: string, args: string[]): ComplianceResult {
133
+ const violations: string[] = [];
134
+ const recommendations: string[] = [];
135
+
136
+ // Check base command
137
+ const baseCommand = command.split(' ')[0];
138
+ if (this.config.execution.blockedCommands.includes(baseCommand)) {
139
+ violations.push(`Command "${baseCommand}" is blocked`);
140
+ }
141
+
142
+ if (!this.config.execution.allowedCommands.includes(baseCommand)) {
143
+ violations.push(`Command "${baseCommand}" is not in allowlist`);
144
+ }
145
+
146
+ // Check for injection patterns in args
147
+ const injectionPatterns = [';', '|', '&', '`', '$', '(', ')', '<', '>', '\n'];
148
+ for (const arg of args) {
149
+ for (const pattern of injectionPatterns) {
150
+ if (arg.includes(pattern)) {
151
+ violations.push(`Argument contains injection pattern: ${pattern}`);
152
+ }
153
+ }
154
+ }
155
+
156
+ if (violations.length > 0) {
157
+ recommendations.push('Sanitize command arguments');
158
+ recommendations.push('Use allowlist for commands');
159
+ recommendations.push('Disable shell execution');
160
+ }
161
+
162
+ return {
163
+ compliant: violations.length === 0,
164
+ violations,
165
+ severity: violations.length > 0 ? 'critical' : 'none',
166
+ recommendations,
167
+ };
168
+ }
169
+
170
+ checkNullByteInjection(input: string): ComplianceResult {
171
+ const violations: string[] = [];
172
+
173
+ if (input.includes('\0')) {
174
+ violations.push('Input contains null byte');
175
+ }
176
+
177
+ // Check for encoded null bytes
178
+ if (input.includes('%00')) {
179
+ violations.push('Input contains URL-encoded null byte');
180
+ }
181
+
182
+ return {
183
+ compliant: violations.length === 0,
184
+ violations,
185
+ severity: violations.length > 0 ? 'high' : 'none',
186
+ recommendations: violations.length > 0 ? ['Strip null bytes from input'] : [],
187
+ };
188
+ }
189
+
190
+ checkPasswordPolicy(password: string): ComplianceResult {
191
+ const violations: string[] = [];
192
+
193
+ if (password.length < 8) {
194
+ violations.push('Password must be at least 8 characters');
195
+ }
196
+
197
+ if (!/[A-Z]/.test(password)) {
198
+ violations.push('Password must contain uppercase letter');
199
+ }
200
+
201
+ if (!/[a-z]/.test(password)) {
202
+ violations.push('Password must contain lowercase letter');
203
+ }
204
+
205
+ if (!/[0-9]/.test(password)) {
206
+ violations.push('Password must contain number');
207
+ }
208
+
209
+ if (!/[!@#$%^&*]/.test(password)) {
210
+ violations.push('Password should contain special character');
211
+ }
212
+
213
+ return {
214
+ compliant: violations.length === 0,
215
+ violations,
216
+ severity: violations.length > 2 ? 'high' : violations.length > 0 ? 'medium' : 'none',
217
+ recommendations: ['Use a password manager', 'Enable MFA'],
218
+ };
219
+ }
220
+
221
+ async runFullAudit(): Promise<AuditResult> {
222
+ const checks: AuditCheck[] = [
223
+ {
224
+ name: 'Path Traversal Protection',
225
+ passed: this.config.paths.blockedPatterns.includes('../'),
226
+ details: 'Verified blocked patterns include directory traversal',
227
+ },
228
+ {
229
+ name: 'Command Injection Protection',
230
+ passed: this.config.execution.shell === false,
231
+ details: 'Shell execution is disabled',
232
+ },
233
+ {
234
+ name: 'Dangerous Commands Blocked',
235
+ passed: this.config.execution.blockedCommands.includes('rm'),
236
+ details: 'Verified dangerous commands are blocked',
237
+ },
238
+ {
239
+ name: 'Secure Hashing Algorithm',
240
+ passed: this.config.hashing.algorithm === 'argon2',
241
+ details: 'Using recommended hashing algorithm',
242
+ },
243
+ {
244
+ name: 'Input Size Limit',
245
+ passed: this.config.validation.maxInputSize <= 10000,
246
+ details: 'Input size is properly limited',
247
+ },
248
+ ];
249
+
250
+ const passed = checks.every((c) => c.passed);
251
+ const overallScore = (checks.filter((c) => c.passed).length / checks.length) * 100;
252
+
253
+ return {
254
+ passed,
255
+ checks,
256
+ overallScore,
257
+ timestamp: new Date(),
258
+ };
259
+ }
260
+ }
261
+
262
+ describe('Security Compliance Acceptance', () => {
263
+ let complianceChecker: SecurityComplianceChecker;
264
+ let mockCVEScanner: MockedInterface<ICVEScanner>;
265
+ let mockPolicyEnforcer: MockedInterface<ISecurityPolicyEnforcer>;
266
+
267
+ beforeEach(() => {
268
+ complianceChecker = new SecurityComplianceChecker(securityConfigs.strict);
269
+ mockCVEScanner = createMock<ICVEScanner>();
270
+ mockPolicyEnforcer = createMock<ISecurityPolicyEnforcer>();
271
+
272
+ // Configure CVE scanner mock
273
+ mockCVEScanner.getKnownCVEs.mockReturnValue([
274
+ {
275
+ id: 'CVE-1',
276
+ severity: 'critical',
277
+ description: 'Directory traversal vulnerability',
278
+ affectedVersions: ['<3.0.0'],
279
+ fixedIn: '3.0.0',
280
+ },
281
+ {
282
+ id: 'CVE-2',
283
+ severity: 'critical',
284
+ description: 'Absolute path injection vulnerability',
285
+ affectedVersions: ['<3.0.0'],
286
+ fixedIn: '3.0.0',
287
+ },
288
+ {
289
+ id: 'CVE-3',
290
+ severity: 'critical',
291
+ description: 'Command injection vulnerability',
292
+ affectedVersions: ['<3.0.0'],
293
+ fixedIn: '3.0.0',
294
+ },
295
+ ]);
296
+
297
+ mockCVEScanner.validateFix.mockResolvedValue(true);
298
+ mockCVEScanner.scan.mockResolvedValue({
299
+ vulnerabilities: [],
300
+ riskScore: 0,
301
+ remediation: [],
302
+ });
303
+
304
+ // Configure policy enforcer mock
305
+ mockPolicyEnforcer.enforcePathPolicy.mockImplementation((path) => ({
306
+ allowed: !path.includes('../'),
307
+ reason: path.includes('../') ? 'Path traversal detected' : undefined,
308
+ }));
309
+ mockPolicyEnforcer.enforceCommandPolicy.mockImplementation((cmd) => ({
310
+ allowed: securityConfigs.strict.execution.allowedCommands.includes(cmd.split(' ')[0]),
311
+ }));
312
+ mockPolicyEnforcer.getViolations.mockReturnValue([]);
313
+ });
314
+
315
+ describe('CVE-1: Directory Traversal Prevention', () => {
316
+ it('should detect basic directory traversal', () => {
317
+ // Given
318
+ const maliciousPath = '../../../etc/passwd';
319
+
320
+ // When
321
+ const result = complianceChecker.checkPathTraversal(maliciousPath);
322
+
323
+ // Then
324
+ expect(result.compliant).toBe(false);
325
+ expect(result.severity).toBe('critical');
326
+ expect(result.violations).toContainEqual(expect.stringContaining('../'));
327
+ });
328
+
329
+ it('should detect Windows-style traversal', () => {
330
+ // Given
331
+ const maliciousPath = '..\\..\\..\\Windows\\System32';
332
+
333
+ // When
334
+ const result = complianceChecker.checkPathTraversal(maliciousPath);
335
+
336
+ // Then
337
+ expect(result.compliant).toBe(false);
338
+ });
339
+
340
+ it('should detect URL-encoded traversal', () => {
341
+ // Given
342
+ const maliciousPath = '%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd';
343
+
344
+ // When
345
+ const result = complianceChecker.checkPathTraversal(maliciousPath);
346
+
347
+ // Then
348
+ expect(result.compliant).toBe(false);
349
+ });
350
+
351
+ it('should allow safe paths', () => {
352
+ // Given
353
+ const safePath = './v3/src/security/index.ts';
354
+
355
+ // When
356
+ const result = complianceChecker.checkPathTraversal(safePath);
357
+
358
+ // Then
359
+ expect(result.compliant).toBe(true);
360
+ expect(result.severity).toBe('none');
361
+ });
362
+
363
+ it('should validate CVE-1 fix', async () => {
364
+ // When
365
+ const isFixed = await mockCVEScanner.validateFix('CVE-1');
366
+
367
+ // Then
368
+ expect(isFixed).toBe(true);
369
+ });
370
+ });
371
+
372
+ describe('CVE-2: Absolute Path Injection Prevention', () => {
373
+ it('should detect /etc/ access attempts', () => {
374
+ // Given
375
+ const maliciousPath = '/etc/passwd';
376
+
377
+ // When
378
+ const result = complianceChecker.checkPathTraversal(maliciousPath);
379
+
380
+ // Then
381
+ expect(result.compliant).toBe(false);
382
+ expect(result.violations).toContainEqual(expect.stringContaining('/etc/'));
383
+ });
384
+
385
+ it('should detect /tmp/ access attempts', () => {
386
+ // Given
387
+ const maliciousPath = '/tmp/malicious.sh';
388
+
389
+ // When
390
+ const result = complianceChecker.checkPathTraversal(maliciousPath);
391
+
392
+ // Then
393
+ expect(result.compliant).toBe(false);
394
+ });
395
+
396
+ it('should detect home directory access attempts', () => {
397
+ // Given
398
+ const maliciousPath = '~/.ssh/id_rsa';
399
+
400
+ // When
401
+ const result = complianceChecker.checkPathTraversal(maliciousPath);
402
+
403
+ // Then
404
+ expect(result.compliant).toBe(false);
405
+ });
406
+
407
+ it('should validate CVE-2 fix', async () => {
408
+ // When
409
+ const isFixed = await mockCVEScanner.validateFix('CVE-2');
410
+
411
+ // Then
412
+ expect(isFixed).toBe(true);
413
+ });
414
+ });
415
+
416
+ describe('CVE-3: Command Injection Prevention', () => {
417
+ it('should detect semicolon injection', () => {
418
+ // Given
419
+ const command = 'npm';
420
+ const args = ['install; rm -rf /'];
421
+
422
+ // When
423
+ const result = complianceChecker.checkCommandInjection(command, args);
424
+
425
+ // Then
426
+ expect(result.compliant).toBe(false);
427
+ expect(result.violations).toContainEqual(expect.stringContaining(';'));
428
+ });
429
+
430
+ it('should detect pipe injection', () => {
431
+ // Given
432
+ const command = 'npm';
433
+ const args = ['install | cat /etc/passwd'];
434
+
435
+ // When
436
+ const result = complianceChecker.checkCommandInjection(command, args);
437
+
438
+ // Then
439
+ expect(result.compliant).toBe(false);
440
+ });
441
+
442
+ it('should detect command substitution', () => {
443
+ // Given
444
+ const command = 'npm';
445
+ const args = ['install $(whoami)'];
446
+
447
+ // When
448
+ const result = complianceChecker.checkCommandInjection(command, args);
449
+
450
+ // Then
451
+ expect(result.compliant).toBe(false);
452
+ });
453
+
454
+ it('should detect backtick execution', () => {
455
+ // Given
456
+ const command = 'npm';
457
+ const args = ['install `rm -rf /`'];
458
+
459
+ // When
460
+ const result = complianceChecker.checkCommandInjection(command, args);
461
+
462
+ // Then
463
+ expect(result.compliant).toBe(false);
464
+ });
465
+
466
+ it('should block dangerous commands', () => {
467
+ // Given
468
+ const command = 'rm';
469
+ const args = ['-rf', '/'];
470
+
471
+ // When
472
+ const result = complianceChecker.checkCommandInjection(command, args);
473
+
474
+ // Then
475
+ expect(result.compliant).toBe(false);
476
+ expect(result.violations).toContainEqual(expect.stringContaining('rm'));
477
+ });
478
+
479
+ it('should allow safe commands', () => {
480
+ // Given
481
+ const command = 'npm';
482
+ const args = ['install', '--save', 'lodash'];
483
+
484
+ // When
485
+ const result = complianceChecker.checkCommandInjection(command, args);
486
+
487
+ // Then
488
+ expect(result.compliant).toBe(true);
489
+ });
490
+
491
+ it('should validate CVE-3 fix', async () => {
492
+ // When
493
+ const isFixed = await mockCVEScanner.validateFix('CVE-3');
494
+
495
+ // Then
496
+ expect(isFixed).toBe(true);
497
+ });
498
+ });
499
+
500
+ describe('Null Byte Injection Prevention', () => {
501
+ it('should detect null byte in path', () => {
502
+ // Given
503
+ const input = 'file.txt\0.exe';
504
+
505
+ // When
506
+ const result = complianceChecker.checkNullByteInjection(input);
507
+
508
+ // Then
509
+ expect(result.compliant).toBe(false);
510
+ expect(result.severity).toBe('high');
511
+ });
512
+
513
+ it('should detect URL-encoded null byte', () => {
514
+ // Given
515
+ const input = 'file.txt%00.exe';
516
+
517
+ // When
518
+ const result = complianceChecker.checkNullByteInjection(input);
519
+
520
+ // Then
521
+ expect(result.compliant).toBe(false);
522
+ });
523
+
524
+ it('should allow clean input', () => {
525
+ // Given
526
+ const input = 'file.txt';
527
+
528
+ // When
529
+ const result = complianceChecker.checkNullByteInjection(input);
530
+
531
+ // Then
532
+ expect(result.compliant).toBe(true);
533
+ });
534
+ });
535
+
536
+ describe('Password Policy Compliance', () => {
537
+ it('should require minimum length', () => {
538
+ // Given
539
+ const weakPassword = 'Short1!';
540
+
541
+ // When
542
+ const result = complianceChecker.checkPasswordPolicy(weakPassword);
543
+
544
+ // Then
545
+ expect(result.compliant).toBe(false);
546
+ expect(result.violations).toContainEqual(expect.stringContaining('8 characters'));
547
+ });
548
+
549
+ it('should require uppercase letter', () => {
550
+ // Given
551
+ const noUpper = 'password123!';
552
+
553
+ // When
554
+ const result = complianceChecker.checkPasswordPolicy(noUpper);
555
+
556
+ // Then
557
+ expect(result.violations).toContainEqual(expect.stringContaining('uppercase'));
558
+ });
559
+
560
+ it('should require lowercase letter', () => {
561
+ // Given
562
+ const noLower = 'PASSWORD123!';
563
+
564
+ // When
565
+ const result = complianceChecker.checkPasswordPolicy(noLower);
566
+
567
+ // Then
568
+ expect(result.violations).toContainEqual(expect.stringContaining('lowercase'));
569
+ });
570
+
571
+ it('should require number', () => {
572
+ // Given
573
+ const noNumber = 'Password!!';
574
+
575
+ // When
576
+ const result = complianceChecker.checkPasswordPolicy(noNumber);
577
+
578
+ // Then
579
+ expect(result.violations).toContainEqual(expect.stringContaining('number'));
580
+ });
581
+
582
+ it('should accept strong password', () => {
583
+ // Given
584
+ const strongPassword = 'SecureP@ss123!';
585
+
586
+ // When
587
+ const result = complianceChecker.checkPasswordPolicy(strongPassword);
588
+
589
+ // Then
590
+ expect(result.compliant).toBe(true);
591
+ });
592
+ });
593
+
594
+ describe('Full Security Audit', () => {
595
+ it('should pass full audit with strict config', async () => {
596
+ // When
597
+ const audit = await complianceChecker.runFullAudit();
598
+
599
+ // Then
600
+ expect(audit.passed).toBe(true);
601
+ expect(audit.overallScore).toBe(100);
602
+ });
603
+
604
+ it('should verify all security checks pass', async () => {
605
+ // When
606
+ const audit = await complianceChecker.runFullAudit();
607
+
608
+ // Then
609
+ for (const check of audit.checks) {
610
+ expect(check.passed).toBe(true);
611
+ }
612
+ });
613
+
614
+ it('should verify path traversal protection is enabled', async () => {
615
+ // When
616
+ const audit = await complianceChecker.runFullAudit();
617
+
618
+ // Then
619
+ const pathCheck = audit.checks.find((c) => c.name === 'Path Traversal Protection');
620
+ expect(pathCheck?.passed).toBe(true);
621
+ });
622
+
623
+ it('should verify shell execution is disabled', async () => {
624
+ // When
625
+ const audit = await complianceChecker.runFullAudit();
626
+
627
+ // Then
628
+ const shellCheck = audit.checks.find((c) => c.name === 'Command Injection Protection');
629
+ expect(shellCheck?.passed).toBe(true);
630
+ });
631
+
632
+ it('should verify secure hashing is configured', async () => {
633
+ // When
634
+ const audit = await complianceChecker.runFullAudit();
635
+
636
+ // Then
637
+ const hashCheck = audit.checks.find((c) => c.name === 'Secure Hashing Algorithm');
638
+ expect(hashCheck?.passed).toBe(true);
639
+ });
640
+ });
641
+
642
+ describe('Security Configuration Compliance', () => {
643
+ it('should have 95% security test coverage target', () => {
644
+ // Given
645
+ const securityCoverageTarget = 0.95;
646
+
647
+ // Then
648
+ expect(securityCoverageTarget).toBe(0.95);
649
+ });
650
+
651
+ it('should use argon2 for password hashing', () => {
652
+ // Then
653
+ expect(securityConfigs.strict.hashing.algorithm).toBe('argon2');
654
+ });
655
+
656
+ it('should disable shell execution by default', () => {
657
+ // Then
658
+ expect(securityConfigs.strict.execution.shell).toBe(false);
659
+ });
660
+
661
+ it('should block all dangerous commands', () => {
662
+ // Then
663
+ expect(securityConfigs.strict.execution.blockedCommands).toContain('rm');
664
+ expect(securityConfigs.strict.execution.blockedCommands).toContain('del');
665
+ expect(securityConfigs.strict.execution.blockedCommands).toContain('format');
666
+ expect(securityConfigs.strict.execution.blockedCommands).toContain('dd');
667
+ });
668
+
669
+ it('should have limited allowed commands', () => {
670
+ // Then
671
+ expect(securityConfigs.strict.execution.allowedCommands).toEqual(['npm', 'npx', 'node', 'git']);
672
+ });
673
+ });
674
+ });