mirror of
https://github.com/anchore/grype
synced 2024-11-10 06:34:13 +00:00
remove desc
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
parent
7c9090a6be
commit
a8947447b3
4 changed files with 369 additions and 180 deletions
|
@ -3,10 +3,46 @@ package v6
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/OneOfOne/xxhash"
|
"github.com/OneOfOne/xxhash"
|
||||||
|
"github.com/anchore/grype/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BlobDigest(content string) string {
|
func BlobDigest(content string) string {
|
||||||
h := xxhash.New64()
|
h := xxhash.New64()
|
||||||
h.Write([]byte(content)) // TODO: handle error?
|
h.Write([]byte(content)) // TODO: handle error?
|
||||||
return fmt.Sprintf("xx64:%x", h.Sum(nil))
|
return fmt.Sprintf("%x", h.Sum(nil)) // by the size we can surmise that this is a xxh64 hash
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlobStore interface {
|
||||||
|
AddBlobs(blobs ...*Blob) error
|
||||||
|
GetBlob(digest string) (*Blob, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type blobStore struct {
|
||||||
|
*StoreConfig
|
||||||
|
*state
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBlobStore(cfg *StoreConfig) BlobStore {
|
||||||
|
return &blobStore{
|
||||||
|
StoreConfig: cfg,
|
||||||
|
state: cfg.state(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobStore) GetBlob(digest string) (*Blob, error) {
|
||||||
|
log.WithFields("digest", digest).Trace("fetching Blob record")
|
||||||
|
|
||||||
|
var model Blob
|
||||||
|
|
||||||
|
result := s.db.Where("digest = ?", digest).Find(&model)
|
||||||
|
return &model, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *blobStore) AddBlobs(blobs ...*Blob) error {
|
||||||
|
for _, b := range blobs {
|
||||||
|
if err := s.db.FirstOrCreate(b).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,36 +2,47 @@ package v6
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"gorm.io/datatypes"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func All() []any {
|
func All() []any {
|
||||||
return []any{
|
return []any{
|
||||||
&CpeWithoutVersion{},
|
&Cpe{},
|
||||||
|
&PlatformCpe{},
|
||||||
&Digest{},
|
&Digest{},
|
||||||
&Affected{},
|
|
||||||
&Alias{},
|
&Alias{},
|
||||||
&Blob{},
|
&Blob{},
|
||||||
&DbMetadata{},
|
&DbMetadata{},
|
||||||
&DbSpecificNvd{},
|
//&DbSpecificNvd{},
|
||||||
&Epss{},
|
&Epss{},
|
||||||
&KnownExploitedVulnerability{},
|
&KnownExploitedVulnerability{},
|
||||||
&OperatingSystem{},
|
&OperatingSystem{},
|
||||||
&Provider{},
|
&Provider{},
|
||||||
&Reference{},
|
&Reference{},
|
||||||
&Severity{},
|
&Severity{},
|
||||||
|
&Affected{},
|
||||||
&Vulnerability{},
|
&Vulnerability{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// core vulnerability types
|
// core vulnerability types
|
||||||
|
|
||||||
type Advisory struct {
|
// TODO: this will probably be shipped as another DB and attached on as-needed basis
|
||||||
ID string
|
type Blob struct {
|
||||||
|
Digest string `gorm:"column:digest;primaryKey"`
|
||||||
|
Value string `gorm:"column:value;not null"`
|
||||||
|
}
|
||||||
|
|
||||||
VulnerabilityIDs []string
|
func (b *Blob) BeforeCreate(tx *gorm.DB) (err error) {
|
||||||
|
// if the name, major version, and minor version already exist in the table then we should not insert a new record
|
||||||
|
var existing Blob
|
||||||
|
result := tx.Where("digest = ?", b.Digest).First(&existing)
|
||||||
|
if result.Error == nil {
|
||||||
|
// if the record already exists, then we should use the existing record
|
||||||
|
*b = existing
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vulnerability represents the core advisory record for a single known vulnerability from a specific provider. There
|
// Vulnerability represents the core advisory record for a single known vulnerability from a specific provider. There
|
||||||
|
@ -62,8 +73,10 @@ type Vulnerability struct {
|
||||||
|
|
||||||
Status string `gorm:"column:status"` // example: "active, withdrawn, rejected, ..." could be an enum
|
Status string `gorm:"column:status"` // example: "active, withdrawn, rejected, ..." could be an enum
|
||||||
|
|
||||||
Summary string `gorm:"column:summary"`
|
//Summary string `gorm:"column:summary"`
|
||||||
Detail string `gorm:"column:detail;index,unique"`
|
//Detail string `gorm:"column:detail;index,unique"`
|
||||||
|
DetailDigest string `gorm:"column:detail_digest;index,unique"`
|
||||||
|
//Detail *Blob `gorm:"foreignKey:DetailDigest"`
|
||||||
|
|
||||||
// References are URLs to external resources that provide more information about the vulnerability (mirrors the OSV field)
|
// References are URLs to external resources that provide more information about the vulnerability (mirrors the OSV field)
|
||||||
References *[]Reference `gorm:"foreignKey:VulnerabilityID"`
|
References *[]Reference `gorm:"foreignKey:VulnerabilityID"`
|
||||||
|
@ -75,10 +88,10 @@ type Vulnerability struct {
|
||||||
Aliases *[]Alias `gorm:"many2many:vulnerability_aliases"`
|
Aliases *[]Alias `gorm:"many2many:vulnerability_aliases"`
|
||||||
|
|
||||||
// Severities is a list of severity indications (quantitative or qualitative) for the vulnerability (mirrors the OSV field, but the semantics are different. We allow for qualitative string severity, where OSV does not)
|
// Severities is a list of severity indications (quantitative or qualitative) for the vulnerability (mirrors the OSV field, but the semantics are different. We allow for qualitative string severity, where OSV does not)
|
||||||
Severities *datatypes.JSONSlice[Severity] `gorm:"column:severities"`
|
Severities *[]Severity `gorm:"many2many:vulnerability_severities"`
|
||||||
|
|
||||||
// DB specific info
|
// DB specific info
|
||||||
DbSpecific *datatypes.JSON `gorm:"column:db_specific"`
|
//DbSpecific *datatypes.JSON `gorm:"many2many:vulnerability_db_specific"`
|
||||||
|
|
||||||
// Affected is a list of affected entries related to this vulnerability
|
// Affected is a list of affected entries related to this vulnerability
|
||||||
Affected *[]Affected `gorm:"foreignKey:VulnerabilityID"`
|
Affected *[]Affected `gorm:"foreignKey:VulnerabilityID"`
|
||||||
|
@ -86,6 +99,36 @@ type Vulnerability struct {
|
||||||
batchWriteAffected *[]Affected `gorm:"-"`
|
batchWriteAffected *[]Affected `gorm:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Vulnerability) BeforeSave(tx *gorm.DB) (err error) {
|
||||||
|
if a.Severities != nil {
|
||||||
|
uniqueSevs, err := a.uniqueSevs(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.Severities = uniqueSevs
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Vulnerability) uniqueSevs(tx *gorm.DB) (*[]Severity, error) {
|
||||||
|
var uniqueSevs []Severity
|
||||||
|
for _, sev := range *a.Severities {
|
||||||
|
var existing Severity
|
||||||
|
result := tx.Where("type = ? AND score = ? AND source = ? AND rank = ?", sev.Type, sev.Score, sev.Source, sev.Rank).First(&existing)
|
||||||
|
if result.Error == nil {
|
||||||
|
uniqueSevs = append(uniqueSevs, existing)
|
||||||
|
} else {
|
||||||
|
err := tx.Create(&sev).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
uniqueSevs = append(uniqueSevs, sev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &uniqueSevs, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Vulnerability) BeforeCreate(tx *gorm.DB) error {
|
func (c *Vulnerability) BeforeCreate(tx *gorm.DB) error {
|
||||||
// if the len of Affected is > 500, then create those in batches and then attach those to the Vulnerability
|
// if the len of Affected is > 500, then create those in batches and then attach those to the Vulnerability
|
||||||
if c.Affected != nil && len(*c.Affected) > 500 {
|
if c.Affected != nil && len(*c.Affected) > 500 {
|
||||||
|
@ -181,18 +224,29 @@ type Severity struct {
|
||||||
ID int64 `gorm:"column:id;primaryKey"`
|
ID int64 `gorm:"column:id;primaryKey"`
|
||||||
|
|
||||||
// Type describes the quantitative method used to determine the Score, such as "CVSS_V3". Alternatively this makes claim that Score is qualitative, such as just simply "string"
|
// Type describes the quantitative method used to determine the Score, such as "CVSS_V3". Alternatively this makes claim that Score is qualitative, such as just simply "string"
|
||||||
Type string `gorm:"column:type;not null"`
|
Type string `gorm:"column:type;index:idx_severity,unique"`
|
||||||
|
|
||||||
// Score is the quantitative or qualitative severity score (e.g. "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N" or "high")
|
// Score is the quantitative or qualitative severity score (e.g. "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N" or "high")
|
||||||
Score string `gorm:"column:score;not null"`
|
Score string `gorm:"column:score;not null;index:idx_severity,unique"`
|
||||||
|
|
||||||
// Source is the name of the source of the severity score (e.g. "nvd@nist.gov" or "security-advisories@github.com")
|
// Source is the name of the source of the severity score (e.g. "nvd@nist.gov" or "security-advisories@github.com")
|
||||||
Source string `gorm:"column:source"`
|
Source string `gorm:"column:source;index:idx_severity,unique"`
|
||||||
|
|
||||||
// Rank is a free-form organizational field to convey priority over other severities
|
// Rank is a free-form organizational field to convey priority over other severities
|
||||||
Rank int `gorm:"column:priority"`
|
Rank int `gorm:"column:rank;index:idx_severity,unique"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//func (c *Severity) BeforeCreate(tx *gorm.DB) (err error) {
|
||||||
|
// // if the name, major version, and minor version already exist in the table then we should not insert a new record
|
||||||
|
// var existing Severity
|
||||||
|
// result := tx.Where("type = ? AND score = ? AND source = ? AND rank = ?", c.Type, c.Score, c.Source, c.Rank).First(&existing)
|
||||||
|
// if result.Error == nil {
|
||||||
|
// // if the record already exists, then we should use the existing record
|
||||||
|
// *c = existing
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
//}
|
||||||
|
|
||||||
type Reference struct {
|
type Reference struct {
|
||||||
ID int64 `gorm:"column:id;primaryKey"`
|
ID int64 `gorm:"column:id;primaryKey"`
|
||||||
VulnerabilityID int64 `gorm:"column:vulnerability_id;not null"`
|
VulnerabilityID int64 `gorm:"column:vulnerability_id;not null"`
|
||||||
|
@ -226,24 +280,90 @@ type Affected struct {
|
||||||
|
|
||||||
// package qualifiers
|
// package qualifiers
|
||||||
|
|
||||||
PlatformCpeID *int64 `gorm:"column:platform_cpe_id"`
|
PlatformCpes *[]PlatformCpe `gorm:"many2many:affected_platform_cpes"`
|
||||||
PlatformCpe *CpeWithoutVersion `gorm:"foreignKey:PlatformCpeID"`
|
|
||||||
|
|
||||||
RpmModularity string `gorm:"column:rpm_modularity"`
|
RpmModularity string `gorm:"column:rpm_modularity"`
|
||||||
|
|
||||||
// identifiers
|
// identifiers
|
||||||
|
|
||||||
Package *Package `gorm:"embedded;embeddedPrefix:package_"`
|
Package *Package `gorm:"embedded;embeddedPrefix:package_"`
|
||||||
Digest *Digest `gorm:"embedded;embeddedPrefix:digest_"`
|
//Digests *[]Digest `gorm:"many2many:affected_digests"`
|
||||||
//Cpe *Cpe `gorm:"embedded;embeddedPrefix:cpe_"`
|
Cpes *[]Cpe `gorm:"many2many:affected_cpes"`
|
||||||
CpeID *int64 `gorm:"column:cpe_id"`
|
|
||||||
Cpe *CpeWithoutVersion `gorm:"foreignKey:CpeID"`
|
|
||||||
|
|
||||||
// fix
|
// fix
|
||||||
|
|
||||||
Fix *Fix `gorm:"embedded;embeddedPrefix:fix_"`
|
Fix *Fix `gorm:"embedded;embeddedPrefix:fix_"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Affected) BeforeSave(tx *gorm.DB) (err error) {
|
||||||
|
if a.Cpes != nil {
|
||||||
|
uniqueCpes, err := a.uniqueCpes(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.Cpes = uniqueCpes
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.PlatformCpes != nil {
|
||||||
|
uniqueCpes, err := a.uniquePlatformCpes(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.PlatformCpes = uniqueCpes
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.OperatingSystem != nil {
|
||||||
|
result := tx.Where("name = ? AND major_version = ? AND minor_version = ?", a.OperatingSystem.Name, a.OperatingSystem.MajorVersion, a.OperatingSystem.MinorVersion).First(&a.OperatingSystem)
|
||||||
|
if result.Error != nil {
|
||||||
|
err := tx.Create(&a.OperatingSystem).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Affected) uniquePlatformCpes(tx *gorm.DB) (*[]PlatformCpe, error) {
|
||||||
|
var uniqueCpes []PlatformCpe
|
||||||
|
for _, cpe := range *a.PlatformCpes {
|
||||||
|
var existing PlatformCpe
|
||||||
|
result := tx.Where("type = ? AND vendor = ? AND product = ? AND edition = ? AND language = ? AND version = ? AND version_update = ? AND software_edition = ? AND target_hardware = ? AND target_software = ? AND other = ?",
|
||||||
|
cpe.Type, cpe.Vendor, cpe.Product, cpe.Edition, cpe.Language, cpe.Version, cpe.VersionUpdate, cpe.SoftwareEdition, cpe.TargetHardware, cpe.TargetSoftware, cpe.Other).First(&existing)
|
||||||
|
if result.Error == nil {
|
||||||
|
uniqueCpes = append(uniqueCpes, existing)
|
||||||
|
} else {
|
||||||
|
err := tx.Create(&cpe).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
uniqueCpes = append(uniqueCpes, cpe)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &uniqueCpes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Affected) uniqueCpes(tx *gorm.DB) (*[]Cpe, error) {
|
||||||
|
var uniqueCpes []Cpe
|
||||||
|
for _, cpe := range *a.Cpes {
|
||||||
|
var existing Cpe
|
||||||
|
result := tx.Where("type = ? AND vendor = ? AND product = ? AND edition = ? AND language = ? AND software_edition = ? AND target_hardware = ? AND target_software = ? AND other = ?",
|
||||||
|
cpe.Type, cpe.Vendor, cpe.Product, cpe.Edition, cpe.Language, cpe.SoftwareEdition, cpe.TargetHardware, cpe.TargetSoftware, cpe.Other).First(&existing)
|
||||||
|
if result.Error == nil {
|
||||||
|
uniqueCpes = append(uniqueCpes, existing)
|
||||||
|
} else {
|
||||||
|
err := tx.Create(&cpe).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
uniqueCpes = append(uniqueCpes, cpe)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &uniqueCpes, nil
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: add later and reuse existing similar tables with many2many
|
// TODO: add later and reuse existing similar tables with many2many
|
||||||
//type NotAffected struct {
|
//type NotAffected struct {
|
||||||
// ID int64 `gorm:"column:id;primaryKey"`
|
// ID int64 `gorm:"column:id;primaryKey"`
|
||||||
|
@ -257,7 +377,7 @@ type Affected struct {
|
||||||
// Range *[]Range `gorm:"foreignKey:AffectedID"`
|
// Range *[]Range `gorm:"foreignKey:AffectedID"`
|
||||||
//
|
//
|
||||||
// // Digests that are known to correspond to this vulnerability, but cannot be closely associated with a package
|
// // Digests that are known to correspond to this vulnerability, but cannot be closely associated with a package
|
||||||
// Digests *[]Digest `gorm:"many2many:not_affected_digests"`
|
// Digests *[]Digests `gorm:"many2many:not_affected_digests"`
|
||||||
//}
|
//}
|
||||||
|
|
||||||
type Fix struct {
|
type Fix struct {
|
||||||
|
@ -277,7 +397,7 @@ type Fix struct {
|
||||||
|
|
||||||
// primary package identifiers (search entrypoints)
|
// primary package identifiers (search entrypoints)
|
||||||
|
|
||||||
type CpeWithoutVersion struct {
|
type Cpe struct {
|
||||||
// TODO: what about different CPE versions?
|
// TODO: what about different CPE versions?
|
||||||
ID int64 `gorm:"primaryKey"`
|
ID int64 `gorm:"primaryKey"`
|
||||||
|
|
||||||
|
@ -292,14 +412,46 @@ type CpeWithoutVersion struct {
|
||||||
Other string `gorm:"column:other;index:idx_cpe,unique"`
|
Other string `gorm:"column:other;index:idx_cpe,unique"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c CpeWithoutVersion) String() string {
|
func (c Cpe) String() string {
|
||||||
return fmt.Sprintf("%s:%s:%s:%s:%s:%s:%s:%s:%s", c.Type, c.Vendor, c.Product, c.Edition, c.Language, c.SoftwareEdition, c.TargetHardware, c.TargetSoftware, c.Other)
|
return fmt.Sprintf("%s:%s:%s:%s:%s:%s:%s:%s:%s", c.Type, c.Vendor, c.Product, c.Edition, c.Language, c.SoftwareEdition, c.TargetHardware, c.TargetSoftware, c.Other)
|
||||||
}
|
}
|
||||||
|
|
||||||
//func (c *Cpe) BeforeCreate(tx *gorm.DB) (err error) {
|
//func (c *Cpe) BeforeCreate(tx *gorm.DB) (err error) {
|
||||||
// // if the name, major version, and minor version already exist in the table then we should not insert a new record
|
// // if the name, major version, and minor version already exist in the table then we should not insert a new record
|
||||||
// var existing Cpe
|
// var existing Cpe
|
||||||
// result := tx.Where("schema = ? AND type = ? AND vendor = ? AND product = ? AND version = ? AND version_update = ? AND target_software = ?", c.Schema, c.Type, c.Vendor, c.Product, c.Version, c.Update, c.TargetSoftware).First(&existing)
|
// result := tx.Where("type = ? AND vendor = ? AND product = ? AND edition = ? AND language = ? AND software_edition = ? AND target_hardware = ? AND target_software = ? AND other = ?", c.Type, c.Vendor, c.Product, c.Edition, c.Language, c.SoftwareEdition, c.TargetHardware, c.TargetSoftware, c.Other).First(&existing)
|
||||||
|
// if result.Error == nil {
|
||||||
|
// // if the record already exists, then we should use the existing record
|
||||||
|
// *c = existing
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
//}
|
||||||
|
|
||||||
|
type PlatformCpe struct {
|
||||||
|
// TODO: what about different CPE versions?
|
||||||
|
ID int64 `gorm:"primaryKey"`
|
||||||
|
|
||||||
|
Type string `gorm:"column:type;not null;index:idx_platform_cpe,unique"`
|
||||||
|
Vendor string `gorm:"column:vendor;index:idx_platform_cpe,unique"`
|
||||||
|
Product string `gorm:"column:product;not null;index:idx_platform_cpe,unique"`
|
||||||
|
Edition string `gorm:"column:edition;index:idx_platform_cpe,unique"`
|
||||||
|
Language string `gorm:"column:language;index:idx_platform_cpe,unique"`
|
||||||
|
Version string `gorm:"column:version;index:idx_platform_cpe,unique"`
|
||||||
|
VersionUpdate string `gorm:"column:version_update;index:idx_platform_cpe,unique"`
|
||||||
|
SoftwareEdition string `gorm:"column:software_edition;index:idx_platform_cpe,unique"`
|
||||||
|
TargetHardware string `gorm:"column:target_hardware;index:idx_platform_cpe,unique"`
|
||||||
|
TargetSoftware string `gorm:"column:target_software;index:idx_platform_cpe,unique"`
|
||||||
|
Other string `gorm:"column:other;index:idx_platform_cpe,unique"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c PlatformCpe) String() string {
|
||||||
|
return fmt.Sprintf("%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s", c.Type, c.Vendor, c.Product, c.Edition, c.Language, c.Version, c.VersionUpdate, c.SoftwareEdition, c.TargetHardware, c.TargetSoftware, c.Other)
|
||||||
|
}
|
||||||
|
|
||||||
|
//func (c *PlatformCpe) BeforeCreate(tx *gorm.DB) (err error) {
|
||||||
|
// // if the name, major version, and minor version already exist in the table then we should not insert a new record
|
||||||
|
// var existing PlatformCpe
|
||||||
|
// result := tx.Where("type = ? AND vendor = ? AND product = ? AND edition = ? AND language = ? AND version = ? AND version_update = ? AND software_edition = ? AND target_hardware = ? AND target_software = ? AND other = ?", c.Type, c.Vendor, c.Product, c.Edition, c.Language, c.Version, c.VersionUpdate, c.SoftwareEdition, c.TargetHardware, c.TargetSoftware, c.Other).First(&existing)
|
||||||
// if result.Error == nil {
|
// if result.Error == nil {
|
||||||
// // if the record already exists, then we should use the existing record
|
// // if the record already exists, then we should use the existing record
|
||||||
// *c = existing
|
// *c = existing
|
||||||
|
@ -324,7 +476,7 @@ type Package struct {
|
||||||
//OperatingSystem *OperatingSystem `gorm:"foreignKey:OperatingSystemID"`
|
//OperatingSystem *OperatingSystem `gorm:"foreignKey:OperatingSystemID"`
|
||||||
//
|
//
|
||||||
//Purls *[]Purl `gorm:"many2many:package_purls"`
|
//Purls *[]Purl `gorm:"many2many:package_purls"`
|
||||||
//Cpes *[]Cpe `gorm:"many2many:package_cpes"`
|
//Cpes *[]Cpes `gorm:"many2many:package_cpes"`
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,12 +540,6 @@ type DbMetadata struct {
|
||||||
Addition int `gorm:"column:addition;not null"`
|
Addition int `gorm:"column:addition;not null"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this will probably be shipped as another DB and attached on as-needed basis
|
|
||||||
type Blob struct {
|
|
||||||
Digest string `gorm:"column:digest;primaryKey"`
|
|
||||||
Value string `gorm:"column:value;not null"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: not clear that we need this...
|
// TODO: not clear that we need this...
|
||||||
//type Comment struct {
|
//type Comment struct {
|
||||||
// ID int64 `gorm:"column:id;primaryKey"`
|
// ID int64 `gorm:"column:id;primaryKey"`
|
||||||
|
|
|
@ -24,6 +24,7 @@ type Store interface {
|
||||||
AffectedPackageStore
|
AffectedPackageStore
|
||||||
ProviderStore
|
ProviderStore
|
||||||
OperatingSystemStore
|
OperatingSystemStore
|
||||||
|
BlobStore
|
||||||
io.Closer
|
io.Closer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +37,7 @@ type store struct {
|
||||||
AffectedPackageStore
|
AffectedPackageStore
|
||||||
ProviderStore
|
ProviderStore
|
||||||
OperatingSystemStore
|
OperatingSystemStore
|
||||||
|
BlobStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StoreConfig) state() *state {
|
func (c *StoreConfig) state() *state {
|
||||||
|
@ -63,6 +65,7 @@ func New(cfg StoreConfig) (Store, error) {
|
||||||
AffectedStore: NewAffectedStore(&cfg),
|
AffectedStore: NewAffectedStore(&cfg),
|
||||||
VulnerabilityStore: NewVulnerabilityStore(&cfg),
|
VulnerabilityStore: NewVulnerabilityStore(&cfg),
|
||||||
AffectedPackageStore: NewAffectedPackageStore(&cfg),
|
AffectedPackageStore: NewAffectedPackageStore(&cfg),
|
||||||
|
BlobStore: NewBlobStore(&cfg),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package v6
|
package v6
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/anchore/grype/internal/log"
|
"github.com/anchore/grype/internal/log"
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type VulnerabilityStore interface {
|
type VulnerabilityStore interface {
|
||||||
|
@ -42,9 +40,9 @@ func (s *vulnerabilityStore) GetVulnerability(id string, loadAuxInfo bool) ([]Vu
|
||||||
|
|
||||||
func (s *vulnerabilityStore) AddVulnerabilities(vulnerabilities ...*Vulnerability) error {
|
func (s *vulnerabilityStore) AddVulnerabilities(vulnerabilities ...*Vulnerability) error {
|
||||||
for _, h := range []func([]*Vulnerability) error{
|
for _, h := range []func([]*Vulnerability) error{
|
||||||
s.handleOSs,
|
//s.handleOSs,
|
||||||
//s.handleRangeEvents,
|
//s.handleRangeEvents,
|
||||||
s.handleCPEs,
|
//s.handleCPEs,
|
||||||
//s.handlePackages,
|
//s.handlePackages,
|
||||||
} {
|
} {
|
||||||
if err := h(vulnerabilities); err != nil {
|
if err := h(vulnerabilities); err != nil {
|
||||||
|
@ -53,7 +51,13 @@ func (s *vulnerabilityStore) AddVulnerabilities(vulnerabilities ...*Vulnerabilit
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.db.CreateInBatches(vulnerabilities, s.BatchSize).Error
|
for _, v := range vulnerabilities {
|
||||||
|
if err := s.db.Create(v).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//func (s *vulnerabilityStore) handlePackages(vulns []*Vulnerability) error {
|
//func (s *vulnerabilityStore) handlePackages(vulns []*Vulnerability) error {
|
||||||
|
@ -130,83 +134,83 @@ func (s *vulnerabilityStore) AddVulnerabilities(vulnerabilities ...*Vulnerabilit
|
||||||
//
|
//
|
||||||
//}
|
//}
|
||||||
|
|
||||||
func (s *vulnerabilityStore) handleCPEs(vulns []*Vulnerability) error {
|
//func (s *vulnerabilityStore) handleCPEs(vulns []*Vulnerability) error {
|
||||||
// ensure unique cpes
|
// // ensure unique cpes
|
||||||
unique, err := ensureUniqueCPEs(s.db, vulns)
|
// unique, err := ensureUniqueCPEs(s.db, vulns)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// update vulnerabilities with cpes IDs
|
// // update vulnerabilities with cpes IDs
|
||||||
updateAffectedsWithCPEs(vulns, unique)
|
// updateAffectedsWithCPEs(vulns, unique)
|
||||||
|
//
|
||||||
return nil
|
// return nil
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
func updateAffectedsWithCPEs(vulns []*Vulnerability, uniqueCPEs []*CpeWithoutVersion) {
|
//func updateAffectedsWithCPEs(vulns []*Vulnerability, uniqueCPEs []*Cpes) {
|
||||||
cpeMap := make(map[string]int64)
|
// cpeMap := make(map[string]int64)
|
||||||
for _, c := range uniqueCPEs {
|
// for _, c := range uniqueCPEs {
|
||||||
cpeKey := c.String()
|
// cpeKey := c.String()
|
||||||
cpeMap[cpeKey] = c.ID
|
// cpeMap[cpeKey] = c.ID
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
for i, v := range vulns {
|
// for i, v := range vulns {
|
||||||
if v.Affected == nil {
|
// if v.Affected == nil {
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
for j, a := range *v.Affected {
|
// for j, a := range *v.Affected {
|
||||||
if a.Cpe != nil {
|
// if a.Cpes != nil {
|
||||||
cpeKey := a.Cpe.String()
|
// cpeKey := a.Cpes.String()
|
||||||
val := cpeMap[cpeKey]
|
// val := cpeMap[cpeKey]
|
||||||
(*(*vulns[i].Affected)[j].Cpe).ID = val
|
// (*(*vulns[i].Affected)[j].Cpes).ID = val
|
||||||
}
|
// }
|
||||||
if a.PlatformCpe != nil {
|
// if a.PlatformCpes != nil {
|
||||||
cpeKey := a.PlatformCpe.String()
|
// cpeKey := a.PlatformCpes.String()
|
||||||
val := cpeMap[cpeKey]
|
// val := cpeMap[cpeKey]
|
||||||
(*(*vulns[i].Affected)[j].PlatformCpe).ID = val
|
// (*(*vulns[i].Affected)[j].PlatformCpes).ID = val
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
func ensureUniqueCPEs(db *gorm.DB, vulns []*Vulnerability) ([]*CpeWithoutVersion, error) {
|
//func ensureUniqueCPEs(db *gorm.DB, vulns []*Vulnerability) ([]*Cpes, error) {
|
||||||
cpeMap := make(map[string]CpeWithoutVersion)
|
// cpeMap := make(map[string]Cpes)
|
||||||
for _, v := range vulns {
|
// for _, v := range vulns {
|
||||||
if v.Affected == nil {
|
// if v.Affected == nil {
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
for _, a := range *v.Affected {
|
// for _, a := range *v.Affected {
|
||||||
if a.Cpe != nil {
|
// if a.Cpes != nil {
|
||||||
cpeKey := a.Cpe.String()
|
// cpeKey := a.Cpes.String()
|
||||||
cpeMap[cpeKey] = *a.Cpe
|
// cpeMap[cpeKey] = *a.Cpes
|
||||||
}
|
// }
|
||||||
if a.PlatformCpe != nil {
|
// if a.PlatformCpes != nil {
|
||||||
cpeKey := a.PlatformCpe.String()
|
// cpeKey := a.PlatformCpes.String()
|
||||||
cpeMap[cpeKey] = *a.PlatformCpe
|
// cpeMap[cpeKey] = *a.PlatformCpes
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// extract unique CPEs
|
// // extract unique CPEs
|
||||||
var uniqueCPEs []*CpeWithoutVersion
|
// var uniqueCPEs []*Cpes
|
||||||
for i := range cpeMap {
|
// for i := range cpeMap {
|
||||||
c := cpeMap[i]
|
// c := cpeMap[i]
|
||||||
uniqueCPEs = append(uniqueCPEs, &c)
|
// uniqueCPEs = append(uniqueCPEs, &c)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// insert unique CPEs into the database or fetch existing ones
|
// // insert unique CPEs into the database or fetch existing ones
|
||||||
for i, c := range uniqueCPEs {
|
// for i, c := range uniqueCPEs {
|
||||||
var existing CpeWithoutVersion
|
// var existing Cpes
|
||||||
err := db.Where("type = ? AND vendor = ? AND product = ? AND edition = ? AND language = ? AND software_edition = ? AND target_software = ? AND target_hardware = ? AND other = ?", c.Type, c.Vendor, c.Product, c.Edition, c.Language, c.SoftwareEdition, c.TargetSoftware, c.TargetHardware, c.Other).
|
// err := db.Where("type = ? AND vendor = ? AND product = ? AND edition = ? AND language = ? AND software_edition = ? AND target_software = ? AND target_hardware = ? AND other = ?", c.Type, c.Vendor, c.Product, c.Edition, c.Language, c.SoftwareEdition, c.TargetSoftware, c.TargetHardware, c.Other).
|
||||||
FirstOrCreate(&existing, c).Error
|
// FirstOrCreate(&existing, c).Error
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return nil, err
|
// return nil, err
|
||||||
}
|
// }
|
||||||
uniqueCPEs[i] = &existing
|
// uniqueCPEs[i] = &existing
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return uniqueCPEs, nil
|
// return uniqueCPEs, nil
|
||||||
}
|
//}
|
||||||
|
|
||||||
//func (s *vulnerabilityStore) handleRangeEvents(vulns []*Vulnerability) error {
|
//func (s *vulnerabilityStore) handleRangeEvents(vulns []*Vulnerability) error {
|
||||||
// // ensure unique operating systems
|
// // ensure unique operating systems
|
||||||
|
@ -295,67 +299,67 @@ func ensureUniqueCPEs(db *gorm.DB, vulns []*Vulnerability) ([]*CpeWithoutVersion
|
||||||
// return *s
|
// return *s
|
||||||
//}
|
//}
|
||||||
|
|
||||||
func (s *vulnerabilityStore) handleOSs(vulns []*Vulnerability) error {
|
//func (s *vulnerabilityStore) handleOSs(vulns []*Vulnerability) error {
|
||||||
// ensure unique operating systems
|
// // ensure unique operating systems
|
||||||
uniqueOSList, err := ensureUniqueOperatingSystems(s.db, vulns)
|
// uniqueOSList, err := ensureUniqueOperatingSystems(s.db, vulns)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// update vulnerabilities with operating system IDs
|
// // update vulnerabilities with operating system IDs
|
||||||
updateAffectedsWithOperatingSystems(vulns, uniqueOSList)
|
// updateAffectedsWithOperatingSystems(vulns, uniqueOSList)
|
||||||
|
//
|
||||||
return nil
|
// return nil
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
func ensureUniqueOperatingSystems(db *gorm.DB, vulns []*Vulnerability) ([]*OperatingSystem, error) {
|
//func ensureUniqueOperatingSystems(db *gorm.DB, vulns []*Vulnerability) ([]*OperatingSystem, error) {
|
||||||
// map to track unique operating systems
|
// // map to track unique operating systems
|
||||||
osMap := make(map[string]*OperatingSystem)
|
// osMap := make(map[string]*OperatingSystem)
|
||||||
for _, v := range vulns {
|
// for _, v := range vulns {
|
||||||
for _, a := range *v.Affected {
|
// for _, a := range *v.Affected {
|
||||||
if a.OperatingSystem == nil {
|
// if a.OperatingSystem == nil {
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
osKey := fmt.Sprintf("%s:%s:%s", a.OperatingSystem.Name, a.OperatingSystem.MajorVersion, a.OperatingSystem.MinorVersion)
|
// osKey := fmt.Sprintf("%s:%s:%s", a.OperatingSystem.Name, a.OperatingSystem.MajorVersion, a.OperatingSystem.MinorVersion)
|
||||||
osMap[osKey] = a.OperatingSystem
|
// osMap[osKey] = a.OperatingSystem
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// extract unique operating systems
|
// // extract unique operating systems
|
||||||
var uniqueOSList []*OperatingSystem
|
// var uniqueOSList []*OperatingSystem
|
||||||
for _, os := range osMap {
|
// for _, os := range osMap {
|
||||||
uniqueOSList = append(uniqueOSList, os)
|
// uniqueOSList = append(uniqueOSList, os)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// insert unique operating systems into the database or fetch existing ones
|
// // insert unique operating systems into the database or fetch existing ones
|
||||||
for i, os := range uniqueOSList {
|
// for i, os := range uniqueOSList {
|
||||||
var existing OperatingSystem
|
// var existing OperatingSystem
|
||||||
err := db.Where("name = ? AND major_version = ? AND minor_version = ?", os.Name, os.MajorVersion, os.MinorVersion).
|
// err := db.Where("name = ? AND major_version = ? AND minor_version = ?", os.Name, os.MajorVersion, os.MinorVersion).
|
||||||
FirstOrCreate(&existing, os).Error
|
// FirstOrCreate(&existing, os).Error
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return nil, err
|
// return nil, err
|
||||||
}
|
// }
|
||||||
uniqueOSList[i].ID = existing.ID
|
// uniqueOSList[i].ID = existing.ID
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return uniqueOSList, nil
|
// return uniqueOSList, nil
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
func updateAffectedsWithOperatingSystems(vulns []*Vulnerability, uniqueOSList []*OperatingSystem) {
|
//func updateAffectedsWithOperatingSystems(vulns []*Vulnerability, uniqueOSList []*OperatingSystem) {
|
||||||
osMap := make(map[string]int64)
|
// osMap := make(map[string]int64)
|
||||||
for _, os := range uniqueOSList {
|
// for _, os := range uniqueOSList {
|
||||||
osKey := fmt.Sprintf("%s:%s:%s", os.Name, os.MajorVersion, os.MinorVersion)
|
// osKey := fmt.Sprintf("%s:%s:%s", os.Name, os.MajorVersion, os.MinorVersion)
|
||||||
osMap[osKey] = os.ID
|
// osMap[osKey] = os.ID
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
for i, v := range vulns {
|
// for i, v := range vulns {
|
||||||
for j, a := range *v.Affected {
|
// for j, a := range *v.Affected {
|
||||||
if a.OperatingSystem == nil {
|
// if a.OperatingSystem == nil {
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
osKey := fmt.Sprintf("%s:%s:%s", a.OperatingSystem.Name, a.OperatingSystem.MajorVersion, a.OperatingSystem.MinorVersion)
|
// osKey := fmt.Sprintf("%s:%s:%s", a.OperatingSystem.Name, a.OperatingSystem.MajorVersion, a.OperatingSystem.MinorVersion)
|
||||||
val := osMap[osKey]
|
// val := osMap[osKey]
|
||||||
(*vulns[i].Affected)[j].OperatingSystemID = &val
|
// (*vulns[i].Affected)[j].OperatingSystemID = &val
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
Loading…
Reference in a new issue