@@ -564,4 +564,128 @@ public void GenerateScanResult_MultipleRichAndBare_BareGraphDataAbsorbedByAllRic
564564 // Both rich entries should have the bare graph's file path (package.json)
565565 lodashResults . Should ( ) . OnlyContain ( c => c . LocationsFoundAt . Any ( l => l . Contains ( "package.json" ) ) ) ;
566566 }
567+
568+ [ TestMethod ]
569+ public void FilterBaseImageComponents_RemovesComponentsExclusivelyFromBaseImageLayers ( )
570+ {
571+ var singleFileRecorder = this . componentRecorder . CreateSingleFileComponentRecorder ( Path . Join ( this . sourceDirectory . FullName , "/file1" ) ) ;
572+
573+ var baseImageComponent = new DetectedComponent ( new NpmComponent ( "base-pkg" , "1.0.0" ) , containerDetailsId : 1 , containerLayerId : 0 ) ;
574+ singleFileRecorder . RegisterUsage ( baseImageComponent ) ;
575+
576+ var containerDetailsMap = new Dictionary < int , ContainerDetails >
577+ {
578+ [ 1 ] = new ContainerDetails
579+ {
580+ Id = 1 ,
581+ Layers = [ new DockerLayer { LayerIndex = 0 , IsBaseImage = true } , new DockerLayer { LayerIndex = 1 , IsBaseImage = false } ] ,
582+ } ,
583+ } ;
584+
585+ var processingResult = new DetectorProcessingResult
586+ {
587+ ResultCode = ProcessingResultCode . Success ,
588+ ContainersDetailsMap = containerDetailsMap ,
589+ ComponentRecorders = [ ( this . componentDetectorMock . Object , this . componentRecorder ) ] ,
590+ } ;
591+
592+ var result = this . serviceUnderTest . GenerateScanResultFromProcessingResult (
593+ processingResult , new ScanSettings { SourceDirectory = this . sourceDirectory , FilterBaseImageComponents = true } ) ;
594+
595+ result . ComponentsFound . Should ( ) . BeEmpty ( ) ;
596+ }
597+
598+ [ TestMethod ]
599+ public void FilterBaseImageComponents_RetainsComponentsWithMixedLayers ( )
600+ {
601+ var singleFileRecorder = this . componentRecorder . CreateSingleFileComponentRecorder ( Path . Join ( this . sourceDirectory . FullName , "/file1" ) ) ;
602+
603+ var mixedComponent = new DetectedComponent ( new NpmComponent ( "mixed-pkg" , "1.0.0" ) , containerDetailsId : 1 , containerLayerId : 0 ) ;
604+ mixedComponent . ContainerLayerIds [ 1 ] = [ 0 , 1 ] ;
605+ singleFileRecorder . RegisterUsage ( mixedComponent ) ;
606+
607+ var containerDetailsMap = new Dictionary < int , ContainerDetails >
608+ {
609+ [ 1 ] = new ContainerDetails
610+ {
611+ Id = 1 ,
612+ Layers = [ new DockerLayer { LayerIndex = 0 , IsBaseImage = true } , new DockerLayer { LayerIndex = 1 , IsBaseImage = false } ] ,
613+ } ,
614+ } ;
615+
616+ var processingResult = new DetectorProcessingResult
617+ {
618+ ResultCode = ProcessingResultCode . Success ,
619+ ContainersDetailsMap = containerDetailsMap ,
620+ ComponentRecorders = [ ( this . componentDetectorMock . Object , this . componentRecorder ) ] ,
621+ } ;
622+
623+ var result = this . serviceUnderTest . GenerateScanResultFromProcessingResult (
624+ processingResult , new ScanSettings { SourceDirectory = this . sourceDirectory , FilterBaseImageComponents = true } ) ;
625+
626+ result . ComponentsFound . Should ( ) . HaveCount ( 1 ) ;
627+ ( ( NpmComponent ) result . ComponentsFound . Single ( ) . Component ) . Name . Should ( ) . Be ( "mixed-pkg" ) ;
628+ }
629+
630+ [ TestMethod ]
631+ public void FilterBaseImageComponents_RetainsComponentsWithNoContainerReferences ( )
632+ {
633+ var singleFileRecorder = this . componentRecorder . CreateSingleFileComponentRecorder ( Path . Join ( this . sourceDirectory . FullName , "/file1" ) ) ;
634+
635+ var filesystemComponent = new DetectedComponent ( new NpmComponent ( "fs-pkg" , "2.0.0" ) ) ;
636+ singleFileRecorder . RegisterUsage ( filesystemComponent ) ;
637+
638+ var containerDetailsMap = new Dictionary < int , ContainerDetails >
639+ {
640+ [ 1 ] = new ContainerDetails
641+ {
642+ Id = 1 ,
643+ Layers = [ new DockerLayer { LayerIndex = 0 , IsBaseImage = true } ] ,
644+ } ,
645+ } ;
646+
647+ var processingResult = new DetectorProcessingResult
648+ {
649+ ResultCode = ProcessingResultCode . Success ,
650+ ContainersDetailsMap = containerDetailsMap ,
651+ ComponentRecorders = [ ( this . componentDetectorMock . Object , this . componentRecorder ) ] ,
652+ } ;
653+
654+ var result = this . serviceUnderTest . GenerateScanResultFromProcessingResult (
655+ processingResult , new ScanSettings { SourceDirectory = this . sourceDirectory , FilterBaseImageComponents = true } ) ;
656+
657+ result . ComponentsFound . Should ( ) . HaveCount ( 1 ) ;
658+ ( ( NpmComponent ) result . ComponentsFound . Single ( ) . Component ) . Name . Should ( ) . Be ( "fs-pkg" ) ;
659+ }
660+
661+ [ TestMethod ]
662+ public void FilterBaseImageComponents_NoOpWhenFlagIsDisabled ( )
663+ {
664+ var singleFileRecorder = this . componentRecorder . CreateSingleFileComponentRecorder ( Path . Join ( this . sourceDirectory . FullName , "/file1" ) ) ;
665+
666+ var baseImageComponent = new DetectedComponent ( new NpmComponent ( "base-pkg" , "1.0.0" ) , containerDetailsId : 1 , containerLayerId : 0 ) ;
667+ singleFileRecorder . RegisterUsage ( baseImageComponent ) ;
668+
669+ var containerDetailsMap = new Dictionary < int , ContainerDetails >
670+ {
671+ [ 1 ] = new ContainerDetails
672+ {
673+ Id = 1 ,
674+ Layers = [ new DockerLayer { LayerIndex = 0 , IsBaseImage = true } ] ,
675+ } ,
676+ } ;
677+
678+ var processingResult = new DetectorProcessingResult
679+ {
680+ ResultCode = ProcessingResultCode . Success ,
681+ ContainersDetailsMap = containerDetailsMap ,
682+ ComponentRecorders = [ ( this . componentDetectorMock . Object , this . componentRecorder ) ] ,
683+ } ;
684+
685+ var result = this . serviceUnderTest . GenerateScanResultFromProcessingResult (
686+ processingResult , new ScanSettings { SourceDirectory = this . sourceDirectory , FilterBaseImageComponents = false } ) ;
687+
688+ result . ComponentsFound . Should ( ) . HaveCount ( 1 ) ;
689+ ( ( NpmComponent ) result . ComponentsFound . Single ( ) . Component ) . Name . Should ( ) . Be ( "base-pkg" ) ;
690+ }
567691}
0 commit comments