github.com/SAP/jenkins-library@v1.362.0/pkg/contrast/contrast.go (about)

     1  package contrast
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/SAP/jenkins-library/pkg/log"
     7  )
     8  
     9  const (
    10  	StatusReported = "REPORTED"
    11  	Critical       = "CRITICAL"
    12  	High           = "HIGH"
    13  	Medium         = "MEDIUM"
    14  	AuditAll       = "Audit All"
    15  	Optional       = "Optional"
    16  	pageSize       = 100
    17  	startPage      = 0
    18  )
    19  
    20  type VulnerabilitiesResponse struct {
    21  	Size            int             `json:"size"`
    22  	TotalElements   int             `json:"totalElements"`
    23  	TotalPages      int             `json:"totalPages"`
    24  	Empty           bool            `json:"empty"`
    25  	First           bool            `json:"first"`
    26  	Last            bool            `json:"last"`
    27  	Vulnerabilities []Vulnerability `json:"content"`
    28  }
    29  
    30  type Vulnerability struct {
    31  	Severity string `json:"severity"`
    32  	Status   string `json:"status"`
    33  }
    34  
    35  type ApplicationResponse struct {
    36  	Id          string `json:"id"`
    37  	Name        string `json:"name"`
    38  	DisplayName string `json:"displayName"`
    39  	Path        string `json:"path"`
    40  	Language    string `json:"language"`
    41  	Importance  string `json:"importance"`
    42  }
    43  
    44  type Contrast interface {
    45  	GetVulnerabilities() error
    46  	GetAppInfo(appUIUrl, server string)
    47  }
    48  
    49  type ContrastInstance struct {
    50  	url    string
    51  	apiKey string
    52  	auth   string
    53  }
    54  
    55  func NewContrastInstance(url, apiKey, auth string) ContrastInstance {
    56  	return ContrastInstance{
    57  		url:    url,
    58  		apiKey: apiKey,
    59  		auth:   auth,
    60  	}
    61  }
    62  
    63  func (contrast *ContrastInstance) GetVulnerabilities() ([]ContrastFindings, error) {
    64  	url := contrast.url + "/vulnerabilities"
    65  	client := NewContrastHttpClient(contrast.apiKey, contrast.auth)
    66  
    67  	return getVulnerabilitiesFromClient(client, url, startPage)
    68  }
    69  
    70  func (contrast *ContrastInstance) GetAppInfo(appUIUrl, server string) (*ApplicationInfo, error) {
    71  	client := NewContrastHttpClient(contrast.apiKey, contrast.auth)
    72  	app, err := getApplicationFromClient(client, contrast.url)
    73  	if err != nil {
    74  		log.Entry().Errorf("failed to get application from client: %v", err)
    75  		return nil, err
    76  	}
    77  	app.Url = appUIUrl
    78  	app.Server = server
    79  	return app, nil
    80  }
    81  
    82  func getApplicationFromClient(client ContrastHttpClient, url string) (*ApplicationInfo, error) {
    83  	var appResponse ApplicationResponse
    84  	err := client.ExecuteRequest(url, nil, &appResponse)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	return &ApplicationInfo{
    90  		Id:   appResponse.Id,
    91  		Name: appResponse.Name,
    92  	}, nil
    93  }
    94  
    95  func getVulnerabilitiesFromClient(client ContrastHttpClient, url string, page int) ([]ContrastFindings, error) {
    96  	params := map[string]string{
    97  		"page": fmt.Sprintf("%d", page),
    98  		"size": fmt.Sprintf("%d", pageSize),
    99  	}
   100  	var vulnsResponse VulnerabilitiesResponse
   101  	err := client.ExecuteRequest(url, params, &vulnsResponse)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  
   106  	if vulnsResponse.Empty {
   107  		log.Entry().Info("empty vulnerabilities response")
   108  		return []ContrastFindings{}, nil
   109  	}
   110  
   111  	auditAllFindings, optionalFindings := getFindings(vulnsResponse.Vulnerabilities)
   112  
   113  	if !vulnsResponse.Last {
   114  		findings, err := getVulnerabilitiesFromClient(client, url, page+1)
   115  		if err != nil {
   116  			return nil, err
   117  		}
   118  		accumulateFindings(auditAllFindings, optionalFindings, findings)
   119  		return findings, nil
   120  	}
   121  	return []ContrastFindings{auditAllFindings, optionalFindings}, nil
   122  }
   123  
   124  func getFindings(vulnerabilities []Vulnerability) (ContrastFindings, ContrastFindings) {
   125  	var auditAllFindings, optionalFindings ContrastFindings
   126  	auditAllFindings.ClassificationName = AuditAll
   127  	optionalFindings.ClassificationName = Optional
   128  
   129  	for _, vuln := range vulnerabilities {
   130  		if vuln.Severity == Critical || vuln.Severity == High || vuln.Severity == Medium {
   131  			if vuln.Status != StatusReported {
   132  				auditAllFindings.Audited += 1
   133  			}
   134  			auditAllFindings.Total += 1
   135  		} else {
   136  			if vuln.Status != StatusReported {
   137  				optionalFindings.Audited += 1
   138  			}
   139  			optionalFindings.Total += 1
   140  		}
   141  	}
   142  	return auditAllFindings, optionalFindings
   143  }
   144  
   145  func accumulateFindings(auditAllFindings, optionalFindings ContrastFindings, contrastFindings []ContrastFindings) {
   146  	for i, fr := range contrastFindings {
   147  		if fr.ClassificationName == AuditAll {
   148  			contrastFindings[i].Total += auditAllFindings.Total
   149  			contrastFindings[i].Audited += auditAllFindings.Audited
   150  		}
   151  		if fr.ClassificationName == Optional {
   152  			contrastFindings[i].Total += optionalFindings.Total
   153  			contrastFindings[i].Audited += optionalFindings.Audited
   154  		}
   155  	}
   156  }