Repository: xanzy/go-gitlab
Pull request #1448 (2022-04-11 09:38:36)

added vulnerabilities

rotiv13: Just seeing if it possible to get implemented the vulnerabilities for each repo.
svanharmelen: Made this a draft PR as you also updated the `go.mod` file to point at your own fork... Additionally (as a premature review comment) the field types of the struct should not be `interface{}`, so please make sure they are of the correct type before finishing the PR. Thanks!
rotiv13: > Made this a draft PR as you also updated the `go.mod` file to point at your own fork... Additionally (as a premature review comment) the field types of the struct should not be `interface{}`, so please make sure they are of the correct type before finishing the PR. Thanks!

Yep makes sense. Thank you for the comment. I am basically experimenting with this and seeing if it is possible to get the vulnerabilities of a project. I will make it better once I see that everything is ready.

Patch:
diff --git a/gitlab.go b/gitlab.go
index d9d4f26..d1d59bb 100644
--- a/gitlab.go
+++ b/gitlab.go
@@ -101,105 +101,106 @@ type Client struct {
 	UserAgent string
 
 	// Services used for talking to different parts of the GitLab API.
-	AccessRequests        *AccessRequestsService
-	Applications          *ApplicationsService
-	AuditEvents           *AuditEventsService
-	Avatar                *AvatarRequestsService
-	AwardEmoji            *AwardEmojiService
-	Boards                *IssueBoardsService
-	Branches              *BranchesService
-	BroadcastMessage      *BroadcastMessagesService
-	CIYMLTemplate         *CIYMLTemplatesService
-	Commits               *CommitsService
-	ContainerRegistry     *ContainerRegistryService
-	CustomAttribute       *CustomAttributesService
-	DeployKeys            *DeployKeysService
-	DeployTokens          *DeployTokensService
-	Deployments           *DeploymentsService
-	Discussions           *DiscussionsService
-	Environments          *EnvironmentsService
-	EpicIssues            *EpicIssuesService
-	Epics                 *EpicsService
-	Events                *EventsService
-	ExternalStatusChecks  *ExternalStatusChecksService
-	Features              *FeaturesService
-	FreezePeriods         *FreezePeriodsService
-	GenericPackages       *GenericPackagesService
-	GeoNodes              *GeoNodesService
-	GitIgnoreTemplates    *GitIgnoreTemplatesService
-	GroupAccessTokens     *GroupAccessTokensService
-	GroupBadges           *GroupBadgesService
-	GroupCluster          *GroupClustersService
-	GroupImportExport     *GroupImportExportService
-	GroupIssueBoards      *GroupIssueBoardsService
-	GroupIterations       *GroupIterationsService
-	GroupLabels           *GroupLabelsService
-	GroupMembers          *GroupMembersService
-	GroupMilestones       *GroupMilestonesService
-	GroupVariables        *GroupVariablesService
-	GroupWikis            *GroupWikisService
-	Groups                *GroupsService
-	InstanceCluster       *InstanceClustersService
-	InstanceVariables     *InstanceVariablesService
-	Invites               *InvitesService
-	IssueLinks            *IssueLinksService
-	Issues                *IssuesService
-	IssuesStatistics      *IssuesStatisticsService
-	Jobs                  *JobsService
-	Keys                  *KeysService
-	Labels                *LabelsService
-	License               *LicenseService
-	LicenseTemplates      *LicenseTemplatesService
-	ManagedLicenses       *ManagedLicensesService
-	Markdown              *MarkdownService
-	MergeRequestApprovals *MergeRequestApprovalsService
-	MergeRequests         *MergeRequestsService
-	Milestones            *MilestonesService
-	Namespaces            *NamespacesService
-	Notes                 *NotesService
-	NotificationSettings  *NotificationSettingsService
-	Packages              *PackagesService
-	Pages                 *PagesService
-	PagesDomains          *PagesDomainsService
-	PersonalAccessTokens  *PersonalAccessTokensService
-	PipelineSchedules     *PipelineSchedulesService
-	PipelineTriggers      *PipelineTriggersService
-	Pipelines             *PipelinesService
-	PlanLimits            *PlanLimitsService
-	ProjectBadges         *ProjectBadgesService
-	ProjectAccessTokens   *ProjectAccessTokensService
-	ProjectCluster        *ProjectClustersService
-	ProjectImportExport   *ProjectImportExportService
-	ProjectIterations     *ProjectIterationsService
-	ProjectMembers        *ProjectMembersService
-	ProjectMirrors        *ProjectMirrorService
-	ProjectSnippets       *ProjectSnippetsService
-	ProjectVariables      *ProjectVariablesService
-	Projects              *ProjectsService
-	ProtectedBranches     *ProtectedBranchesService
-	ProtectedEnvironments *ProtectedEnvironmentsService
-	ProtectedTags         *ProtectedTagsService
-	ReleaseLinks          *ReleaseLinksService
-	Releases              *ReleasesService
-	Repositories          *RepositoriesService
-	RepositoryFiles       *RepositoryFilesService
-	RepositorySubmodules  *RepositorySubmodulesService
-	ResourceLabelEvents   *ResourceLabelEventsService
-	ResourceStateEvents   *ResourceStateEventsService
-	Runners               *RunnersService
-	Search                *SearchService
-	Services              *ServicesService
-	Settings              *SettingsService
-	Sidekiq               *SidekiqService
-	Snippets              *SnippetsService
-	SystemHooks           *SystemHooksService
-	Tags                  *TagsService
-	Todos                 *TodosService
-	Topics                *TopicsService
-	Users                 *UsersService
-	Validate              *ValidateService
-	Version               *VersionService
-	Wikis                 *WikisService
+	AccessRequests         *AccessRequestsService
+	Applications           *ApplicationsService
+	AuditEvents            *AuditEventsService
+	Avatar                 *AvatarRequestsService
+	AwardEmoji             *AwardEmojiService
+	Boards                 *IssueBoardsService
+	Branches               *BranchesService
+	BroadcastMessage       *BroadcastMessagesService
+	CIYMLTemplate          *CIYMLTemplatesService
+	Commits                *CommitsService
+	ContainerRegistry      *ContainerRegistryService
+	CustomAttribute        *CustomAttributesService
+	DeployKeys             *DeployKeysService
+	DeployTokens           *DeployTokensService
+	Deployments            *DeploymentsService
+	Discussions            *DiscussionsService
+	Environments           *EnvironmentsService
+	EpicIssues             *EpicIssuesService
+	Epics                  *EpicsService
+	Events                 *EventsService
+	ExternalStatusChecks   *ExternalStatusChecksService
+	Features               *FeaturesService
+	FreezePeriods          *FreezePeriodsService
+	GenericPackages        *GenericPackagesService
+	GeoNodes               *GeoNodesService
+	GitIgnoreTemplates     *GitIgnoreTemplatesService
+	GroupAccessTokens      *GroupAccessTokensService
+	GroupBadges            *GroupBadgesService
+	GroupCluster           *GroupClustersService
+	GroupImportExport      *GroupImportExportService
+	GroupIssueBoards       *GroupIssueBoardsService
+	GroupIterations        *GroupIterationsService
+	GroupLabels            *GroupLabelsService
+	GroupMembers           *GroupMembersService
+	GroupMilestones        *GroupMilestonesService
+	GroupVariables         *GroupVariablesService
+	GroupWikis             *GroupWikisService
+	Groups                 *GroupsService
+	InstanceCluster        *InstanceClustersService
+	InstanceVariables      *InstanceVariablesService
+	Invites                *InvitesService
+	IssueLinks             *IssueLinksService
+	Issues                 *IssuesService
+	IssuesStatistics       *IssuesStatisticsService
+	Jobs                   *JobsService
+	Keys                   *KeysService
+	Labels                 *LabelsService
+	License                *LicenseService
+	LicenseTemplates       *LicenseTemplatesService
+	ManagedLicenses        *ManagedLicensesService
+	Markdown               *MarkdownService
+	MergeRequestApprovals  *MergeRequestApprovalsService
+	MergeRequests          *MergeRequestsService
+	Milestones             *MilestonesService
+	Namespaces             *NamespacesService
+	Notes                  *NotesService
+	NotificationSettings   *NotificationSettingsService
+	Packages               *PackagesService
+	Pages                  *PagesService
+	PagesDomains           *PagesDomainsService
+	PersonalAccessTokens   *PersonalAccessTokensService
+	PipelineSchedules      *PipelineSchedulesService
+	PipelineTriggers       *PipelineTriggersService
+	Pipelines              *PipelinesService
+	PlanLimits             *PlanLimitsService
+	ProjectBadges          *ProjectBadgesService
+	ProjectAccessTokens    *ProjectAccessTokensService
+	ProjectCluster         *ProjectClustersService
+	ProjectImportExport    *ProjectImportExportService
+	ProjectIterations      *ProjectIterationsService
+	ProjectMembers         *ProjectMembersService
+	ProjectMirrors         *ProjectMirrorService
+	ProjectSnippets        *ProjectSnippetsService
+	ProjectVariables       *ProjectVariablesService
+	ProjectVulnerabilities *ProjectVulnerabilitiesService
+	Projects               *ProjectsService
+	ProtectedBranches      *ProtectedBranchesService
+	ProtectedEnvironments  *ProtectedEnvironmentsService
+	ProtectedTags          *ProtectedTagsService
+	ReleaseLinks           *ReleaseLinksService
+	Releases               *ReleasesService
+	Repositories           *RepositoriesService
+	RepositoryFiles        *RepositoryFilesService
+	RepositorySubmodules   *RepositorySubmodulesService
+	ResourceLabelEvents    *ResourceLabelEventsService
+	ResourceStateEvents    *ResourceStateEventsService
+	Runners                *RunnersService
+	Search                 *SearchService
+	Services               *ServicesService
+	Settings               *SettingsService
+	Sidekiq                *SidekiqService
+	Snippets               *SnippetsService
+	SystemHooks            *SystemHooksService
+	Tags                   *TagsService
+	Todos                  *TodosService
+	Topics                 *TopicsService
+	Users                  *UsersService
+	Validate               *ValidateService
+	Version                *VersionService
+	Wikis                  *WikisService
 }
 
 // ListOptions specifies the optional parameters to various List methods that
