diff --git a/development-kit/pkg/databases/relational/repository/vulnerability/vulnerability.go b/development-kit/pkg/databases/relational/repository/vulnerability/vulnerability.go index fc55d0f39..8d1e989b8 100644 --- a/development-kit/pkg/databases/relational/repository/vulnerability/vulnerability.go +++ b/development-kit/pkg/databases/relational/repository/vulnerability/vulnerability.go @@ -18,6 +18,7 @@ import ( SQL "github.com/ZupIT/horusec/development-kit/pkg/databases/relational" "github.com/ZupIT/horusec/development-kit/pkg/entities/api/dto" "github.com/ZupIT/horusec/development-kit/pkg/entities/horusec" + horusecEnums "github.com/ZupIT/horusec/development-kit/pkg/enums/horusec" "github.com/ZupIT/horusec/development-kit/pkg/enums/severity" "github.com/ZupIT/horusec/development-kit/pkg/utils/pagination" "github.com/google/uuid" @@ -26,7 +27,7 @@ import ( type IRepository interface { ListVulnManagementData(repositoryID uuid.UUID, page, size int, vulnSeverity severity.Severity, - vulnHash string) (vulnManagement dto.VulnManagement, err error) + vulnType horusecEnums.VulnerabilityType, vulnHash string) (vulnManagement dto.VulnManagement, err error) UpdateVulnType(vulnerabilityID uuid.UUID, updateTypeData *dto.UpdateVulnType) (*horusec.Vulnerability, error) GetVulnByID(vulnerabilityID uuid.UUID) (*horusec.Vulnerability, error) @@ -44,25 +45,21 @@ func NewManagementRepository(databaseRead SQL.InterfaceRead, databaseWrite SQL.I } } -func (r *Repository) ListVulnManagementData(repositoryID uuid.UUID, page, size int, - vulnSeverity severity.Severity, vulnHash string) (vulnManagement dto.VulnManagement, err error) { - query := r.databaseRead.GetConnection(). - Select("DISTINCT ON (vulnerabilities.vulnerability_id) vulnerabilities.vulnerability_id," + - " vulnerabilities.type, vulnerabilities.vuln_hash, vulnerabilities.line, vulnerabilities.column," + - " vulnerabilities.confidence, vulnerabilities.file, vulnerabilities.code, vulnerabilities.details," + - " vulnerabilities.security_tool, vulnerabilities.language, vulnerabilities.severity"). - Table("analysis"). - Joins("JOIN analysis_vulnerabilities ON analysis.analysis_id = analysis_vulnerabilities.analysis_id"). - Joins("JOIN vulnerabilities ON vulnerabilities.vulnerability_id = analysis_vulnerabilities.vulnerability_id"). - Limit(size). - Offset(pagination.GetSkip(int64(page), int64(size))) - - vulnManagement.TotalItems = r.getTotalVulnManagementData(repositoryID, vulnSeverity, vulnHash) - return vulnManagement, r.setWhereFilter(query, repositoryID, vulnSeverity, vulnHash).Find(&vulnManagement.Data).Error +func (r *Repository) ListVulnManagementData(repositoryID uuid.UUID, page, size int, vulnSeverity severity.Severity, + vulnType horusecEnums.VulnerabilityType, vulnHash string) (vulnManagement dto.VulnManagement, err error) { + query := r.databaseRead.GetConnection().Raw("SELECT * FROM ? AS tmpTable"+ + " ORDER BY CASE tmpTable.severity"+ + " WHEN 'HIGH' THEN 1 WHEN 'MEDIUM' THEN 2 WHEN 'LOW' THEN 3 WHEN 'AUDIT' THEN 4"+ + " WHEN 'INFO' THEN 5 END, tmpTable.type DESC LIMIT ? OFFSET ?", + r.listVulnManagementDataSubQuery(repositoryID, vulnSeverity, vulnType, vulnHash), + size, pagination.GetSkip(int64(page), int64(size))) + + vulnManagement.TotalItems = r.getTotalVulnManagementData(repositoryID, vulnSeverity, vulnType, vulnHash) + return vulnManagement, query.Find(&vulnManagement.Data).Error } func (r *Repository) getTotalVulnManagementData(repositoryID uuid.UUID, - vulnSeverity severity.Severity, vulnHash string) (count int) { + vulnSeverity severity.Severity, vulnType horusecEnums.VulnerabilityType, vulnHash string) (count int) { query := r.databaseRead. GetConnection(). Select("COUNT( DISTINCT ( vulnerabilities.vulnerability_id ) )"). @@ -70,17 +67,33 @@ func (r *Repository) getTotalVulnManagementData(repositoryID uuid.UUID, Joins("JOIN analysis_vulnerabilities ON analysis.analysis_id = analysis_vulnerabilities.analysis_id"). Joins("JOIN vulnerabilities ON vulnerabilities.vulnerability_id = analysis_vulnerabilities.vulnerability_id") - _ = r.setWhereFilter(query, repositoryID, vulnSeverity, vulnHash).Count(&count) + _ = r.setWhereFilter(query, repositoryID, vulnSeverity, vulnType, vulnHash).Count(&count) return count } -func (r *Repository) setWhereFilter(query *gorm.DB, repositoryID uuid.UUID, - vulnSeverity severity.Severity, vulnHash string) *gorm.DB { +// nolint +func (r *Repository) setWhereFilter(query *gorm.DB, repositoryID uuid.UUID, vulnSeverity severity.Severity, + vulnType horusecEnums.VulnerabilityType, vulnHash string) *gorm.DB { + if vulnHash != "" && vulnSeverity != "" && vulnType != "" { + return query.Where("repository_id = ? AND vulnerabilities.severity = ? AND vulnerabilities.type = ?"+ + " AND vulnerabilities.vuln_hash ~ ?", repositoryID, vulnSeverity, vulnType, vulnHash) + } + if vulnHash != "" && vulnSeverity != "" { return query.Where("repository_id = ? AND vulnerabilities.severity = ? AND vulnerabilities.vuln_hash ~ ?", repositoryID, vulnSeverity, vulnHash) } + if vulnHash != "" && vulnType != "" { + return query.Where("repository_id = ? AND vulnerabilities.type = ? AND vulnerabilities.vuln_hash ~ ?", + repositoryID, vulnType, vulnHash) + } + + if vulnSeverity != "" && vulnType != "" { + return query.Where("repository_id = ? AND vulnerabilities.type = ? AND vulnerabilities.severity = ?", + repositoryID, vulnType, vulnSeverity) + } + if vulnHash != "" { return query.Where("repository_id = ? AND vulnerabilities.vuln_hash ~ ?", repositoryID, vulnHash) } @@ -89,6 +102,10 @@ func (r *Repository) setWhereFilter(query *gorm.DB, repositoryID uuid.UUID, return query.Where("repository_id = ? AND vulnerabilities.severity = ?", repositoryID, vulnSeverity) } + if vulnType != "" { + return query.Where("repository_id = ? AND vulnerabilities.type = ?", repositoryID, vulnType) + } + return query.Where("repository_id = ?", repositoryID) } @@ -112,3 +129,17 @@ func (r *Repository) GetVulnByID(vulnerabilityID uuid.UUID) (*horusec.Vulnerabil return vulnerability, response.GetError() } + +func (r *Repository) listVulnManagementDataSubQuery(repositoryID uuid.UUID, + vulnSeverity severity.Severity, vulnType horusecEnums.VulnerabilityType, vulnHash string) *gorm.SqlExpr { + query := r.databaseRead.GetConnection(). + Select("DISTINCT ON (vulnerabilities.vulnerability_id) vulnerabilities.vulnerability_id," + + " vulnerabilities.type, vulnerabilities.vuln_hash, vulnerabilities.line, vulnerabilities.column," + + " vulnerabilities.confidence, vulnerabilities.file, vulnerabilities.code, vulnerabilities.details," + + " vulnerabilities.security_tool, vulnerabilities.language, vulnerabilities.severity"). + Table("analysis"). + Joins("JOIN analysis_vulnerabilities ON analysis.analysis_id = analysis_vulnerabilities.analysis_id"). + Joins("JOIN vulnerabilities ON vulnerabilities.vulnerability_id = analysis_vulnerabilities.vulnerability_id") + + return r.setWhereFilter(query, repositoryID, vulnSeverity, vulnType, vulnHash).SubQuery() +} diff --git a/development-kit/pkg/databases/relational/repository/vulnerability/vulnerability_mock.go b/development-kit/pkg/databases/relational/repository/vulnerability/vulnerability_mock.go index 2c9981fd8..093585616 100644 --- a/development-kit/pkg/databases/relational/repository/vulnerability/vulnerability_mock.go +++ b/development-kit/pkg/databases/relational/repository/vulnerability/vulnerability_mock.go @@ -17,6 +17,7 @@ package vulnerability import ( "github.com/ZupIT/horusec/development-kit/pkg/entities/api/dto" "github.com/ZupIT/horusec/development-kit/pkg/entities/horusec" + horusecEnums "github.com/ZupIT/horusec/development-kit/pkg/enums/horusec" "github.com/ZupIT/horusec/development-kit/pkg/enums/severity" mockUtils "github.com/ZupIT/horusec/development-kit/pkg/utils/mock" "github.com/google/uuid" @@ -28,7 +29,7 @@ type Mock struct { } func (m *Mock) ListVulnManagementData(repositoryID uuid.UUID, page, size int, vulnSeverity severity.Severity, - vulnHash string) (vulnManagement dto.VulnManagement, err error) { + vulnType horusecEnums.VulnerabilityType, vulnHash string) (vulnManagement dto.VulnManagement, err error) { args := m.MethodCalled("ListVulnManagementData") return args.Get(0).(dto.VulnManagement), mockUtils.ReturnNilOrError(args, 1) } diff --git a/development-kit/pkg/databases/relational/repository/vulnerability/vulnerability_test.go b/development-kit/pkg/databases/relational/repository/vulnerability/vulnerability_test.go index 83d6b4f48..acff0d0f3 100644 --- a/development-kit/pkg/databases/relational/repository/vulnerability/vulnerability_test.go +++ b/development-kit/pkg/databases/relational/repository/vulnerability/vulnerability_test.go @@ -133,7 +133,8 @@ func TestGetAllVulnManagementData(t *testing.T) { t.Run("should return error sqlite do not supports distinct on", func(t *testing.T) { repo := NewManagementRepository(databaseRead, databaseWrite) - result, err := repo.ListVulnManagementData(repository.RepositoryID, 1, 1, "", "") + result, err := repo.ListVulnManagementData(repository.RepositoryID, + 1, 1, "", "", "") assert.Error(t, err) assert.Len(t, result.Data, 0) @@ -142,7 +143,8 @@ func TestGetAllVulnManagementData(t *testing.T) { t.Run("should return error sqlite do not supports distinct on", func(t *testing.T) { repo := NewManagementRepository(databaseRead, databaseWrite) - result, err := repo.ListVulnManagementData(repository.RepositoryID, 1, 1, "test", "") + result, err := repo.ListVulnManagementData(repository.RepositoryID, 1, 1, + "test", "", "") assert.Error(t, err) assert.Len(t, result.Data, 0) @@ -151,7 +153,8 @@ func TestGetAllVulnManagementData(t *testing.T) { t.Run("should success get vulnerability data with no errors", func(t *testing.T) { repo := NewManagementRepository(databaseRead, databaseWrite) - result, err := repo.ListVulnManagementData(repository.RepositoryID, 1, 1, "", "test") + result, err := repo.ListVulnManagementData(repository.RepositoryID, 1, 1, + "", "", "test") assert.Error(t, err) assert.Len(t, result.Data, 0) @@ -160,7 +163,48 @@ func TestGetAllVulnManagementData(t *testing.T) { t.Run("should success get vulnerability data with no errors", func(t *testing.T) { repo := NewManagementRepository(databaseRead, databaseWrite) - result, err := repo.ListVulnManagementData(repository.RepositoryID, 1, 1, "test", "test") + result, err := repo.ListVulnManagementData(repository.RepositoryID, 1, 1, + "test", "", "test") + + assert.Error(t, err) + assert.Len(t, result.Data, 0) + }) + + t.Run("should success get vulnerability data with no errors", func(t *testing.T) { + repo := NewManagementRepository(databaseRead, databaseWrite) + + result, err := repo.ListVulnManagementData(repository.RepositoryID, 1, 1, + "test", "test", "test") + + assert.Error(t, err) + assert.Len(t, result.Data, 0) + }) + + t.Run("should success get vulnerability data with no errors", func(t *testing.T) { + repo := NewManagementRepository(databaseRead, databaseWrite) + + result, err := repo.ListVulnManagementData(repository.RepositoryID, 1, 1, + "", "test", "test") + + assert.Error(t, err) + assert.Len(t, result.Data, 0) + }) + + t.Run("should success get vulnerability data with no errors", func(t *testing.T) { + repo := NewManagementRepository(databaseRead, databaseWrite) + + result, err := repo.ListVulnManagementData(repository.RepositoryID, 1, 1, + "test", "test", "") + + assert.Error(t, err) + assert.Len(t, result.Data, 0) + }) + + t.Run("should success get vulnerability data with no errors", func(t *testing.T) { + repo := NewManagementRepository(databaseRead, databaseWrite) + + result, err := repo.ListVulnManagementData(repository.RepositoryID, 1, 1, + "", "test", "") assert.Error(t, err) assert.Len(t, result.Data, 0) diff --git a/horusec-api/docs/docs.go b/horusec-api/docs/docs.go index b40f0eeba..e0d7bab0d 100644 --- a/horusec-api/docs/docs.go +++ b/horusec-api/docs/docs.go @@ -327,6 +327,12 @@ var doc = `{ "description": "vulnType query string", "name": "vulnType", "in": "query" + }, + { + "type": "string", + "description": "vulnSeverity query string", + "name": "vulnSeverity", + "in": "query" } ], "responses": { diff --git a/horusec-api/docs/swagger.json b/horusec-api/docs/swagger.json index 9b61bebb2..fb648c6a8 100644 --- a/horusec-api/docs/swagger.json +++ b/horusec-api/docs/swagger.json @@ -295,6 +295,12 @@ "description": "vulnType query string", "name": "vulnType", "in": "query" + }, + { + "type": "string", + "description": "vulnSeverity query string", + "name": "vulnSeverity", + "in": "query" } ], "responses": { diff --git a/horusec-api/docs/swagger.yaml b/horusec-api/docs/swagger.yaml index 23c9584f6..ede9941ed 100644 --- a/horusec-api/docs/swagger.yaml +++ b/horusec-api/docs/swagger.yaml @@ -264,6 +264,10 @@ paths: in: query name: vulnType type: string + - description: vulnSeverity query string + in: query + name: vulnSeverity + type: string produces: - application/json responses: diff --git a/horusec-api/internal/controllers/management/management.go b/horusec-api/internal/controllers/management/management.go index dc64a63bc..8e34f9e1f 100644 --- a/horusec-api/internal/controllers/management/management.go +++ b/horusec-api/internal/controllers/management/management.go @@ -19,13 +19,14 @@ import ( "github.com/ZupIT/horusec/development-kit/pkg/databases/relational/repository/vulnerability" "github.com/ZupIT/horusec/development-kit/pkg/entities/api/dto" "github.com/ZupIT/horusec/development-kit/pkg/entities/horusec" + horusecEnums "github.com/ZupIT/horusec/development-kit/pkg/enums/horusec" "github.com/ZupIT/horusec/development-kit/pkg/enums/severity" "github.com/google/uuid" ) type IController interface { ListVulnManagementData(repositoryID uuid.UUID, page, size int, vulnSeverity severity.Severity, - vulnHash string) (vulnManagement dto.VulnManagement, err error) + vulnType horusecEnums.VulnerabilityType, vulnHash string) (vulnManagement dto.VulnManagement, err error) UpdateVulnType(vulnerabilityID uuid.UUID, vulnType *dto.UpdateVulnType) (*horusec.Vulnerability, error) } @@ -40,9 +41,9 @@ func NewManagementController(postgresRead relational.InterfaceRead, } } -func (c *Controller) ListVulnManagementData(repositoryID uuid.UUID, page, size int, - vulnSeverity severity.Severity, vulnHash string) (vulnManagement dto.VulnManagement, err error) { - return c.managementRepository.ListVulnManagementData(repositoryID, page, size, vulnSeverity, vulnHash) +func (c *Controller) ListVulnManagementData(repositoryID uuid.UUID, page, size int, vulnSeverity severity.Severity, + vulnType horusecEnums.VulnerabilityType, vulnHash string) (vulnManagement dto.VulnManagement, err error) { + return c.managementRepository.ListVulnManagementData(repositoryID, page, size, vulnSeverity, vulnType, vulnHash) } func (c *Controller) UpdateVulnType(vulnerabilityID uuid.UUID, diff --git a/horusec-api/internal/controllers/management/management_mock.go b/horusec-api/internal/controllers/management/management_mock.go index ba7d0bcd0..026a87b7c 100644 --- a/horusec-api/internal/controllers/management/management_mock.go +++ b/horusec-api/internal/controllers/management/management_mock.go @@ -17,6 +17,7 @@ package management import ( "github.com/ZupIT/horusec/development-kit/pkg/entities/api/dto" "github.com/ZupIT/horusec/development-kit/pkg/entities/horusec" + horusecEnums "github.com/ZupIT/horusec/development-kit/pkg/enums/horusec" "github.com/ZupIT/horusec/development-kit/pkg/enums/severity" mockUtils "github.com/ZupIT/horusec/development-kit/pkg/utils/mock" "github.com/google/uuid" @@ -28,7 +29,7 @@ type Mock struct { } func (m *Mock) ListVulnManagementData(repositoryID uuid.UUID, page, size int, vulnSeverity severity.Severity, - vulnHash string) (vulnManagement dto.VulnManagement, err error) { + vulnType horusecEnums.VulnerabilityType, vulnHash string) (vulnManagement dto.VulnManagement, err error) { args := m.MethodCalled("ListVulnManagementData") return args.Get(0).(dto.VulnManagement), mockUtils.ReturnNilOrError(args, 1) } diff --git a/horusec-api/internal/controllers/management/management_test.go b/horusec-api/internal/controllers/management/management_test.go index 55b90cce2..41c977c03 100644 --- a/horusec-api/internal/controllers/management/management_test.go +++ b/horusec-api/internal/controllers/management/management_test.go @@ -50,7 +50,8 @@ func TestListVulnManagementData(t *testing.T) { controller := Controller{managementRepository: repositoryMock} - result, err := controller.ListVulnManagementData(uuid.New(), 1, 10, "", "") + result, err := controller.ListVulnManagementData(uuid.New(), 1, 10, + "", "", "") assert.NoError(t, err) assert.Equal(t, 1, result.TotalItems) assert.Len(t, result.Data, 1) diff --git a/horusec-api/internal/handlers/management/management.go b/horusec-api/internal/handlers/management/management.go index 3729be0bf..21a4b5c5d 100644 --- a/horusec-api/internal/handlers/management/management.go +++ b/horusec-api/internal/handlers/management/management.go @@ -18,6 +18,7 @@ import ( "github.com/ZupIT/horusec/development-kit/pkg/databases/relational" _ "github.com/ZupIT/horusec/development-kit/pkg/entities/api/dto" // [swagger-import] "github.com/ZupIT/horusec/development-kit/pkg/enums/errors" + horusecEnums "github.com/ZupIT/horusec/development-kit/pkg/enums/horusec" "github.com/ZupIT/horusec/development-kit/pkg/enums/severity" managementUseCases "github.com/ZupIT/horusec/development-kit/pkg/usecases/management" httpUtil "github.com/ZupIT/horusec/development-kit/pkg/utils/http" @@ -55,6 +56,7 @@ func (h *Handler) Options(w netHTTP.ResponseWriter, _ *netHTTP.Request) { // @Param size query string false "size query string" // @Param vulnHash query string false "vulnHash query string" // @Param vulnType query string false "vulnType query string" +// @Param vulnSeverity query string false "vulnSeverity query string" // @Success 200 {object} http.Response{content=string} "OK" // @Failure 400 {object} http.Response{content=string} "BAD REQUEST" // @Failure 500 {object} http.Response{content=string} "INTERNAL SERVER ERROR" @@ -68,7 +70,7 @@ func (h *Handler) Get(w netHTTP.ResponseWriter, r *netHTTP.Request) { page, size := h.getPageSize(r) result, err := h.managementController.ListVulnManagementData(repositoryID, page, size, - h.getVulnSeverity(r), h.getVulnHash(r)) + h.getVulnSeverity(r), h.getVulnType(r), h.getVulnHash(r)) if err != nil { httpUtil.StatusInternalServerError(w, err) return @@ -87,6 +89,10 @@ func (h *Handler) getVulnSeverity(r *netHTTP.Request) severity.Severity { return severity.Severity(r.URL.Query().Get("vulnSeverity")) } +func (h *Handler) getVulnType(r *netHTTP.Request) horusecEnums.VulnerabilityType { + return horusecEnums.VulnerabilityType(r.URL.Query().Get("vulnType")) +} + func (h *Handler) getVulnHash(r *netHTTP.Request) string { return r.URL.Query().Get("vulnHash") }