diff --git a/client.go b/client.go index f16a1f6..58fdd8f 100644 --- a/client.go +++ b/client.go @@ -27,15 +27,16 @@ type Client struct { userAgent string debug bool - About AboutService - Analysis AnalysisService - BOM BOMService - Component ComponentService - Finding FindingService - License LicenseService - Project ProjectService - Repository RepositoryService - User UserService + About AboutService + Analysis AnalysisService + BOM BOMService + Component ComponentService + Finding FindingService + License LicenseService + Project ProjectService + Repository RepositoryService + User UserService + Vulnerability VulnerabilityService } func NewClient(baseURL string, options ...ClientOption) (*Client, error) { @@ -72,6 +73,7 @@ func NewClient(baseURL string, options ...ClientOption) (*Client, error) { client.Project = ProjectService{client: &client} client.Repository = RepositoryService{client: &client} client.User = UserService{client: &client} + client.Vulnerability = VulnerabilityService{client: &client} return &client, nil } diff --git a/component.go b/component.go index e3ddd52..1e539dc 100644 --- a/component.go +++ b/component.go @@ -54,8 +54,23 @@ type ComponentService struct { client *Client } -func (c ComponentService) GetAll(ctx context.Context, project uuid.UUID, po PageOptions) (*ComponentsPage, error) { - req, err := c.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/component/project/%s", project), withPageOptions(po)) +func (c ComponentService) Get(ctx context.Context, componentUUID uuid.UUID) (*Component, error) { + req, err := c.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/component/%s", componentUUID)) + if err != nil { + return nil, err + } + + var component Component + _, err = c.client.doRequest(req, &component) + if err != nil { + return nil, err + } + + return &component, nil +} + +func (c ComponentService) GetAll(ctx context.Context, projectUUID uuid.UUID, po PageOptions) (*ComponentsPage, error) { + req, err := c.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/component/project/%s", projectUUID), withPageOptions(po)) if err != nil { return nil, err } diff --git a/finding.go b/finding.go index 091faa4..db5c425 100644 --- a/finding.go +++ b/finding.go @@ -34,12 +34,12 @@ type FindingService struct { client *Client } -func (f FindingService) GetAll(ctx context.Context, project uuid.UUID, suppressed bool, po PageOptions) (*FindingsPage, error) { +func (f FindingService) GetAll(ctx context.Context, projectUUID uuid.UUID, suppressed bool, po PageOptions) (*FindingsPage, error) { params := map[string]string{ "suppressed": strconv.FormatBool(suppressed), } - req, err := f.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/finding/project/%s", project), withParams(params), withPageOptions(po)) + req, err := f.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/finding/project/%s", projectUUID), withParams(params), withPageOptions(po)) if err != nil { return nil, err } diff --git a/project.go b/project.go index 2af9a72..446d2e0 100644 --- a/project.go +++ b/project.go @@ -37,8 +37,8 @@ type ProjectService struct { client *Client } -func (p ProjectService) Get(ctx context.Context, u uuid.UUID) (*Project, error) { - req, err := p.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/project/%s", u)) +func (p ProjectService) Get(ctx context.Context, projectUUID uuid.UUID) (*Project, error) { + req, err := p.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/project/%s", projectUUID)) if err != nil { return nil, err } @@ -91,7 +91,7 @@ func (p ProjectService) GetAll(ctx context.Context, po PageOptions) (*ProjectsPa } type ProjectCloneRequest struct { - UUID uuid.UUID `json:"project"` + ProjectUUID uuid.UUID `json:"project"` Version string `json:"version"` IncludeAuditHistory bool `json:"includeAuditHistory"` IncludeComponents bool `json:"includeComponents"` diff --git a/vulnerability.go b/vulnerability.go index 7ba5487..f8cf480 100644 --- a/vulnerability.go +++ b/vulnerability.go @@ -1,10 +1,133 @@ package dtrack -import "github.com/google/uuid" +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/google/uuid" +) type Vulnerability struct { - UUID uuid.UUID `json:"uuid"` - VulnID string `json:"vulnId"` - Source string `json:"source"` - Severity string `json:"severity"` + UUID uuid.UUID `json:"uuid"` + VulnID string `json:"vulnId"` + Source string `json:"source"` + + Title string `json:"title"` + SubTitle string `json:"subTitle"` + Description string `json:"description"` + Recommendation string `json:"recommendation"` + References string `json:"references"` + Credits string `json:"credits"` + + Created time.Time `json:"created"` + Published time.Time `json:"published"` + + CWE CWE `json:"cwe"` + CVSSV2BaseScore float64 `json:"cvssV2BaseScore"` + CVSSV2ImpactSubScore float64 `json:"cvssV2ImpactSubScore"` + CVSSV2ExploitabilitySubScore float64 `json:"cvssV2ExploitabilitySubScore"` + CVSSV2Vector string `json:"cvssV2Vector"` + CVSSV3BaseScore float64 `json:"cvssV3BaseScore"` + CVSSV3ImpactSubScore float64 `json:"cvssV3ImpactSubScore"` + CVSSV3ExploitabilitySubScore float64 `json:"cvssV3ExploitabilitySubScore"` + CVSSV3Vector string `json:"cvssV3Vector"` + Severity string `json:"severity"` + + VulnerableVersions string `json:"vulnerableVersions"` + PatchedVersions string `json:"patchedVersions"` +} + +type VulnerabilitiesPage struct { + Vulnerabilities []Vulnerability + TotalCount int +} + +type CWE struct { + ID int `json:"cweId"` + Name string `json:"name"` +} + +type VulnerabilityService struct { + client *Client +} + +func (v VulnerabilityService) Get(ctx context.Context, vulnUUID uuid.UUID) (*Vulnerability, error) { + req, err := v.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/vulnerability/%s", vulnUUID)) + if err != nil { + return nil, err + } + + var vulnerability Vulnerability + _, err = v.client.doRequest(req, &vulnerability) + if err != nil { + return nil, err + } + + return &vulnerability, nil +} + +func (v VulnerabilityService) GetAllForComponent(ctx context.Context, componentUUID uuid.UUID, po PageOptions) (*VulnerabilitiesPage, error) { + req, err := v.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/vulnerability/component/%s", componentUUID), withPageOptions(po)) + if err != nil { + return nil, err + } + + var vulnerabilities []Vulnerability + res, err := v.client.doRequest(req, &vulnerabilities) + if err != nil { + return nil, err + } + + return &VulnerabilitiesPage{ + Vulnerabilities: vulnerabilities, + TotalCount: res.TotalCount, + }, nil +} + +func (v VulnerabilityService) GetAllForProject(ctx context.Context, projectUUID uuid.UUID, po PageOptions) (*VulnerabilitiesPage, error) { + req, err := v.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/vulnerability/project/%s", projectUUID), withPageOptions(po)) + if err != nil { + return nil, err + } + + var vulnerabilities []Vulnerability + res, err := v.client.doRequest(req, &vulnerabilities) + if err != nil { + return nil, err + } + + return &VulnerabilitiesPage{ + Vulnerabilities: vulnerabilities, + TotalCount: res.TotalCount, + }, nil +} + +func (v VulnerabilityService) Assign(ctx context.Context, vulnUUID, componentUUID uuid.UUID) error { + req, err := v.client.newRequest(ctx, http.MethodPost, fmt.Sprintf("/api/v1/vulnerability/%s/component/%s", vulnUUID, componentUUID)) + if err != nil { + return err + } + + _, err = v.client.doRequest(req, nil) + if err != nil { + return err + } + + return nil +} + +func (v VulnerabilityService) Unassign(ctx context.Context, vulnUUID, componentUUID uuid.UUID) error { + req, err := v.client.newRequest(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/vulnerability/%s/component/%s", vulnUUID, componentUUID)) + if err != nil { + return err + } + + _, err = v.client.doRequest(req, nil) + if err != nil { + return err + } + + return nil }