@@ -373,6 +374,7 @@ func newClient(options ...ClientOptionFunc) (*Client, error) {
 	c.ProjectMirrors = &ProjectMirrorService{client: c}
 	c.ProjectSnippets = &ProjectSnippetsService{client: c}
 	c.ProjectVariables = &ProjectVariablesService{client: c}
+	c.ProjectVulnerabilities = &ProjectVulnerabilitiesService{client: c}
 	c.Projects = &ProjectsService{client: c}
 	c.ProtectedBranches = &ProtectedBranchesService{client: c}
 	c.ProtectedEnvironments = &ProtectedEnvironmentsService{client: c}
diff --git a/project_vulnerabilities.go b/project_vulnerabilities.go
new file mode 100644
index 0000000..168ee1a
--- /dev/null
+++ b/project_vulnerabilities.go
@@ -0,0 +1,150 @@
+//
+// Copyright 2021, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"net/http"
+	"time"
+)
+
+// ProjectVulnerabilitiesService handles communication with the projects
+// vulnerabilities related methods of the GitLab API.
+//
+// GitLab API docs: https://docs.gitlab.com/ee/api/project_vulnerabilities.html
+type ProjectVulnerabilitiesService struct {
+	client *Client
+}
+
+// Project represents a GitLab project vulnerability.
+//
+// GitLab API docs: https://docs.gitlab.com/ee/api/project_vulnerabilities.html
+type ProjectVulnerability struct {
+	AuthorID                int        `json:"author_id"`
+	Confidence              string     `json:"confidence"`
+	CreatedAt               *time.Time `json:"created_at"`
+	Description             string     `json:"description"`
+	DismissedAt             *time.Time `json:"dismissed_at"`
+	DismissedByID           int        `json:"dismissed_by_id"`
+	DueDate                 *time.Time `json:"due_date"`
+	Finding                 *Finding   `json:"finding"`
+	ID                      int        `json:"id"`
+	LastEditedAt            *time.Time `json:"last_edited_at"`
+	LastEditedByID          int        `json:"last_edited_by_id"`
+	Project                 *Project   `json:"project"`
+	ProjectDefaultBranch    string     `json:"project_default_branch"`
+	ReportType              string     `json:"report_type"`
+	ResolvedAt              *time.Time `json:"resolved_at"`
+	ResolvedByID            int        `json:"resolved_by_id"`
+	ResolvedOnDefaultBranch bool       `json:"resolved_on_default_branch"`
+	Severity                string     `json:"severity"`
+	StartDate               *time.Time `json:"start_date"`
+	State                   string     `json:"state"`
+	Title                   string     `json:"title"`
+	UpdatedAt               *time.Time `json:"updated_at"`
+	UpdatedByID             int        `json:"updated_by_id"`
+}
+
+// Project represents a GitLab project vulnerability finding.
+//
+// GitLab API docs: https://docs.gitlab.com/ee/api/project_vulnerabilities.html
+type Finding struct {
+	Confidence          string     `json:"confidence"`
+	CreatedAt           *time.Time `json:"created_at"`
+	ID                  int        `json:"id"`
+	LocationFingerprint string     `json:"location_fingerprint"`
+	MetadataVersion     string     `json:"metadata_version"`
+	Name                string     `json:"name"`
+	PrimaryIdentifierID int        `json:"primary_identifier_id"`
+	ProjectFingerprint  string     `json:"project_fingerprint"`
+	ProjectID           int        `json:"project_id"`
+	RawMetadata         string     `json:"raw_metadata"`
+	ReportType          string     `json:"report_type"`
+	ScannerID           int        `json:"scanner_id"`
+	Severity            string     `json:"severity"`
+	UpdatedAt           *time.Time `json:"updated_at"`
+	UUID                string     `json:"uuid"`
+	VulnerabilityID     int        `json:"vulnerability_id"`
+}
+
+// ListProjectVulnerabilitiesOptions represents the available
+// ListProjectVulnerabilities() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/project_vulnerabilities.html#list-project-vulnerabilities
+type ListProjectVulnerabilitiesOptions struct {
+	ListOptions
+}
+
+// ListProjectVulnerabilities gets a list of all project vulnerabilities.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/project_vulnerabilities.html#list-project-vulnerabilities
+func (s *ProjectVulnerabilitiesService) ListProjectVulnerabilities(pid interface{}, opt *ListProjectVulnerabilitiesOptions, options ...RequestOptionFunc) ([]*ProjectVulnerability, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/vulnerabilities", PathEscape(project))
+
+	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var p []*ProjectVulnerability
+	resp, err := s.client.Do(req, &p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}
+
+// CreateVulnerabilityOptions represents the available CreateVulnerability()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/project_vulnerabilities.html#new-vulnerability
+type CreateVulnerabilityOptions struct {
+	FindingID *int `url:"finding_id,omitempty" json:"finding_id,omitempty"`
+}
+
+// CreateVulnerability creates a new vulnerability on the selected project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/project_vulnerabilities.html#new-vulnerability
+func (s *ProjectVulnerabilitiesService) CreateVulnerability(pid interface{}, opt *CreateVulnerabilityOptions, options ...RequestOptionFunc) (*ProjectVulnerability, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("projects/%s/vulnerabilities", PathEscape(project))
+
+	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	p := new(ProjectVulnerability)
+	resp, err := s.client.Do(req, p)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return p, resp, err
+}


Test patch:
diff --git a/project_vulnerabilities_test.go b/project_vulnerabilities_test.go
new file mode 100644
index 0000000..19f14be
--- /dev/null
+++ b/project_vulnerabilities_test.go
@@ -0,0 +1,72 @@
+//
+// Copyright 2021, Sander van Harmelen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package gitlab
+
+import (
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+)
+
+func TestListProjectVulnerabilities(t *testing.T) {
+	mux, server, client := setup(t)
+	defer teardown(server)
+
+	mux.HandleFunc("/api/v4/projects/1/vulnerabilities", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, http.MethodGet)
+		fmt.Fprint(w, `[{"id":1},{"id":2}]`)
+	})
+
+	opt := &ListProjectVulnerabilitiesOptions{
+		ListOptions: ListOptions{2, 3},
+	}
+
+	projectVulnerabilities, _, err := client.ProjectVulnerabilities.ListProjectVulnerabilities(1, opt)
+	if err != nil {
+		t.Errorf("ProjectVulnerabilities.ListProjectVulnerabilities returned error: %v", err)
+	}
+
+	want := []*ProjectVulnerability{{ID: 1}, {ID: 2}}
+	if !reflect.DeepEqual(want, projectVulnerabilities) {
+		t.Errorf("ProjectVulnerabilities.ListProjectVulnerabilities returned %+v, want %+v", projectVulnerabilities, want)
+	}
+}
+
+func TestCreateVulnerability(t *testing.T) {
+	mux, server, client := setup(t)
+	defer teardown(server)
+
+	mux.HandleFunc("/api/v4/projects/1/vulnerabilities", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, http.MethodPost)
+		fmt.Fprint(w, `{"id":1}`)
+	})
+
+	opt := &CreateVulnerabilityOptions{
+		FindingID: Int(1),
+	}
+
+	projectVulnerability, _, err := client.ProjectVulnerabilities.CreateVulnerability(1, opt)
+	if err != nil {
+		t.Errorf("ProjectVulnerabilities.CreateVulnerability returned error: %v", err)
+	}
+
+	want := &ProjectVulnerability{ID: 1}
+	if !reflect.DeepEqual(want, projectVulnerability) {
+		t.Errorf("ProjectVulnerabilities.CreateVulnerability returned %+v, want %+v", projectVulnerability, want)
+	}
+}