code-intelligence.com/cifuzz@v0.40.0/internal/api/finding.go (about)

     1  package api
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net/url"
     8  	"time"
     9  
    10  	"github.com/pkg/errors"
    11  
    12  	"code-intelligence.com/cifuzz/pkg/finding"
    13  	"code-intelligence.com/cifuzz/pkg/log"
    14  )
    15  
    16  type Findings struct {
    17  	Findings []Finding `json:"findings"`
    18  }
    19  
    20  type Finding struct {
    21  	Name        string      `json:"name"`
    22  	DisplayName string      `json:"display_name"`
    23  	FuzzTarget  string      `json:"fuzz_target"`
    24  	FuzzingRun  string      `json:"fuzzing_run"`
    25  	CampaignRun string      `json:"campaign_run"`
    26  	ErrorReport ErrorReport `json:"error_report"`
    27  	Timestamp   string      `json:"timestamp"`
    28  }
    29  
    30  type ErrorReport struct {
    31  	Logs      []string `json:"logs"`
    32  	Details   string   `json:"details"`
    33  	Type      string   `json:"type,omitempty"`
    34  	InputData []byte   `json:"input_data,omitempty"`
    35  
    36  	DebuggingInfo      *DebuggingInfo        `json:"debugging_info,omitempty"`
    37  	HumanReadableInput string                `json:"human_readable_input,omitempty"`
    38  	MoreDetails        *finding.ErrorDetails `json:"more_details,omitempty"`
    39  	Tag                string                `json:"tag,omitempty"`
    40  	ShortDescription   string                `json:"short_description,omitempty"`
    41  }
    42  
    43  type DebuggingInfo struct {
    44  	ExecutablePath string        `json:"executable_path,omitempty"`
    45  	RunArguments   []string      `json:"run_arguments,omitempty"`
    46  	BreakPoints    []BreakPoint  `json:"break_points,omitempty"`
    47  	Environment    []Environment `json:"environment,omitempty"`
    48  }
    49  
    50  type BreakPoint struct {
    51  	SourceFilePath string           `json:"source_file_path,omitempty"`
    52  	Location       *FindingLocation `json:"location,omitempty"`
    53  	Function       string           `json:"function,omitempty"`
    54  }
    55  
    56  type FindingLocation struct {
    57  	Line   uint32 `json:"line,omitempty"`
    58  	Column uint32 `json:"column,omitempty"`
    59  }
    60  
    61  type Environment struct {
    62  	Name  string `json:"name,omitempty"`
    63  	Value string `json:"value,omitempty"`
    64  }
    65  
    66  type Severity struct {
    67  	Description string  `json:"description,omitempty"`
    68  	Score       float32 `json:"score,omitempty"`
    69  }
    70  
    71  func (client *APIClient) UploadFinding(project string, fuzzTarget string, campaignRunName string, fuzzingRunName string, finding *finding.Finding, token string) error {
    72  	// loop through the stack trace and create a list of breakpoints
    73  	breakPoints := []BreakPoint{}
    74  	for _, stackFrame := range finding.StackTrace {
    75  		breakPoints = append(breakPoints, BreakPoint{
    76  			SourceFilePath: stackFrame.SourceFile,
    77  			Location: &FindingLocation{
    78  				Line:   stackFrame.Line,
    79  				Column: stackFrame.Column,
    80  			},
    81  			Function: stackFrame.Function,
    82  		})
    83  	}
    84  
    85  	errorDetails, err := client.GetErrorDetails(token)
    86  	if err != nil {
    87  		var connErr *ConnectionError
    88  		if !errors.As(err, &connErr) {
    89  			return err
    90  		} else {
    91  			log.Warn("Connection to API failed. Skipping error details.")
    92  			log.Debugf("Connection error: %v (continuing gracefully)", err)
    93  			return nil
    94  		}
    95  	}
    96  
    97  	finding.EnhanceWithErrorDetails(&errorDetails)
    98  
    99  	findings := &Findings{
   100  		Findings: []Finding{
   101  			{
   102  				Name:        project + "/findings/cifuzz-" + finding.Name,
   103  				DisplayName: finding.Name,
   104  				FuzzTarget:  fuzzTarget,
   105  				FuzzingRun:  fuzzingRunName,
   106  				CampaignRun: campaignRunName,
   107  				ErrorReport: ErrorReport{
   108  					Logs:      finding.Logs,
   109  					Details:   finding.Details,
   110  					Type:      string(finding.Type),
   111  					InputData: finding.InputData,
   112  					DebuggingInfo: &DebuggingInfo{
   113  						BreakPoints: breakPoints,
   114  					},
   115  					MoreDetails:      finding.MoreDetails,
   116  					Tag:              fmt.Sprint(finding.Tag),
   117  					ShortDescription: finding.ShortDescription(),
   118  				},
   119  				Timestamp: time.Now().Format(time.RFC3339),
   120  			},
   121  		},
   122  	}
   123  
   124  	body, err := json.Marshal(findings)
   125  	if err != nil {
   126  		return errors.WithStack(err)
   127  	}
   128  
   129  	url, err := url.JoinPath("/v1", project, "findings")
   130  	if err != nil {
   131  		return errors.WithStack(err)
   132  	}
   133  	resp, err := client.sendRequest("POST", url, bytes.NewReader(body), token)
   134  	if err != nil {
   135  		return err
   136  	}
   137  	defer resp.Body.Close()
   138  
   139  	if resp.StatusCode != 200 {
   140  		return responseToAPIError(resp)
   141  	}
   142  
   143  	return nil
   144  }