github-issue-tower-defence-management 1.148.6 → 1.148.8
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.
- package/CHANGELOG.md +14 -0
- package/bin/domain/usecases/CheckIssueReviewReadinessUseCase.js +5 -1
- package/bin/domain/usecases/CheckIssueReviewReadinessUseCase.js.map +1 -1
- package/bin/domain/usecases/DailySecurityScanUseCase.js +65 -41
- package/bin/domain/usecases/DailySecurityScanUseCase.js.map +1 -1
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js +8 -1
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js +6 -0
- package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js.map +1 -1
- package/bin/domain/usecases/isPullRequestDeclaredUnnecessary.js +31 -0
- package/bin/domain/usecases/isPullRequestDeclaredUnnecessary.js.map +1 -0
- package/package.json +1 -1
- package/src/domain/usecases/CheckIssueReviewReadinessUseCase.test.ts +43 -0
- package/src/domain/usecases/CheckIssueReviewReadinessUseCase.ts +11 -1
- package/src/domain/usecases/DailySecurityScanUseCase.test.ts +299 -237
- package/src/domain/usecases/DailySecurityScanUseCase.ts +106 -60
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.test.ts +79 -0
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts +13 -1
- package/src/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.test.ts +81 -0
- package/src/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.ts +13 -1
- package/src/domain/usecases/isPullRequestDeclaredUnnecessary.test.ts +114 -0
- package/src/domain/usecases/isPullRequestDeclaredUnnecessary.ts +34 -0
- package/types/domain/usecases/CheckIssueReviewReadinessUseCase.d.ts.map +1 -1
- package/types/domain/usecases/DailySecurityScanUseCase.d.ts +0 -1
- package/types/domain/usecases/DailySecurityScanUseCase.d.ts.map +1 -1
- package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts.map +1 -1
- package/types/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.d.ts +1 -1
- package/types/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.d.ts.map +1 -1
- package/types/domain/usecases/isPullRequestDeclaredUnnecessary.d.ts +5 -0
- package/types/domain/usecases/isPullRequestDeclaredUnnecessary.d.ts.map +1 -0
|
@@ -311,14 +311,53 @@ describe('DailySecurityScanUseCase', () => {
|
|
|
311
311
|
mockHttpRepository,
|
|
312
312
|
} = buildUseCase();
|
|
313
313
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
314
|
+
mockIssueRepository.searchIssue.mockResolvedValue([]);
|
|
315
|
+
mockLocalCommandRunner.runCommand.mockImplementation(async (program) => {
|
|
316
|
+
if (program === 'find') {
|
|
317
|
+
return {
|
|
318
|
+
stdout: '/repos/example-org/app/.git\n',
|
|
319
|
+
stderr: '',
|
|
320
|
+
exitCode: 0,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
if (program === 'git') {
|
|
324
|
+
return {
|
|
325
|
+
stdout: 'git@github.com:example-org/app.git\n',
|
|
326
|
+
stderr: '',
|
|
327
|
+
exitCode: 0,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
if (program === 'osv-scanner') {
|
|
331
|
+
return {
|
|
332
|
+
stdout: JSON.stringify({
|
|
333
|
+
results: [
|
|
334
|
+
{
|
|
335
|
+
source: { path: '/repos/example-org/app', type: 'lockfile' },
|
|
336
|
+
packages: [
|
|
337
|
+
{
|
|
338
|
+
package: {
|
|
339
|
+
name: 'example-library',
|
|
340
|
+
version: '1.2.3',
|
|
341
|
+
ecosystem: 'npm',
|
|
342
|
+
},
|
|
343
|
+
vulnerabilities: [
|
|
344
|
+
{
|
|
345
|
+
id: 'GHSA-1111-2222-3333',
|
|
346
|
+
aliases: ['CVE-2024-0001', 'CVE-2023-9999'],
|
|
347
|
+
summary: 'New Vulnerability',
|
|
348
|
+
},
|
|
349
|
+
],
|
|
350
|
+
},
|
|
351
|
+
],
|
|
352
|
+
},
|
|
353
|
+
],
|
|
354
|
+
}),
|
|
355
|
+
stderr: '',
|
|
356
|
+
exitCode: 1,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
360
|
+
});
|
|
322
361
|
mockHttpRepository.get.mockResolvedValue(
|
|
323
362
|
JSON.stringify({
|
|
324
363
|
vulnerabilities: [
|
|
@@ -354,22 +393,17 @@ describe('DailySecurityScanUseCase', () => {
|
|
|
354
393
|
|
|
355
394
|
expect(mockHttpRepository.get.mock.calls).toHaveLength(1);
|
|
356
395
|
expect(mockHttpRepository.get.mock.calls[0][0]).toBe(KEV_CATALOG_URL);
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
expect(
|
|
362
|
-
|
|
363
|
-
)
|
|
364
|
-
expect(mockIssueRepository.createNewIssue.mock.calls[0][2]).toBe(
|
|
396
|
+
const kevIssueCalls =
|
|
397
|
+
mockIssueRepository.createNewIssue.mock.calls.filter(
|
|
398
|
+
(call) => call[1] === 'security-reports',
|
|
399
|
+
);
|
|
400
|
+
expect(kevIssueCalls).toHaveLength(1);
|
|
401
|
+
expect(kevIssueCalls[0][0]).toBe('example-org');
|
|
402
|
+
expect(kevIssueCalls[0][2]).toBe(
|
|
365
403
|
'CISA KEV new additions since 2024-01-01',
|
|
366
404
|
);
|
|
367
|
-
expect(
|
|
368
|
-
|
|
369
|
-
);
|
|
370
|
-
expect(mockIssueRepository.createNewIssue.mock.calls[0][3]).not.toContain(
|
|
371
|
-
'CVE-2023-9999',
|
|
372
|
-
);
|
|
405
|
+
expect(kevIssueCalls[0][3]).toContain('CVE-2024-0001');
|
|
406
|
+
expect(kevIssueCalls[0][3]).not.toContain('CVE-2023-9999');
|
|
373
407
|
});
|
|
374
408
|
|
|
375
409
|
it('does not create a KEV report issue when there are no new additions', async () => {
|
|
@@ -428,218 +462,6 @@ describe('DailySecurityScanUseCase', () => {
|
|
|
428
462
|
expect(mockIssueRepository.createNewIssue.mock.calls).toHaveLength(0);
|
|
429
463
|
});
|
|
430
464
|
|
|
431
|
-
it('does not create a KEV report issue when the product is absent from the scanned workspace', async () => {
|
|
432
|
-
const {
|
|
433
|
-
useCase,
|
|
434
|
-
mockLocalCommandRunner,
|
|
435
|
-
mockIssueRepository,
|
|
436
|
-
mockHttpRepository,
|
|
437
|
-
} = buildUseCase();
|
|
438
|
-
|
|
439
|
-
mockLocalCommandRunner.runCommand.mockImplementation(
|
|
440
|
-
async (program, args) => {
|
|
441
|
-
if (program === 'find' && args.includes('-maxdepth')) {
|
|
442
|
-
return {
|
|
443
|
-
stdout: '/repos/app/.git\n/repos/site/.git\n',
|
|
444
|
-
stderr: '',
|
|
445
|
-
exitCode: 0,
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
if (program === 'git' && args.includes('grep')) {
|
|
449
|
-
return { stdout: '', stderr: '', exitCode: 1 };
|
|
450
|
-
}
|
|
451
|
-
return { stdout: '', stderr: '', exitCode: 0 };
|
|
452
|
-
},
|
|
453
|
-
);
|
|
454
|
-
mockHttpRepository.get.mockResolvedValue(
|
|
455
|
-
JSON.stringify({
|
|
456
|
-
vulnerabilities: [
|
|
457
|
-
{
|
|
458
|
-
cveID: 'CVE-2024-0001',
|
|
459
|
-
vendorProject: 'Progress',
|
|
460
|
-
product: 'LoadMaster',
|
|
461
|
-
vulnerabilityName: 'Progress LoadMaster Command Injection',
|
|
462
|
-
dateAdded: '2024-01-02',
|
|
463
|
-
},
|
|
464
|
-
],
|
|
465
|
-
}),
|
|
466
|
-
);
|
|
467
|
-
|
|
468
|
-
await useCase.run({
|
|
469
|
-
targetDates: [new Date('2024-01-02T05:00:00Z')],
|
|
470
|
-
org: 'example-org',
|
|
471
|
-
manager: 'manager-name',
|
|
472
|
-
dailySecurityScan: {
|
|
473
|
-
scanBaseDirectory: '/repos',
|
|
474
|
-
targetHourUtc: 5,
|
|
475
|
-
enableKevNvdReport: true,
|
|
476
|
-
kevReportRepo: 'security-reports',
|
|
477
|
-
},
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
const gitGrepCalls = mockLocalCommandRunner.runCommand.mock.calls.filter(
|
|
481
|
-
(call) => call[0] === 'git' && call[1].includes('grep'),
|
|
482
|
-
);
|
|
483
|
-
expect(gitGrepCalls.map((call) => call[1])).toEqual([
|
|
484
|
-
[
|
|
485
|
-
'-C',
|
|
486
|
-
'/repos/app',
|
|
487
|
-
'grep',
|
|
488
|
-
'-I',
|
|
489
|
-
'-i',
|
|
490
|
-
'-q',
|
|
491
|
-
'-F',
|
|
492
|
-
'-e',
|
|
493
|
-
'LoadMaster',
|
|
494
|
-
],
|
|
495
|
-
[
|
|
496
|
-
'-C',
|
|
497
|
-
'/repos/site',
|
|
498
|
-
'grep',
|
|
499
|
-
'-I',
|
|
500
|
-
'-i',
|
|
501
|
-
'-q',
|
|
502
|
-
'-F',
|
|
503
|
-
'-e',
|
|
504
|
-
'LoadMaster',
|
|
505
|
-
],
|
|
506
|
-
]);
|
|
507
|
-
expect(mockIssueRepository.createNewIssue.mock.calls).toHaveLength(0);
|
|
508
|
-
});
|
|
509
|
-
|
|
510
|
-
it('reports only the new KEV entries whose product is present in the scanned workspace', async () => {
|
|
511
|
-
const {
|
|
512
|
-
useCase,
|
|
513
|
-
mockLocalCommandRunner,
|
|
514
|
-
mockIssueRepository,
|
|
515
|
-
mockHttpRepository,
|
|
516
|
-
} = buildUseCase();
|
|
517
|
-
|
|
518
|
-
mockLocalCommandRunner.runCommand.mockImplementation(
|
|
519
|
-
async (program, args) => {
|
|
520
|
-
if (program === 'find' && args.includes('-maxdepth')) {
|
|
521
|
-
return { stdout: '/repos/app/.git\n', stderr: '', exitCode: 0 };
|
|
522
|
-
}
|
|
523
|
-
if (program === 'git' && args.includes('grep')) {
|
|
524
|
-
return {
|
|
525
|
-
stdout: '',
|
|
526
|
-
stderr: '',
|
|
527
|
-
exitCode: args.includes('LoadMaster') ? 1 : 0,
|
|
528
|
-
};
|
|
529
|
-
}
|
|
530
|
-
return { stdout: '', stderr: '', exitCode: 0 };
|
|
531
|
-
},
|
|
532
|
-
);
|
|
533
|
-
mockHttpRepository.get.mockResolvedValue(
|
|
534
|
-
JSON.stringify({
|
|
535
|
-
vulnerabilities: [
|
|
536
|
-
{
|
|
537
|
-
cveID: 'CVE-2024-0001',
|
|
538
|
-
vendorProject: 'Progress',
|
|
539
|
-
product: 'LoadMaster',
|
|
540
|
-
vulnerabilityName: 'Progress LoadMaster Command Injection',
|
|
541
|
-
dateAdded: '2024-01-02',
|
|
542
|
-
},
|
|
543
|
-
{
|
|
544
|
-
cveID: 'CVE-2024-0002',
|
|
545
|
-
vendorProject: 'Example',
|
|
546
|
-
product: 'ExampleLibrary',
|
|
547
|
-
vulnerabilityName: 'Example Library Deserialization',
|
|
548
|
-
dateAdded: '2024-01-02',
|
|
549
|
-
},
|
|
550
|
-
],
|
|
551
|
-
}),
|
|
552
|
-
);
|
|
553
|
-
|
|
554
|
-
await useCase.run({
|
|
555
|
-
targetDates: [new Date('2024-01-02T05:00:00Z')],
|
|
556
|
-
org: 'example-org',
|
|
557
|
-
manager: 'manager-name',
|
|
558
|
-
dailySecurityScan: {
|
|
559
|
-
scanBaseDirectory: '/repos',
|
|
560
|
-
targetHourUtc: 5,
|
|
561
|
-
enableKevNvdReport: true,
|
|
562
|
-
kevReportRepo: 'security-reports',
|
|
563
|
-
},
|
|
564
|
-
});
|
|
565
|
-
|
|
566
|
-
expect(mockIssueRepository.createNewIssue.mock.calls).toHaveLength(1);
|
|
567
|
-
expect(mockIssueRepository.createNewIssue.mock.calls[0][3]).toContain(
|
|
568
|
-
'CVE-2024-0002',
|
|
569
|
-
);
|
|
570
|
-
expect(mockIssueRepository.createNewIssue.mock.calls[0][3]).not.toContain(
|
|
571
|
-
'CVE-2024-0001',
|
|
572
|
-
);
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
it('logs a failed repository search and keeps searching the remaining repositories', async () => {
|
|
576
|
-
const {
|
|
577
|
-
useCase,
|
|
578
|
-
mockLocalCommandRunner,
|
|
579
|
-
mockIssueRepository,
|
|
580
|
-
mockHttpRepository,
|
|
581
|
-
} = buildUseCase();
|
|
582
|
-
const errorSpy = jest
|
|
583
|
-
.spyOn(console, 'error')
|
|
584
|
-
.mockImplementation(() => undefined);
|
|
585
|
-
|
|
586
|
-
mockLocalCommandRunner.runCommand.mockImplementation(
|
|
587
|
-
async (program, args) => {
|
|
588
|
-
if (program === 'find' && args.includes('-maxdepth')) {
|
|
589
|
-
return {
|
|
590
|
-
stdout: '/repos/broken/.git\n/repos/app/.git\n',
|
|
591
|
-
stderr: '',
|
|
592
|
-
exitCode: 0,
|
|
593
|
-
};
|
|
594
|
-
}
|
|
595
|
-
if (program === 'git' && args.includes('grep')) {
|
|
596
|
-
return args.includes('/repos/broken')
|
|
597
|
-
? {
|
|
598
|
-
stdout: '',
|
|
599
|
-
stderr: 'fatal: not a git repository',
|
|
600
|
-
exitCode: 128,
|
|
601
|
-
}
|
|
602
|
-
: { stdout: '', stderr: '', exitCode: 0 };
|
|
603
|
-
}
|
|
604
|
-
return { stdout: '', stderr: '', exitCode: 0 };
|
|
605
|
-
},
|
|
606
|
-
);
|
|
607
|
-
mockHttpRepository.get.mockResolvedValue(
|
|
608
|
-
JSON.stringify({
|
|
609
|
-
vulnerabilities: [
|
|
610
|
-
{
|
|
611
|
-
cveID: 'CVE-2024-0001',
|
|
612
|
-
vendorProject: 'Progress',
|
|
613
|
-
product: 'LoadMaster',
|
|
614
|
-
vulnerabilityName: 'Progress LoadMaster Command Injection',
|
|
615
|
-
dateAdded: '2024-01-02',
|
|
616
|
-
},
|
|
617
|
-
],
|
|
618
|
-
}),
|
|
619
|
-
);
|
|
620
|
-
|
|
621
|
-
await useCase.run({
|
|
622
|
-
targetDates: [new Date('2024-01-02T05:00:00Z')],
|
|
623
|
-
org: 'example-org',
|
|
624
|
-
manager: 'manager-name',
|
|
625
|
-
dailySecurityScan: {
|
|
626
|
-
scanBaseDirectory: '/repos',
|
|
627
|
-
targetHourUtc: 5,
|
|
628
|
-
enableKevNvdReport: true,
|
|
629
|
-
kevReportRepo: 'security-reports',
|
|
630
|
-
},
|
|
631
|
-
});
|
|
632
|
-
|
|
633
|
-
expect(errorSpy).toHaveBeenCalledWith(
|
|
634
|
-
'Failed to search /repos/broken for LoadMaster: fatal: not a git repository',
|
|
635
|
-
);
|
|
636
|
-
expect(mockIssueRepository.createNewIssue.mock.calls).toHaveLength(1);
|
|
637
|
-
expect(mockIssueRepository.createNewIssue.mock.calls[0][3]).toContain(
|
|
638
|
-
'CVE-2024-0001',
|
|
639
|
-
);
|
|
640
|
-
errorSpy.mockRestore();
|
|
641
|
-
});
|
|
642
|
-
|
|
643
465
|
it('throws when the KEV catalog format is unexpected', async () => {
|
|
644
466
|
const { useCase, mockLocalCommandRunner, mockHttpRepository } =
|
|
645
467
|
buildUseCase();
|
|
@@ -741,15 +563,41 @@ describe('DailySecurityScanUseCase', () => {
|
|
|
741
563
|
};
|
|
742
564
|
}
|
|
743
565
|
if (program === 'osv-scanner') {
|
|
744
|
-
const
|
|
745
|
-
if (
|
|
566
|
+
const scannedDirectory = args[args.indexOf('-r') + 1];
|
|
567
|
+
if (scannedDirectory.includes('broken')) {
|
|
746
568
|
return {
|
|
747
569
|
stdout: '',
|
|
748
570
|
stderr: 'osv-scanner: command not found',
|
|
749
571
|
exitCode: 127,
|
|
750
572
|
};
|
|
751
573
|
}
|
|
752
|
-
return {
|
|
574
|
+
return {
|
|
575
|
+
stdout: JSON.stringify({
|
|
576
|
+
results: [
|
|
577
|
+
{
|
|
578
|
+
source: { path: scannedDirectory, type: 'lockfile' },
|
|
579
|
+
packages: [
|
|
580
|
+
{
|
|
581
|
+
package: {
|
|
582
|
+
name: 'example-library',
|
|
583
|
+
version: '1.2.3',
|
|
584
|
+
ecosystem: 'npm',
|
|
585
|
+
},
|
|
586
|
+
vulnerabilities: [
|
|
587
|
+
{
|
|
588
|
+
id: 'GHSA-1111-2222-3333',
|
|
589
|
+
aliases: [],
|
|
590
|
+
summary: 'Example Library Deserialization',
|
|
591
|
+
},
|
|
592
|
+
],
|
|
593
|
+
},
|
|
594
|
+
],
|
|
595
|
+
},
|
|
596
|
+
],
|
|
597
|
+
}),
|
|
598
|
+
stderr: '',
|
|
599
|
+
exitCode: 1,
|
|
600
|
+
};
|
|
753
601
|
}
|
|
754
602
|
return { stdout: '', stderr: '', exitCode: 0 };
|
|
755
603
|
},
|
|
@@ -869,5 +717,219 @@ describe('DailySecurityScanUseCase', () => {
|
|
|
869
717
|
);
|
|
870
718
|
expect(mockIssueRepository.createCommentByUrl.mock.calls).toHaveLength(0);
|
|
871
719
|
});
|
|
720
|
+
|
|
721
|
+
const osvScanOutput = (
|
|
722
|
+
vulnerablePackages: {
|
|
723
|
+
name: string;
|
|
724
|
+
version: string;
|
|
725
|
+
ecosystem: string;
|
|
726
|
+
id: string;
|
|
727
|
+
aliases: string[];
|
|
728
|
+
summary: string;
|
|
729
|
+
}[],
|
|
730
|
+
): string =>
|
|
731
|
+
JSON.stringify({
|
|
732
|
+
results: [
|
|
733
|
+
{
|
|
734
|
+
source: { path: '/repos/example-org/app', type: 'lockfile' },
|
|
735
|
+
packages: vulnerablePackages.map((vulnerablePackage) => ({
|
|
736
|
+
package: {
|
|
737
|
+
name: vulnerablePackage.name,
|
|
738
|
+
version: vulnerablePackage.version,
|
|
739
|
+
ecosystem: vulnerablePackage.ecosystem,
|
|
740
|
+
},
|
|
741
|
+
vulnerabilities: [
|
|
742
|
+
{
|
|
743
|
+
id: vulnerablePackage.id,
|
|
744
|
+
aliases: vulnerablePackage.aliases,
|
|
745
|
+
summary: vulnerablePackage.summary,
|
|
746
|
+
},
|
|
747
|
+
],
|
|
748
|
+
})),
|
|
749
|
+
},
|
|
750
|
+
],
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
const buildScanEnvironment = (scanOutput: string, kevCatalog: unknown) => {
|
|
754
|
+
const built = buildUseCase();
|
|
755
|
+
built.mockIssueRepository.searchIssue.mockResolvedValue([]);
|
|
756
|
+
built.mockLocalCommandRunner.runCommand.mockImplementation(
|
|
757
|
+
async (program) => {
|
|
758
|
+
if (program === 'find') {
|
|
759
|
+
return {
|
|
760
|
+
stdout: '/repos/example-org/app/.git\n',
|
|
761
|
+
stderr: '',
|
|
762
|
+
exitCode: 0,
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
if (program === 'git') {
|
|
766
|
+
return {
|
|
767
|
+
stdout: 'git@github.com:example-org/app.git\n',
|
|
768
|
+
stderr: '',
|
|
769
|
+
exitCode: 0,
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
if (program === 'osv-scanner') {
|
|
773
|
+
return { stdout: scanOutput, stderr: '', exitCode: 1 };
|
|
774
|
+
}
|
|
775
|
+
return { stdout: '', stderr: '', exitCode: 0 };
|
|
776
|
+
},
|
|
777
|
+
);
|
|
778
|
+
built.mockHttpRepository.get.mockResolvedValue(
|
|
779
|
+
JSON.stringify(kevCatalog),
|
|
780
|
+
);
|
|
781
|
+
return built;
|
|
782
|
+
};
|
|
783
|
+
|
|
784
|
+
const kevReportCalls = (
|
|
785
|
+
calls: [string, string, string, string, string[], string[]][],
|
|
786
|
+
) => calls.filter((call) => call[1] === 'security-reports');
|
|
787
|
+
|
|
788
|
+
const runWithKevReporting = async (useCase: DailySecurityScanUseCase) =>
|
|
789
|
+
useCase.run({
|
|
790
|
+
targetDates: [new Date('2024-01-02T05:00:00Z')],
|
|
791
|
+
org: 'example-org',
|
|
792
|
+
manager: 'manager-name',
|
|
793
|
+
dailySecurityScan: {
|
|
794
|
+
scanBaseDirectory: '/repos',
|
|
795
|
+
targetHourUtc: 5,
|
|
796
|
+
enableKevNvdReport: true,
|
|
797
|
+
kevReportRepo: 'security-reports',
|
|
798
|
+
},
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
it('reports a KEV addition whose CVE the scanner found at an installed version', async () => {
|
|
802
|
+
const { useCase, mockIssueRepository } = buildScanEnvironment(
|
|
803
|
+
osvScanOutput([
|
|
804
|
+
{
|
|
805
|
+
name: 'example-library',
|
|
806
|
+
version: '1.2.3',
|
|
807
|
+
ecosystem: 'npm',
|
|
808
|
+
id: 'GHSA-1111-2222-3333',
|
|
809
|
+
aliases: ['CVE-2024-0001'],
|
|
810
|
+
summary: 'Example Library Deserialization',
|
|
811
|
+
},
|
|
812
|
+
]),
|
|
813
|
+
{
|
|
814
|
+
vulnerabilities: [
|
|
815
|
+
{
|
|
816
|
+
cveID: 'CVE-2024-0001',
|
|
817
|
+
vendorProject: 'Example',
|
|
818
|
+
product: 'ExampleLibrary',
|
|
819
|
+
vulnerabilityName: 'Example Library Deserialization',
|
|
820
|
+
dateAdded: '2024-01-02',
|
|
821
|
+
},
|
|
822
|
+
],
|
|
823
|
+
},
|
|
824
|
+
);
|
|
825
|
+
|
|
826
|
+
await runWithKevReporting(useCase);
|
|
827
|
+
|
|
828
|
+
const kevCalls = kevReportCalls(
|
|
829
|
+
mockIssueRepository.createNewIssue.mock.calls,
|
|
830
|
+
);
|
|
831
|
+
expect(kevCalls).toHaveLength(1);
|
|
832
|
+
expect(kevCalls[0][3]).toContain('CVE-2024-0001');
|
|
833
|
+
expect(kevCalls[0][3]).toContain('app');
|
|
834
|
+
expect(kevCalls[0][3]).toContain('example-library');
|
|
835
|
+
expect(kevCalls[0][3]).toContain('1.2.3');
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
it('does not report a KEV addition that the scanner did not find in any repository', async () => {
|
|
839
|
+
const { useCase, mockIssueRepository } = buildScanEnvironment(
|
|
840
|
+
osvScanOutput([
|
|
841
|
+
{
|
|
842
|
+
name: 'example-library',
|
|
843
|
+
version: '1.2.3',
|
|
844
|
+
ecosystem: 'npm',
|
|
845
|
+
id: 'GHSA-1111-2222-3333',
|
|
846
|
+
aliases: ['CVE-2024-0001'],
|
|
847
|
+
summary: 'Example Library Deserialization',
|
|
848
|
+
},
|
|
849
|
+
]),
|
|
850
|
+
{
|
|
851
|
+
vulnerabilities: [
|
|
852
|
+
{
|
|
853
|
+
cveID: 'CVE-2024-9999',
|
|
854
|
+
vendorProject: 'Progress',
|
|
855
|
+
product: 'LoadMaster',
|
|
856
|
+
vulnerabilityName: 'Progress LoadMaster Command Injection',
|
|
857
|
+
dateAdded: '2024-01-02',
|
|
858
|
+
},
|
|
859
|
+
],
|
|
860
|
+
},
|
|
861
|
+
);
|
|
862
|
+
|
|
863
|
+
await runWithKevReporting(useCase);
|
|
864
|
+
|
|
865
|
+
expect(
|
|
866
|
+
kevReportCalls(mockIssueRepository.createNewIssue.mock.calls),
|
|
867
|
+
).toHaveLength(0);
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
it('reports a KEV addition whose CVE the scanner returned as the vulnerability id rather than an alias', async () => {
|
|
871
|
+
const { useCase, mockIssueRepository } = buildScanEnvironment(
|
|
872
|
+
osvScanOutput([
|
|
873
|
+
{
|
|
874
|
+
name: 'example-library',
|
|
875
|
+
version: '1.2.3',
|
|
876
|
+
ecosystem: 'npm',
|
|
877
|
+
id: 'CVE-2024-0001',
|
|
878
|
+
aliases: [],
|
|
879
|
+
summary: 'Example Library Deserialization',
|
|
880
|
+
},
|
|
881
|
+
]),
|
|
882
|
+
{
|
|
883
|
+
vulnerabilities: [
|
|
884
|
+
{
|
|
885
|
+
cveID: 'CVE-2024-0001',
|
|
886
|
+
vendorProject: 'Example',
|
|
887
|
+
product: 'ExampleLibrary',
|
|
888
|
+
vulnerabilityName: 'Example Library Deserialization',
|
|
889
|
+
dateAdded: '2024-01-02',
|
|
890
|
+
},
|
|
891
|
+
],
|
|
892
|
+
},
|
|
893
|
+
);
|
|
894
|
+
|
|
895
|
+
await runWithKevReporting(useCase);
|
|
896
|
+
|
|
897
|
+
expect(
|
|
898
|
+
kevReportCalls(mockIssueRepository.createNewIssue.mock.calls),
|
|
899
|
+
).toHaveLength(1);
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
it('does not search the repositories for the KEV product name', async () => {
|
|
903
|
+
const { useCase, mockLocalCommandRunner } = buildScanEnvironment(
|
|
904
|
+
osvScanOutput([
|
|
905
|
+
{
|
|
906
|
+
name: 'example-library',
|
|
907
|
+
version: '1.2.3',
|
|
908
|
+
ecosystem: 'npm',
|
|
909
|
+
id: 'GHSA-1111-2222-3333',
|
|
910
|
+
aliases: ['CVE-2024-0001'],
|
|
911
|
+
summary: 'Example Library Deserialization',
|
|
912
|
+
},
|
|
913
|
+
]),
|
|
914
|
+
{
|
|
915
|
+
vulnerabilities: [
|
|
916
|
+
{
|
|
917
|
+
cveID: 'CVE-2024-0001',
|
|
918
|
+
vendorProject: 'Example',
|
|
919
|
+
product: 'ExampleLibrary',
|
|
920
|
+
vulnerabilityName: 'Example Library Deserialization',
|
|
921
|
+
dateAdded: '2024-01-02',
|
|
922
|
+
},
|
|
923
|
+
],
|
|
924
|
+
},
|
|
925
|
+
);
|
|
926
|
+
|
|
927
|
+
await runWithKevReporting(useCase);
|
|
928
|
+
|
|
929
|
+
const grepCalls = mockLocalCommandRunner.runCommand.mock.calls.filter(
|
|
930
|
+
(call) => call[0] === 'git' && call[1].includes('grep'),
|
|
931
|
+
);
|
|
932
|
+
expect(grepCalls).toHaveLength(0);
|
|
933
|
+
});
|
|
872
934
|
});
|
|
873
935
|
});
|