github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/scanner/scan.go (about)

     1  package scanner
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/google/wire"
     7  	"golang.org/x/xerrors"
     8  
     9  	"github.com/devseccon/trivy/pkg/clock"
    10  	"github.com/devseccon/trivy/pkg/fanal/artifact"
    11  	aimage "github.com/devseccon/trivy/pkg/fanal/artifact/image"
    12  	flocal "github.com/devseccon/trivy/pkg/fanal/artifact/local"
    13  	"github.com/devseccon/trivy/pkg/fanal/artifact/repo"
    14  	"github.com/devseccon/trivy/pkg/fanal/artifact/sbom"
    15  	"github.com/devseccon/trivy/pkg/fanal/artifact/vm"
    16  	"github.com/devseccon/trivy/pkg/fanal/image"
    17  	ftypes "github.com/devseccon/trivy/pkg/fanal/types"
    18  	"github.com/devseccon/trivy/pkg/log"
    19  	"github.com/devseccon/trivy/pkg/report"
    20  	"github.com/devseccon/trivy/pkg/rpc/client"
    21  	"github.com/devseccon/trivy/pkg/scanner/local"
    22  	"github.com/devseccon/trivy/pkg/types"
    23  )
    24  
    25  ///////////////
    26  // Standalone
    27  ///////////////
    28  
    29  // StandaloneSuperSet is used in the standalone mode
    30  var StandaloneSuperSet = wire.NewSet(
    31  	local.SuperSet,
    32  	wire.Bind(new(Driver), new(local.Scanner)),
    33  	NewScanner,
    34  )
    35  
    36  // StandaloneDockerSet binds docker dependencies
    37  var StandaloneDockerSet = wire.NewSet(
    38  	image.NewContainerImage,
    39  	aimage.NewArtifact,
    40  	StandaloneSuperSet,
    41  )
    42  
    43  // StandaloneArchiveSet binds archive scan dependencies
    44  var StandaloneArchiveSet = wire.NewSet(
    45  	image.NewArchiveImage,
    46  	aimage.NewArtifact,
    47  	StandaloneSuperSet,
    48  )
    49  
    50  // StandaloneFilesystemSet binds filesystem dependencies
    51  var StandaloneFilesystemSet = wire.NewSet(
    52  	flocal.NewArtifact,
    53  	StandaloneSuperSet,
    54  )
    55  
    56  // StandaloneRepositorySet binds repository dependencies
    57  var StandaloneRepositorySet = wire.NewSet(
    58  	repo.NewArtifact,
    59  	StandaloneSuperSet,
    60  )
    61  
    62  // StandaloneSBOMSet binds sbom dependencies
    63  var StandaloneSBOMSet = wire.NewSet(
    64  	sbom.NewArtifact,
    65  	StandaloneSuperSet,
    66  )
    67  
    68  // StandaloneVMSet binds vm dependencies
    69  var StandaloneVMSet = wire.NewSet(
    70  	vm.NewArtifact,
    71  	StandaloneSuperSet,
    72  )
    73  
    74  /////////////////
    75  // Client/Server
    76  /////////////////
    77  
    78  // RemoteSuperSet is used in the client mode
    79  var RemoteSuperSet = wire.NewSet(
    80  	client.NewScanner,
    81  	wire.Value([]client.Option(nil)),
    82  	wire.Bind(new(Driver), new(client.Scanner)),
    83  	NewScanner,
    84  )
    85  
    86  // RemoteFilesystemSet binds filesystem dependencies for client/server mode
    87  var RemoteFilesystemSet = wire.NewSet(
    88  	flocal.NewArtifact,
    89  	RemoteSuperSet,
    90  )
    91  
    92  // RemoteRepositorySet binds repository dependencies for client/server mode
    93  var RemoteRepositorySet = wire.NewSet(
    94  	repo.NewArtifact,
    95  	RemoteSuperSet,
    96  )
    97  
    98  // RemoteSBOMSet binds sbom dependencies for client/server mode
    99  var RemoteSBOMSet = wire.NewSet(
   100  	sbom.NewArtifact,
   101  	RemoteSuperSet,
   102  )
   103  
   104  // RemoteVMSet binds vm dependencies for client/server mode
   105  var RemoteVMSet = wire.NewSet(
   106  	vm.NewArtifact,
   107  	RemoteSuperSet,
   108  )
   109  
   110  // RemoteDockerSet binds remote docker dependencies
   111  var RemoteDockerSet = wire.NewSet(
   112  	aimage.NewArtifact,
   113  	image.NewContainerImage,
   114  	RemoteSuperSet,
   115  )
   116  
   117  // RemoteArchiveSet binds remote archive dependencies
   118  var RemoteArchiveSet = wire.NewSet(
   119  	aimage.NewArtifact,
   120  	image.NewArchiveImage,
   121  	RemoteSuperSet,
   122  )
   123  
   124  // Scanner implements the Artifact and Driver operations
   125  type Scanner struct {
   126  	driver   Driver
   127  	artifact artifact.Artifact
   128  }
   129  
   130  // Driver defines operations of scanner
   131  type Driver interface {
   132  	Scan(ctx context.Context, target, artifactKey string, blobKeys []string, options types.ScanOptions) (
   133  		results types.Results, osFound ftypes.OS, err error)
   134  }
   135  
   136  // NewScanner is the factory method of Scanner
   137  func NewScanner(driver Driver, ar artifact.Artifact) Scanner {
   138  	return Scanner{
   139  		driver:   driver,
   140  		artifact: ar,
   141  	}
   142  }
   143  
   144  // ScanArtifact scans the artifacts and returns results
   145  func (s Scanner) ScanArtifact(ctx context.Context, options types.ScanOptions) (types.Report, error) {
   146  	artifactInfo, err := s.artifact.Inspect(ctx)
   147  	if err != nil {
   148  		return types.Report{}, xerrors.Errorf("failed analysis: %w", err)
   149  	}
   150  	defer func() {
   151  		if err := s.artifact.Clean(artifactInfo); err != nil {
   152  			log.Logger.Warnf("Failed to clean the artifact %q: %v", artifactInfo.Name, err)
   153  		}
   154  	}()
   155  
   156  	results, osFound, err := s.driver.Scan(ctx, artifactInfo.Name, artifactInfo.ID, artifactInfo.BlobIDs, options)
   157  	if err != nil {
   158  		return types.Report{}, xerrors.Errorf("scan failed: %w", err)
   159  	}
   160  
   161  	ptros := &osFound
   162  	if osFound.Detected() && osFound.Eosl {
   163  		log.Logger.Warnf("This OS version is no longer supported by the distribution: %s %s", osFound.Family, osFound.Name)
   164  		log.Logger.Warnf("The vulnerability detection may be insufficient because security updates are not provided")
   165  	} else if !osFound.Detected() {
   166  		ptros = nil
   167  	}
   168  
   169  	// Layer makes sense only when scanning container images
   170  	if artifactInfo.Type != ftypes.ArtifactContainerImage {
   171  		removeLayer(results)
   172  	}
   173  
   174  	return types.Report{
   175  		SchemaVersion: report.SchemaVersion,
   176  		CreatedAt:     clock.Now(),
   177  		ArtifactName:  artifactInfo.Name,
   178  		ArtifactType:  artifactInfo.Type,
   179  		Metadata: types.Metadata{
   180  			OS: ptros,
   181  
   182  			// Container image
   183  			ImageID:     artifactInfo.ImageMetadata.ID,
   184  			DiffIDs:     artifactInfo.ImageMetadata.DiffIDs,
   185  			RepoTags:    artifactInfo.ImageMetadata.RepoTags,
   186  			RepoDigests: artifactInfo.ImageMetadata.RepoDigests,
   187  			ImageConfig: artifactInfo.ImageMetadata.ConfigFile,
   188  		},
   189  		CycloneDX: artifactInfo.CycloneDX,
   190  		Results:   results,
   191  	}, nil
   192  }
   193  
   194  func removeLayer(results types.Results) {
   195  	for i := range results {
   196  		result := results[i]
   197  
   198  		for j := range result.Packages {
   199  			result.Packages[j].Layer = ftypes.Layer{}
   200  		}
   201  		for j := range result.Vulnerabilities {
   202  			result.Vulnerabilities[j].Layer = ftypes.Layer{}
   203  		}
   204  		for j := range result.Misconfigurations {
   205  			result.Misconfigurations[j].Layer = ftypes.Layer{}
   206  		}
   207  	}
   208  }