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

     1  package client
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"net/http"
     7  
     8  	"golang.org/x/xerrors"
     9  
    10  	ftypes "github.com/devseccon/trivy/pkg/fanal/types"
    11  	r "github.com/devseccon/trivy/pkg/rpc"
    12  	"github.com/devseccon/trivy/pkg/types"
    13  	xstrings "github.com/devseccon/trivy/pkg/x/strings"
    14  	rpc "github.com/devseccon/trivy/rpc/scanner"
    15  )
    16  
    17  type options struct {
    18  	rpcClient rpc.Scanner
    19  }
    20  
    21  type Option func(*options)
    22  
    23  // WithRPCClient takes rpc client for testability
    24  func WithRPCClient(c rpc.Scanner) Option {
    25  	return func(opts *options) {
    26  		opts.rpcClient = c
    27  	}
    28  }
    29  
    30  // ScannerOption holds options for RPC client
    31  type ScannerOption struct {
    32  	RemoteURL     string
    33  	Insecure      bool
    34  	CustomHeaders http.Header
    35  }
    36  
    37  // Scanner implements the RPC scanner
    38  type Scanner struct {
    39  	customHeaders http.Header
    40  	client        rpc.Scanner
    41  }
    42  
    43  // NewScanner is the factory method to return RPC Scanner
    44  func NewScanner(scannerOptions ScannerOption, opts ...Option) Scanner {
    45  	httpClient := &http.Client{
    46  		Transport: &http.Transport{
    47  			Proxy: http.ProxyFromEnvironment,
    48  			TLSClientConfig: &tls.Config{
    49  				InsecureSkipVerify: scannerOptions.Insecure,
    50  			},
    51  		},
    52  	}
    53  
    54  	c := rpc.NewScannerProtobufClient(scannerOptions.RemoteURL, httpClient)
    55  
    56  	o := &options{rpcClient: c}
    57  	for _, opt := range opts {
    58  		opt(o)
    59  	}
    60  
    61  	return Scanner{
    62  		customHeaders: scannerOptions.CustomHeaders,
    63  		client:        o.rpcClient,
    64  	}
    65  }
    66  
    67  // Scan scans the image
    68  func (s Scanner) Scan(ctx context.Context, target, artifactKey string, blobKeys []string, opts types.ScanOptions) (types.Results, ftypes.OS, error) {
    69  	ctx = WithCustomHeaders(ctx, s.customHeaders)
    70  
    71  	// Convert to the rpc struct
    72  	licenseCategories := make(map[string]*rpc.Licenses)
    73  	for category, names := range opts.LicenseCategories {
    74  		licenseCategories[string(category)] = &rpc.Licenses{Names: names}
    75  	}
    76  
    77  	var res *rpc.ScanResponse
    78  	err := r.Retry(func() error {
    79  		var err error
    80  		res, err = s.client.Scan(ctx, &rpc.ScanRequest{
    81  			Target:     target,
    82  			ArtifactId: artifactKey,
    83  			BlobIds:    blobKeys,
    84  			Options: &rpc.ScanOptions{
    85  				VulnType:          opts.VulnType,
    86  				Scanners:          xstrings.ToStringSlice(opts.Scanners),
    87  				ListAllPackages:   opts.ListAllPackages,
    88  				LicenseCategories: licenseCategories,
    89  				IncludeDevDeps:    opts.IncludeDevDeps,
    90  			},
    91  		})
    92  		return err
    93  	})
    94  	if err != nil {
    95  		return nil, ftypes.OS{}, xerrors.Errorf("failed to detect vulnerabilities via RPC: %w", err)
    96  	}
    97  
    98  	return r.ConvertFromRPCResults(res.Results), r.ConvertFromRPCOS(res.Os), nil
    99  }