mirror of https://github.com/goharbor/harbor.git
156 lines
4.0 KiB
Go
156 lines
4.0 KiB
Go
package export
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
|
|
beego_orm "github.com/beego/beego/v2/client/orm"
|
|
|
|
"github.com/goharbor/harbor/src/lib/orm"
|
|
q2 "github.com/goharbor/harbor/src/lib/q"
|
|
)
|
|
|
|
const (
|
|
// This sql template aims to select vuln data from database,
|
|
// which receive one parameter:
|
|
// 1. artifacts id sets
|
|
// consider for performance, the caller will slice the artifact ids to multi
|
|
// groups if it's length over limit, so rowNum offset is designed to ensure the
|
|
// final row id is sequence in the final output csv file.
|
|
VulnScanReportQueryTemplate = `
|
|
select
|
|
artifact.digest as artifact_digest,
|
|
artifact.repository_id,
|
|
artifact.repository_name,
|
|
vulnerability_record.cve_id,
|
|
vulnerability_record.package,
|
|
vulnerability_record.severity,
|
|
vulnerability_record.cwe_ids,
|
|
vulnerability_record.package_version,
|
|
vulnerability_record.fixed_version,
|
|
to_jsonb(vulnerability_record.vendor_attributes) as vendor_attributes,
|
|
scanner_registration."name" as scanner_name
|
|
from
|
|
report_vulnerability_record
|
|
inner join scan_report on report_vulnerability_record.report_uuid = scan_report.uuid
|
|
inner join artifact on scan_report.digest = artifact.digest
|
|
left outer join artifact_reference on artifact.id = artifact_reference.child_id
|
|
inner join vulnerability_record on report_vulnerability_record.vuln_record_id = vulnerability_record.id
|
|
inner join scanner_registration on scan_report.registration_uuid = scanner_registration.uuid
|
|
and artifact.id in (%s)
|
|
|
|
group by
|
|
package,
|
|
vulnerability_record.severity,
|
|
vulnerability_record.cve_id,
|
|
artifact.digest,
|
|
artifact.repository_id,
|
|
artifact.repository_name,
|
|
vulnerability_record.cwe_ids,
|
|
vulnerability_record.package_version,
|
|
vulnerability_record.fixed_version,
|
|
to_jsonb(vulnerability_record.vendor_attributes),
|
|
scanner_registration.id
|
|
`
|
|
JobModeExport = "export"
|
|
JobModeKey = "mode"
|
|
)
|
|
|
|
var (
|
|
Mgr = NewManager()
|
|
)
|
|
|
|
// Params specifies the filters for controlling the scan data export process
|
|
type Params struct {
|
|
// cve ids
|
|
CVEIds string
|
|
|
|
// artifact ids
|
|
ArtifactIDs []int64
|
|
|
|
// PageNumber
|
|
PageNumber int64
|
|
|
|
// PageSize
|
|
PageSize int64
|
|
}
|
|
|
|
// FromJSON parses robot from json data
|
|
func (p *Params) FromJSON(jsonData string) error {
|
|
if len(jsonData) == 0 {
|
|
return errors.New("empty json data to parse")
|
|
}
|
|
|
|
return json.Unmarshal([]byte(jsonData), p)
|
|
}
|
|
|
|
// ToJSON marshals Robot to JSON data
|
|
func (p *Params) ToJSON() (string, error) {
|
|
data, err := json.Marshal(p)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return string(data), nil
|
|
}
|
|
|
|
type Manager interface {
|
|
Fetch(ctx context.Context, params Params) ([]Data, error)
|
|
}
|
|
|
|
type exportManager struct {
|
|
exportDataFilter VulnerabilityDataSelector
|
|
}
|
|
|
|
func NewManager() Manager {
|
|
return &exportManager{exportDataFilter: NewVulnerabilityDataSelector()}
|
|
}
|
|
|
|
func (em *exportManager) Fetch(ctx context.Context, params Params) ([]Data, error) {
|
|
exportData := make([]Data, 0)
|
|
rawSeter, _ := em.buildQuery(ctx, params)
|
|
_, err := rawSeter.QueryRows(&exportData)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
exportData, err = em.exportDataFilter.Select(exportData, CVEIDMatches, params.CVEIds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return exportData, nil
|
|
}
|
|
|
|
func (em *exportManager) buildQuery(ctx context.Context, params Params) (beego_orm.RawSeter, error) {
|
|
artIDs := ""
|
|
for _, artID := range params.ArtifactIDs {
|
|
if len(artIDs) == 0 {
|
|
artIDs += fmt.Sprintf("%d", artID)
|
|
} else {
|
|
artIDs += fmt.Sprintf(",%d", artID)
|
|
}
|
|
}
|
|
|
|
sql := fmt.Sprintf(VulnScanReportQueryTemplate, artIDs)
|
|
ormer, err := orm.FromContext(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pageSize := params.PageSize
|
|
q := &q2.Query{
|
|
Keywords: nil,
|
|
Sorts: nil,
|
|
PageNumber: params.PageNumber,
|
|
PageSize: pageSize,
|
|
Sorting: "",
|
|
}
|
|
paginationParams := make([]interface{}, 0)
|
|
query, pageLimits := orm.PaginationOnRawSQL(q, sql, paginationParams)
|
|
// user can open ORM_DEBUG for log the sql
|
|
return ormer.Raw(query, pageLimits), nil
|
|
}
|