harbor/src/pkg/scan/report/manager.go

235 lines
6.6 KiB
Go

// Copyright Project Harbor Authors
//
// 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 report
import (
"context"
"github.com/google/uuid"
"github.com/goharbor/harbor/src/lib/errors"
"github.com/goharbor/harbor/src/lib/q"
"github.com/goharbor/harbor/src/pkg/scan/dao/scan"
)
var (
// Mgr is the global report manager
Mgr = NewManager()
)
// Manager is used to manage the scan reports.
type Manager interface {
// Create a new report record.
//
// Arguments:
// ctx context.Context : the context for this method
// r *scan.Report : report model to be created
//
// Returns:
// string : uuid of the new report
// error : non nil error if any errors occurred
//
Create(ctx context.Context, r *scan.Report) (string, error)
// Delete delete report by uuid
//
// Arguments:
// ctx context.Context : the context for this method
// uuid string : uuid of the report to delete
//
// Returns:
// error : non nil error if any errors occurred
//
Delete(ctx context.Context, uuid string) error
// Update the report data (with JSON format) of the given report.
//
// Arguments:
// ctx context.Context : the context for this method
// uuid string : uuid to identify the report
// report string : report JSON data
//
// Returns:
// error : non nil error if any errors occurred
//
UpdateReportData(ctx context.Context, uuid string, report string) error
// Get the reports for the given digest by other properties.
//
// Arguments:
// ctx context.Context : the context for this method
// digest string : digest of the artifact
// registrationUUID string : [optional] the report generated by which registration.
// If it is empty, reports by all the registrations are retrieved.
// mimeTypes []string : [optional] mime types of the reports requiring
// If empty array is specified, reports with all the supported mimes are retrieved.
//
// Returns:
// []*scan.Report : report list
// error : non nil error if any errors occurred
GetBy(ctx context.Context, digest string, registrationUUID string, mimeTypes []string) ([]*scan.Report, error)
// Delete the reports related with the specified digests (one or more...)
//
// Arguments:
// ctx context.Context : the context for this method
// digests ...string : specify one or more digests whose reports will be deleted
//
// Returns:
// error : non nil error if any errors occurred
DeleteByDigests(ctx context.Context, digests ...string) error
// List reports according to the query
//
// Arguments:
// ctx context.Context : the context for this method
// query *q.Query : the query to list the reports
//
// Returns:
// []*scan.Report : report list
// error : non nil error if any errors occurred
List(ctx context.Context, query *q.Query) ([]*scan.Report, error)
// Update update report information
Update(ctx context.Context, r *scan.Report, cols ...string) error
// DeleteByExtraAttr delete scan_report by sbom_digest
DeleteByExtraAttr(ctx context.Context, mimeType, attrName, attrValue string) error
}
// basicManager is a default implementation of report manager.
type basicManager struct {
dao scan.DAO
vulnDao scan.VulnerabilityRecordDao
}
// NewManager news basic manager.
func NewManager() Manager {
return &basicManager{
dao: scan.New(),
vulnDao: scan.NewVulnerabilityRecordDao(),
}
}
// Create ...
func (bm *basicManager) Create(ctx context.Context, r *scan.Report) (string, error) {
// Validate report object
if r == nil {
return "", errors.New("nil scan report object")
}
if len(r.Digest) == 0 || len(r.RegistrationUUID) == 0 || len(r.MimeType) == 0 {
return "", errors.New("malformed scan report object")
}
r.UUID = uuid.New().String()
// Insert
if _, err := bm.dao.Create(ctx, r); err != nil {
return "", err
}
return r.UUID, nil
}
func (bm *basicManager) Delete(ctx context.Context, uuid string) error {
_, err := bm.vulnDao.DeleteForReport(ctx, uuid)
if err != nil {
return err
}
query := q.Query{Keywords: q.KeyWords{"uuid": uuid}}
count, err := bm.dao.DeleteMany(ctx, query)
if err != nil {
return err
}
if count == 0 {
return errors.Errorf("no report with uuid %s deleted", uuid)
}
return nil
}
// GetBy ...
func (bm *basicManager) GetBy(ctx context.Context, digest string, registrationUUID string, mimeTypes []string) ([]*scan.Report, error) {
if len(digest) == 0 {
return nil, errors.New("empty digest to get report data")
}
kws := make(map[string]interface{})
kws["digest"] = digest
if len(registrationUUID) > 0 {
kws["registration_uuid"] = registrationUUID
}
if len(mimeTypes) > 0 {
kws["mime_type__in"] = mimeTypes
}
// Query all
query := &q.Query{
PageNumber: 0,
Keywords: kws,
}
return bm.dao.List(ctx, query)
}
// UpdateReportData ...
func (bm *basicManager) UpdateReportData(ctx context.Context, uuid string, report string) error {
if len(uuid) == 0 {
return errors.New("missing uuid")
}
if len(report) == 0 {
return errors.New("missing report JSON data")
}
return bm.dao.UpdateReportData(ctx, uuid, report)
}
// DeleteByDigests ...
func (bm *basicManager) DeleteByDigests(ctx context.Context, digests ...string) error {
if len(digests) == 0 {
// Nothing to do
return nil
}
// delete the vulnerability records to the report UUID mapping for the digests
// provided
_, err := bm.vulnDao.DeleteForDigests(ctx, digests...)
if err != nil {
return err
}
var ol q.OrList
for _, digest := range digests {
ol.Values = append(ol.Values, digest)
}
query := q.Query{Keywords: q.KeyWords{"digest": &ol}}
_, err = bm.dao.DeleteMany(ctx, query)
return err
}
func (bm *basicManager) List(ctx context.Context, query *q.Query) ([]*scan.Report, error) {
return bm.dao.List(ctx, query)
}
func (bm *basicManager) Update(ctx context.Context, r *scan.Report, cols ...string) error {
return bm.dao.Update(ctx, r, cols...)
}
func (bm *basicManager) DeleteByExtraAttr(ctx context.Context, mimeType, attrName, attrValue string) error {
return bm.dao.DeleteByExtraAttr(ctx, mimeType, attrName, attrValue)
}