mirror of
https://github.com/anchore/grype
synced 2024-09-20 06:21:56 +00:00
modify schema to meet wes-attempt-1
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
parent
536bd2f6af
commit
7c9090a6be
5 changed files with 238 additions and 306 deletions
|
@ -48,7 +48,7 @@ func populateFixture1(store v6.Store) error {
|
|||
{Alias: "CVE-2024-12341"},
|
||||
},
|
||||
Severities: &[]v6.Severity{
|
||||
{Type: "CVSS_V3", Score: "5.0", Source: sp("nvd@nist.gov"), Priority: sp("secondary")},
|
||||
{Type: "CVSS_V3", Score: "5.0", Source: sp("nvd@nist.gov"), Rank: sp("secondary")},
|
||||
},
|
||||
References: &[]v6.Reference{
|
||||
{Type: "ADVISORY", URL: "https://example.com/GHSA-xxxx-xxxx-xxxx1"},
|
||||
|
@ -84,7 +84,7 @@ func populateFixture1(store v6.Store) error {
|
|||
{Alias: "CVE-2024-12342"},
|
||||
},
|
||||
Severities: &[]v6.Severity{
|
||||
{Type: "CVSS_V3", Score: "7.5", Source: sp("nvd@nist.gov"), Priority: sp("primary")},
|
||||
{Type: "CVSS_V3", Score: "7.5", Source: sp("nvd@nist.gov"), Rank: sp("primary")},
|
||||
},
|
||||
References: &[]v6.Reference{
|
||||
{Type: "ADVISORY", URL: "https://example.com/GHSA-xxxx-xxxx-xxxx2"},
|
||||
|
@ -125,7 +125,7 @@ func populateFixture1(store v6.Store) error {
|
|||
{Alias: "GHSA-xxxx-xxxx-xxxx3"},
|
||||
},
|
||||
Severities: &[]v6.Severity{
|
||||
{Type: "CVSS_V3", Score: "6.0", Source: sp("nvd@nist.gov"), Priority: sp("primary")},
|
||||
{Type: "CVSS_V3", Score: "6.0", Source: sp("nvd@nist.gov"), Rank: sp("primary")},
|
||||
},
|
||||
References: &[]v6.Reference{
|
||||
{Type: "ADVISORY", URL: "https://example.com/CVE-2024-12343"},
|
||||
|
@ -169,7 +169,7 @@ func populateFixture1(store v6.Store) error {
|
|||
{Alias: fmt.Sprintf("CVE-2024-1234%d", i+3)},
|
||||
},
|
||||
Severities: &[]v6.Severity{
|
||||
{Type: "CVSS_V3", Score: "4.0", Source: sp("nvd@nist.gov"), Priority: sp("primary")},
|
||||
{Type: "CVSS_V3", Score: "4.0", Source: sp("nvd@nist.gov"), Rank: sp("primary")},
|
||||
},
|
||||
References: &[]v6.Reference{
|
||||
{Type: "ADVISORY", URL: fmt.Sprintf("https://example.com/GHSA-xxxx-xxxx-xxxx%d", i+3)},
|
||||
|
|
|
@ -88,7 +88,7 @@ func run() error {
|
|||
// Type: "something",
|
||||
// Score: "2.0",
|
||||
// Source: "nvd",
|
||||
// Priority: "something-else",
|
||||
// Rank: "something-else",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
|
@ -100,7 +100,7 @@ func run() error {
|
|||
// Type: "something",
|
||||
// Score: "2.0",
|
||||
// Source: "nvd",
|
||||
// Priority: "something-else",
|
||||
// Rank: "something-else",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
|
@ -161,7 +161,7 @@ func severityStringer(vs *[]v6.Severity) string {
|
|||
}
|
||||
|
||||
stringer := func(v v6.Severity) string {
|
||||
return fmt.Sprintf("{Type=%q, Score=%q, Source=%q, Priority=%q}", v.Type, v.Score, v.Source, v.Priority)
|
||||
return fmt.Sprintf("{Type=%q, Score=%q, Source=%q, Rank=%q}", v.Type, v.Score, v.Source, v.Rank)
|
||||
}
|
||||
|
||||
var strs []string
|
||||
|
|
|
@ -300,7 +300,7 @@ func InsertVulnerabilities(db *gorm.DB, vulns []*Vulnerability) error {
|
|||
// Type string `gorm:"<-:create;column:type;not null;index:idx_severity,unique"`
|
||||
// Score string `gorm:"<-:create;column:score;not null;index:idx_severity,unique"`
|
||||
// Source string `gorm:"<-:create;column:source;index:idx_severity,unique"`
|
||||
// Priority string `gorm:"<-:create;column:priority;index:idx_severity,unique"`
|
||||
// Rank string `gorm:"<-:create;column:priority;index:idx_severity,unique"`
|
||||
//}
|
||||
//
|
||||
//func main() {
|
||||
|
@ -332,19 +332,19 @@ func InsertVulnerabilities(db *gorm.DB, vulns []*Vulnerability) error {
|
|||
// Type: "string",
|
||||
// Score: "high",
|
||||
// Source: "nvd",
|
||||
// Priority: "primary",
|
||||
// Rank: "primary",
|
||||
// },
|
||||
// {
|
||||
// Type: "string",
|
||||
// Score: "high",
|
||||
// Source: "nvd",
|
||||
// Priority: "primary",
|
||||
// Rank: "primary",
|
||||
// },
|
||||
// {
|
||||
// Type: "string",
|
||||
// Score: "medium",
|
||||
// Source: "cve",
|
||||
// Priority: "secondary",
|
||||
// Rank: "secondary",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
|
@ -358,19 +358,19 @@ func InsertVulnerabilities(db *gorm.DB, vulns []*Vulnerability) error {
|
|||
// Type: "string",
|
||||
// Score: "high",
|
||||
// Source: "nvd",
|
||||
// Priority: "primary",
|
||||
// Rank: "primary",
|
||||
// },
|
||||
// {
|
||||
// Type: "string",
|
||||
// Score: "medium",
|
||||
// Source: "cve",
|
||||
// Priority: "secondary",
|
||||
// Rank: "secondary",
|
||||
// },
|
||||
// {
|
||||
// Type: "string",
|
||||
// Score: "medium",
|
||||
// Source: "somewhere-else",
|
||||
// Priority: "secondary",
|
||||
// Rank: "secondary",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
|
@ -388,7 +388,7 @@ func InsertVulnerabilities(db *gorm.DB, vulns []*Vulnerability) error {
|
|||
// }
|
||||
//
|
||||
// for _, sev := range *vuln.Severities {
|
||||
// //if err := db.Where("type = ? AND score = ? AND source = ? AND priority = ?", sev.Type, sev.Score, sev.Source, sev.Priority).FirstOrCreate(&sev).Error; err != nil {
|
||||
// //if err := db.Where("type = ? AND score = ? AND source = ? AND priority = ?", sev.Type, sev.Score, sev.Source, sev.Rank).FirstOrCreate(&sev).Error; err != nil {
|
||||
// // fmt.Println("Failed to create severity:", err)
|
||||
// // return
|
||||
// //}
|
||||
|
|
|
@ -9,30 +9,18 @@ import (
|
|||
|
||||
func All() []any {
|
||||
return []any{
|
||||
&Cpe{},
|
||||
&CpeWithoutVersion{},
|
||||
&Digest{},
|
||||
&AffectedSeverity{},
|
||||
&AffectedVersion{},
|
||||
&Affected{},
|
||||
&Alias{},
|
||||
&Blob{},
|
||||
//&Comment{},
|
||||
&DbMetadata{},
|
||||
&DbSpecificNvd{},
|
||||
&Epss{},
|
||||
&KnownExploitedVulnerability{},
|
||||
//&LogicalPackage{},
|
||||
&AffectedExcludeVersion{},
|
||||
&OperatingSystem{},
|
||||
&PackageQualifierPlatformCpe{},
|
||||
&PackageQualifierRpmModularity{},
|
||||
//&Package{},
|
||||
&Provider{},
|
||||
&RangeEvent{},
|
||||
//&RangeEventMetadata{},
|
||||
&Range{},
|
||||
&Reference{},
|
||||
&Related{},
|
||||
&Severity{},
|
||||
&Vulnerability{},
|
||||
}
|
||||
|
@ -40,6 +28,12 @@ func All() []any {
|
|||
|
||||
// core vulnerability types
|
||||
|
||||
type Advisory struct {
|
||||
ID string
|
||||
|
||||
VulnerabilityIDs []string
|
||||
}
|
||||
|
||||
// Vulnerability represents the core advisory record for a single known vulnerability from a specific provider. There
|
||||
// may be multiple vulnerabilities with the same name.
|
||||
type Vulnerability struct {
|
||||
|
@ -48,6 +42,9 @@ type Vulnerability struct {
|
|||
// ProviderID is the foreign key to the Provider table which indicates the upstream data source for this vulnerability.
|
||||
ProviderID string `gorm:"column:provider_id;not null;index:idx_vulnerability_provider"`
|
||||
|
||||
//// ProviderNamespace is an optional field reserved for logical grouping of vulnerabilities from the same provider (e.g. OS version number)
|
||||
//ProviderNamespace string `gorm:"column:provider_namespace;not null;index:idx_vulnerability_provider"`
|
||||
|
||||
// Provider is the result of a join with the Provider table, which represents all information about where this vulnerability record came from.
|
||||
Provider *Provider
|
||||
|
||||
|
@ -55,19 +52,18 @@ type Vulnerability struct {
|
|||
Name string `gorm:"column:name;not null;index;index:idx_vulnerability_provider"`
|
||||
|
||||
// Modified is the time the entry was last modified, as an RFC3339-formatted timestamp in UTC (ending in “Z”) (mirrors the OSV field)
|
||||
Modified *string `gorm:"column:modified"`
|
||||
Modified string `gorm:"column:modified"`
|
||||
|
||||
// Published is the time the entry should be considered to have been published, as an RFC3339-formatted time stamp in UTC (ending in “Z”) (mirrors the OSV field)
|
||||
Published *string `gorm:"column:published"`
|
||||
Published string `gorm:"column:published"`
|
||||
|
||||
// Withdrawn is the time the entry should be considered to have been withdrawn, as an RFC3339-formatted timestamp in UTC (ending in “Z”) (mirrors the OSV field)
|
||||
Withdrawn *string `gorm:"column:withdrawn"`
|
||||
Withdrawn string `gorm:"column:withdrawn"`
|
||||
|
||||
// SummaryDigest is a self describing hash (e.g. sha256:123... not 123...) of the summary field from the OSV summary field. This digest is searched against the Blob table/DB.
|
||||
SummaryDigest *string `gorm:"column:summary_digest"`
|
||||
Status string `gorm:"column:status"` // example: "active, withdrawn, rejected, ..." could be an enum
|
||||
|
||||
// DetailDigest is a self describing hash (e.g. sha256:123... not 123...) of the detail field from the OSV summary field. This digest is searched against the Blob table/DB.
|
||||
DetailDigest *string `gorm:"column:detail_digest"`
|
||||
Summary string `gorm:"column:summary"`
|
||||
Detail string `gorm:"column:detail;index,unique"`
|
||||
|
||||
// References are URLs to external resources that provide more information about the vulnerability (mirrors the OSV field)
|
||||
References *[]Reference `gorm:"foreignKey:VulnerabilityID"`
|
||||
|
@ -87,13 +83,13 @@ type Vulnerability struct {
|
|||
// Affected is a list of affected entries related to this vulnerability
|
||||
Affected *[]Affected `gorm:"foreignKey:VulnerabilityID"`
|
||||
|
||||
affected *[]Affected `gorm:"-"`
|
||||
batchWriteAffected *[]Affected `gorm:"-"`
|
||||
}
|
||||
|
||||
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 c.Affected != nil && len(*c.Affected) > 500 {
|
||||
c.affected = c.Affected
|
||||
c.batchWriteAffected = c.Affected
|
||||
c.Affected = nil
|
||||
}
|
||||
|
||||
|
@ -101,14 +97,14 @@ func (c *Vulnerability) BeforeCreate(tx *gorm.DB) error {
|
|||
}
|
||||
|
||||
func (c *Vulnerability) AfterCreate(tx *gorm.DB) error {
|
||||
if c.affected == nil {
|
||||
if c.batchWriteAffected == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// create in batches...
|
||||
|
||||
var affecteds []*Affected
|
||||
affs := *c.affected
|
||||
affs := *c.batchWriteAffected
|
||||
for i := range affs {
|
||||
a := affs[i]
|
||||
a.VulnerabilityID = c.ID
|
||||
|
@ -123,7 +119,7 @@ func (c *Vulnerability) AfterCreate(tx *gorm.DB) error {
|
|||
affs[i] = *affecteds[i]
|
||||
}
|
||||
c.Affected = &affs
|
||||
c.affected = nil
|
||||
c.batchWriteAffected = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -168,17 +164,17 @@ type Alias struct {
|
|||
Alias string `gorm:"column:alias;not null,index:idx_alias,unique"`
|
||||
}
|
||||
|
||||
// Related represents a single related vulnerability name
|
||||
type Related struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
//VulnerabilityID int64 `gorm:"column:vulnerability_id;not null"`
|
||||
|
||||
// Name of the related vulnerability (e.g. CVE-2024-34102 or GHSA-85rg-8m6h-825p)
|
||||
Name string `gorm:"column:name;not null,index:idx_related,unique"`
|
||||
|
||||
//// Reason is a free-form text field that describes the relationship between the two vulnerabilities ("CVE-2022-12345 might be related to CVE-2022-54321 because both affect the same software library but are distinct issues")
|
||||
//Reason string `gorm:"column:reason"`
|
||||
}
|
||||
//type CVSS struct {
|
||||
// Vector string `gorm:"column:vector"`
|
||||
//
|
||||
// // 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"`
|
||||
//
|
||||
// Vendor datatypes.JSON `gorm:"column:vendor"`
|
||||
//
|
||||
// // Rank is a free-form organizational field to convey priority over other severities
|
||||
// Rank int `gorm:"column:priority"`
|
||||
//}
|
||||
|
||||
// Severity represents a single severity record for a vulnerability
|
||||
type Severity struct {
|
||||
|
@ -191,10 +187,10 @@ type Severity struct {
|
|||
Score string `gorm:"column:score;not null"`
|
||||
|
||||
// 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"`
|
||||
|
||||
// Priority is a free-form organizational field to convey priority over other severities (e.g. primary vs secondary or authoritative vs unverified)
|
||||
Priority *string `gorm:"column:priority"` // TODO: naming is hard...
|
||||
// Rank is a free-form organizational field to convey priority over other severities
|
||||
Rank int `gorm:"column:priority"`
|
||||
}
|
||||
|
||||
type Reference struct {
|
||||
|
@ -222,21 +218,30 @@ type Affected struct {
|
|||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
VulnerabilityID int64 `gorm:"column:vulnerability_id,not null"`
|
||||
|
||||
//PackageID *int64 `gorm:"column:package_id"`
|
||||
//Package *Package
|
||||
|
||||
OperatingSystemID *int64 `gorm:"column:operating_system_id"`
|
||||
OperatingSystem *OperatingSystem `gorm:"foreignKey:OperatingSystemID"`
|
||||
|
||||
Versions *datatypes.JSONSlice[AffectedVersion] `gorm:"column:versions"`
|
||||
ExcludeVersions *datatypes.JSONSlice[AffectedExcludeVersion] `gorm:"column:excluded_versions"`
|
||||
Severities *datatypes.JSONSlice[AffectedSeverity] `gorm:"column:severities"`
|
||||
PackageQualifier *datatypes.JSON `gorm:"column:package_qualifier"`
|
||||
VersionConstraint string `gorm:"column:version_constraint"`
|
||||
VersionFormat string `gorm:"column:version_format"`
|
||||
|
||||
Range *[]Range `gorm:"foreignKey:AffectedID"`
|
||||
Package *Package `gorm:"embedded;embeddedPrefix:package_"`
|
||||
Digest *Digest `gorm:"embedded;embeddedPrefix:digest_"`
|
||||
Cpes *datatypes.JSONSlice[Cpe] `gorm:"column:cpes"`
|
||||
// package qualifiers
|
||||
|
||||
PlatformCpeID *int64 `gorm:"column:platform_cpe_id"`
|
||||
PlatformCpe *CpeWithoutVersion `gorm:"foreignKey:PlatformCpeID"`
|
||||
|
||||
RpmModularity string `gorm:"column:rpm_modularity"`
|
||||
|
||||
// identifiers
|
||||
|
||||
Package *Package `gorm:"embedded;embeddedPrefix:package_"`
|
||||
Digest *Digest `gorm:"embedded;embeddedPrefix:digest_"`
|
||||
//Cpe *Cpe `gorm:"embedded;embeddedPrefix:cpe_"`
|
||||
CpeID *int64 `gorm:"column:cpe_id"`
|
||||
Cpe *CpeWithoutVersion `gorm:"foreignKey:CpeID"`
|
||||
|
||||
// fix
|
||||
|
||||
Fix *Fix `gorm:"embedded;embeddedPrefix:fix_"`
|
||||
}
|
||||
|
||||
// TODO: add later and reuse existing similar tables with many2many
|
||||
|
@ -255,71 +260,14 @@ type Affected struct {
|
|||
// Digests *[]Digest `gorm:"many2many:not_affected_digests"`
|
||||
//}
|
||||
|
||||
// TODO: reuse existing Severities tables with many2many
|
||||
type AffectedSeverity struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
AffectedID int64 `gorm:"column:affected_id;not null"`
|
||||
|
||||
Type string `gorm:"column:type;not null"`
|
||||
Score string `gorm:"column:score;not null"`
|
||||
Source *string `gorm:"column:source"`
|
||||
Priority *string `gorm:"column:priority"` // TODO: naming is hard...
|
||||
type Fix struct {
|
||||
Version string `gorm:"column:version"`
|
||||
State string `gorm:"column:state"`
|
||||
//Detail *FixDetail
|
||||
}
|
||||
|
||||
type AffectedVersion struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
AffectedID int64 `gorm:"column:affected_id;not null"`
|
||||
|
||||
Version string `gorm:"column:version;not null"`
|
||||
}
|
||||
|
||||
type AffectedExcludeVersion struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
AffectedID int64 `gorm:"column:affected_id;not null"`
|
||||
|
||||
Version string `gorm:"column:version;not null"`
|
||||
}
|
||||
|
||||
type Range struct {
|
||||
ID int64 `gorm:"primaryKey"`
|
||||
AffectedID int64 `gorm:"column:affected_id;not null"`
|
||||
|
||||
Type string `gorm:"column:type;not null"`
|
||||
Repo *string `gorm:"column:repo"`
|
||||
Events *[]RangeEvent `gorm:"many2many:range_range_events"`
|
||||
}
|
||||
|
||||
type RangeEvent struct {
|
||||
ID int64 `gorm:"primaryKey"`
|
||||
|
||||
Introduced *string `gorm:"column:introduced;index:idx_range_event,unique"`
|
||||
Fixed *string `gorm:"column:fixed;index:idx_range_event,unique"`
|
||||
LastAffected *string `gorm:"column:last_affected;index:idx_range_event,unique"`
|
||||
Limit *string `gorm:"column:range_limit;index:idx_range_event,unique"` // limit is a keyword in sql, so it's easier to just use range_limit instead
|
||||
|
||||
// non OSV...
|
||||
State string `gorm:"column:state;index:idx_range_event,unique"` // TODO: this could be db specific since there will be multiple ways to represent/interpret this
|
||||
|
||||
// if deduplicating these, then this can't be associated
|
||||
//RangeEventMetadata *[]RangeEventMetadata `gorm:"foreignKey:RangeEventID"`
|
||||
}
|
||||
|
||||
func (re *RangeEvent) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
//tx = tx.Session(&gorm.Session{Logger: loggerIgnoreRecordNotFound{tx.Logger}})
|
||||
|
||||
// if the event already exist in the table then we should not insert a new record
|
||||
var existing RangeEvent
|
||||
result := tx.Where("introduced = ? AND fixed = ? AND last_affected = ? AND range_limit = ? AND state = ?", re.Introduced, re.Fixed, re.LastAffected, re.Limit, re.State).First(&existing)
|
||||
if result.Error == nil {
|
||||
// if the record already exists, then we should use the existing record
|
||||
*re = existing
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//type RangeEventMetadata struct {
|
||||
// ID int64 `gorm:"primaryKey"`
|
||||
// RangeEventID int64 `gorm:"column:range_event_id;not null"`
|
||||
//type FixDetail struct {
|
||||
// ID int64 `gorm:"primaryKey"`
|
||||
//
|
||||
// GitCommit *string `gorm:"column:git_commit"`
|
||||
// PullRequestURL *string `gorm:"column:pull_request_url"`
|
||||
|
@ -329,18 +277,23 @@ func (re *RangeEvent) BeforeCreate(tx *gorm.DB) (err error) {
|
|||
|
||||
// primary package identifiers (search entrypoints)
|
||||
|
||||
type Cpe struct {
|
||||
type CpeWithoutVersion struct {
|
||||
// TODO: what about different CPE versions?
|
||||
ID int64 `gorm:"primaryKey"`
|
||||
|
||||
Schema string `gorm:"column:schema;not null;index:idx_cpe"` // effectively the CPE version
|
||||
Type string `gorm:"column:type;not null;index:idx_cpe"`
|
||||
Vendor *string `gorm:"column:vendor;index:idx_cpe"`
|
||||
Product string `gorm:"column:product;not null;index:idx_cpe"`
|
||||
Version *string `gorm:"column:version;index:idx_cpe"`
|
||||
Update *string `gorm:"column:version_update;index:idx_cpe"` // update is a SQL keyword
|
||||
TargetSoftware *string `gorm:"column:target_software;index:idx_cpe"`
|
||||
Type string `gorm:"column:type;not null;index:idx_cpe,unique"`
|
||||
Vendor string `gorm:"column:vendor;index:idx_cpe,unique"`
|
||||
Product string `gorm:"column:product;not null;index:idx_cpe,unique"`
|
||||
Edition string `gorm:"column:edition;index:idx_cpe,unique"`
|
||||
Language string `gorm:"column:language;index:idx_cpe,unique"`
|
||||
SoftwareEdition string `gorm:"column:software_edition;index:idx_cpe,unique"`
|
||||
TargetHardware string `gorm:"column:target_hardware;index:idx_cpe,unique"`
|
||||
TargetSoftware string `gorm:"column:target_software;index:idx_cpe,unique"`
|
||||
Other string `gorm:"column:other;index:idx_cpe,unique"`
|
||||
}
|
||||
|
||||
// TODO: should we also have the remaining CPE fields here?
|
||||
func (c CpeWithoutVersion) 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)
|
||||
}
|
||||
|
||||
//func (c *Cpe) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
|
@ -364,8 +317,8 @@ type Package struct {
|
|||
// TODO: setup unique indexes only for writing and drop before shipping for the best size tradeoff
|
||||
|
||||
// TODO: break purl out into fields here
|
||||
Ecosystem *string `gorm:"column:ecosystem;index:idx_package"` // TODO: NVD doesn't have this, should this be nullable?
|
||||
Name string `gorm:"column:name;index:idx_package"`
|
||||
Type string `gorm:"column:type;index:idx_package"` // TODO: NVD doesn't have this, should this be nullable?
|
||||
Name string `gorm:"column:name;index:idx_package"`
|
||||
|
||||
//OperatingSystemID *int64 `gorm:"column:operating_system_id"`
|
||||
//OperatingSystem *OperatingSystem `gorm:"foreignKey:OperatingSystemID"`
|
||||
|
@ -428,30 +381,6 @@ func (os *OperatingSystem) BeforeCreate(tx *gorm.DB) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
type PackageQualifierPlatformCpe struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
PackageID int64 `gorm:"column:package_id;not null"`
|
||||
|
||||
Cpe string `gorm:"column:cpe;not null"`
|
||||
}
|
||||
|
||||
type PackageQualifierRpmModularity struct {
|
||||
ID int64 `gorm:"column:id;primaryKey"`
|
||||
PackageID int64 `gorm:"column:package_id;not null"`
|
||||
|
||||
Module string `gorm:"column:module;not null"`
|
||||
}
|
||||
|
||||
// logical package info
|
||||
|
||||
//type LogicalPackage struct {
|
||||
// ID int64 `gorm:"column:id;primaryKey"`
|
||||
//
|
||||
// Packages []Package `gorm:"many2many:logical_package_packages"`
|
||||
//}
|
||||
|
||||
// aux
|
||||
|
||||
type DbMetadata struct {
|
||||
BuildTimestamp *time.Time `gorm:"column:build_timestamp;not null"`
|
||||
Model int `gorm:"column:model;not null"`
|
||||
|
|
|
@ -43,8 +43,8 @@ func (s *vulnerabilityStore) GetVulnerability(id string, loadAuxInfo bool) ([]Vu
|
|||
func (s *vulnerabilityStore) AddVulnerabilities(vulnerabilities ...*Vulnerability) error {
|
||||
for _, h := range []func([]*Vulnerability) error{
|
||||
s.handleOSs,
|
||||
s.handleRangeEvents,
|
||||
//s.handleCPEs,
|
||||
//s.handleRangeEvents,
|
||||
s.handleCPEs,
|
||||
//s.handlePackages,
|
||||
} {
|
||||
if err := h(vulnerabilities); err != nil {
|
||||
|
@ -130,168 +130,171 @@ func (s *vulnerabilityStore) AddVulnerabilities(vulnerabilities ...*Vulnerabilit
|
|||
//
|
||||
//}
|
||||
|
||||
//func (s *vulnerabilityStore) handleCPEs(vulns []*Vulnerability) error {
|
||||
// // ensure unique cpes
|
||||
// unique, err := ensureUniqueCPEs(s.db, vulns)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// // update vulnerabilities with cpes IDs
|
||||
// updateAffectedsWithCPEs(vulns, unique)
|
||||
//
|
||||
// return nil
|
||||
//}
|
||||
//
|
||||
//func updateAffectedsWithCPEs(vulns []*Vulnerability, uniqueCPEs []*Cpe) {
|
||||
// cpeMap := make(map[string]int64)
|
||||
// for _, c := range uniqueCPEs {
|
||||
// cpeKey := fmt.Sprintf("%s:%s:%s:%s:%s:%s:%s", c.Schema, c.Type, strVal(c.Vendor), c.Product, strVal(c.Version), strVal(c.Update), strVal(c.TargetSoftware))
|
||||
// cpeMap[cpeKey] = c.ID
|
||||
// }
|
||||
//
|
||||
// for i, v := range vulns {
|
||||
// if v.Affected == nil {
|
||||
// continue
|
||||
// }
|
||||
// for j, a := range *v.Affected {
|
||||
// if a.Cpes == nil {
|
||||
// continue
|
||||
// }
|
||||
// for k, c := range *a.Cpes {
|
||||
// cpeKey := fmt.Sprintf("%s:%s:%s:%s:%s:%s:%s", c.Schema, c.Type, strVal(c.Vendor), c.Product, strVal(c.Version), strVal(c.Update), strVal(c.TargetSoftware))
|
||||
// val := cpeMap[cpeKey]
|
||||
// (*(*vulns[i].Affected)[j].Cpes)[k].ID = val
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//func ensureUniqueCPEs(db *gorm.DB, vulns []*Vulnerability) ([]*Cpe, error) {
|
||||
// cpeMap := make(map[string]Cpe)
|
||||
// for _, v := range vulns {
|
||||
// if v.Affected == nil {
|
||||
// continue
|
||||
// }
|
||||
// for _, a := range *v.Affected {
|
||||
// if a.Cpes == nil {
|
||||
// continue
|
||||
// }
|
||||
// for _, c := range *a.Cpes {
|
||||
// cpeKey := fmt.Sprintf("%s:%s:%s:%s:%s:%s:%s", c.Schema, c.Type, strVal(c.Vendor), c.Product, strVal(c.Version), strVal(c.Update), strVal(c.TargetSoftware))
|
||||
// cpeMap[cpeKey] = c
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // extract unique CPEs
|
||||
// var uniqueCPEs []*Cpe
|
||||
// for i := range cpeMap {
|
||||
// c := cpeMap[i]
|
||||
// uniqueCPEs = append(uniqueCPEs, &c)
|
||||
// }
|
||||
//
|
||||
// // insert unique CPEs into the database or fetch existing ones
|
||||
// for i, c := range uniqueCPEs {
|
||||
// var existing Cpe
|
||||
// err := db.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).
|
||||
// FirstOrCreate(&existing, c).Error
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// uniqueCPEs[i] = &existing
|
||||
// }
|
||||
//
|
||||
// return uniqueCPEs, nil
|
||||
//}
|
||||
|
||||
func (s *vulnerabilityStore) handleRangeEvents(vulns []*Vulnerability) error {
|
||||
// ensure unique operating systems
|
||||
unique, err := ensureUniqueRangeEvents(s.db, vulns)
|
||||
func (s *vulnerabilityStore) handleCPEs(vulns []*Vulnerability) error {
|
||||
// ensure unique cpes
|
||||
unique, err := ensureUniqueCPEs(s.db, vulns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update vulnerabilities with operating system IDs
|
||||
updateAffectedsWithRanges(vulns, unique)
|
||||
// update vulnerabilities with cpes IDs
|
||||
updateAffectedsWithCPEs(vulns, unique)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureUniqueRangeEvents(db *gorm.DB, vulns []*Vulnerability) ([]*RangeEvent, error) {
|
||||
reMap := make(map[string]RangeEvent)
|
||||
for _, v := range vulns {
|
||||
for _, a := range *v.Affected {
|
||||
if a.Range == nil {
|
||||
continue
|
||||
}
|
||||
for _, r := range *a.Range {
|
||||
if r.Events == nil {
|
||||
continue
|
||||
}
|
||||
for _, re := range *r.Events {
|
||||
reKey := fmt.Sprintf("%s:%s:%s:%s:%s", strVal(re.Introduced), strVal(re.Fixed), strVal(re.LastAffected), strVal(re.Limit), re.State)
|
||||
reMap[reKey] = re
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// extract unique range events
|
||||
var uniqueRangeEvents []*RangeEvent
|
||||
for i := range reMap {
|
||||
re := reMap[i]
|
||||
uniqueRangeEvents = append(uniqueRangeEvents, &re)
|
||||
}
|
||||
|
||||
// insert unique range events into the database or fetch existing ones
|
||||
for i, re := range uniqueRangeEvents {
|
||||
var existing RangeEvent
|
||||
err := db.Where("introduced = ? AND fixed = ? AND last_affected = ? AND range_limit = ? AND state = ?", re.Introduced, re.Fixed, re.LastAffected, re.Limit, re.State).
|
||||
FirstOrCreate(&existing, re).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uniqueRangeEvents[i] = &existing
|
||||
|
||||
}
|
||||
|
||||
return uniqueRangeEvents, nil
|
||||
}
|
||||
|
||||
func updateAffectedsWithRanges(vulns []*Vulnerability, uniqueRangeEvents []*RangeEvent) {
|
||||
reMap := make(map[string]int64)
|
||||
for _, re := range uniqueRangeEvents {
|
||||
reKey := fmt.Sprintf("%s:%s:%s:%s:%s", strVal(re.Introduced), strVal(re.Fixed), strVal(re.LastAffected), strVal(re.Limit), re.State)
|
||||
reMap[reKey] = re.ID
|
||||
func updateAffectedsWithCPEs(vulns []*Vulnerability, uniqueCPEs []*CpeWithoutVersion) {
|
||||
cpeMap := make(map[string]int64)
|
||||
for _, c := range uniqueCPEs {
|
||||
cpeKey := c.String()
|
||||
cpeMap[cpeKey] = c.ID
|
||||
}
|
||||
|
||||
for i, v := range vulns {
|
||||
if v.Affected == nil {
|
||||
continue
|
||||
}
|
||||
for j, a := range *v.Affected {
|
||||
if a.Range == nil {
|
||||
continue
|
||||
if a.Cpe != nil {
|
||||
cpeKey := a.Cpe.String()
|
||||
val := cpeMap[cpeKey]
|
||||
(*(*vulns[i].Affected)[j].Cpe).ID = val
|
||||
}
|
||||
for k, r := range *a.Range {
|
||||
if r.Events == nil {
|
||||
continue
|
||||
}
|
||||
for l, re := range *r.Events {
|
||||
reKey := fmt.Sprintf("%s:%s:%s:%s:%s", strVal(re.Introduced), strVal(re.Fixed), strVal(re.LastAffected), strVal(re.Limit), re.State)
|
||||
val := reMap[reKey]
|
||||
(*(*(*vulns[i].Affected)[j].Range)[k].Events)[l].ID = val
|
||||
}
|
||||
if a.PlatformCpe != nil {
|
||||
cpeKey := a.PlatformCpe.String()
|
||||
val := cpeMap[cpeKey]
|
||||
(*(*vulns[i].Affected)[j].PlatformCpe).ID = val
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func strVal(s *string) string {
|
||||
if s == nil {
|
||||
return ""
|
||||
func ensureUniqueCPEs(db *gorm.DB, vulns []*Vulnerability) ([]*CpeWithoutVersion, error) {
|
||||
cpeMap := make(map[string]CpeWithoutVersion)
|
||||
for _, v := range vulns {
|
||||
if v.Affected == nil {
|
||||
continue
|
||||
}
|
||||
for _, a := range *v.Affected {
|
||||
if a.Cpe != nil {
|
||||
cpeKey := a.Cpe.String()
|
||||
cpeMap[cpeKey] = *a.Cpe
|
||||
}
|
||||
if a.PlatformCpe != nil {
|
||||
cpeKey := a.PlatformCpe.String()
|
||||
cpeMap[cpeKey] = *a.PlatformCpe
|
||||
}
|
||||
}
|
||||
}
|
||||
return *s
|
||||
|
||||
// extract unique CPEs
|
||||
var uniqueCPEs []*CpeWithoutVersion
|
||||
for i := range cpeMap {
|
||||
c := cpeMap[i]
|
||||
uniqueCPEs = append(uniqueCPEs, &c)
|
||||
}
|
||||
|
||||
// insert unique CPEs into the database or fetch existing ones
|
||||
for i, c := range uniqueCPEs {
|
||||
var existing CpeWithoutVersion
|
||||
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
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uniqueCPEs[i] = &existing
|
||||
}
|
||||
|
||||
return uniqueCPEs, nil
|
||||
}
|
||||
|
||||
//func (s *vulnerabilityStore) handleRangeEvents(vulns []*Vulnerability) error {
|
||||
// // ensure unique operating systems
|
||||
// unique, err := ensureUniqueRangeEvents(s.db, vulns)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// // update vulnerabilities with operating system IDs
|
||||
// updateAffectedsWithRanges(vulns, unique)
|
||||
//
|
||||
// return nil
|
||||
//}
|
||||
//
|
||||
//func ensureUniqueRangeEvents(db *gorm.DB, vulns []*Vulnerability) ([]*RangeEvent, error) {
|
||||
// reMap := make(map[string]RangeEvent)
|
||||
// for _, v := range vulns {
|
||||
// for _, a := range *v.Affected {
|
||||
// if a.Range == nil {
|
||||
// continue
|
||||
// }
|
||||
// for _, r := range *a.Range {
|
||||
// if r.Events == nil {
|
||||
// continue
|
||||
// }
|
||||
// for _, re := range *r.Events {
|
||||
// reKey := fmt.Sprintf("%s:%s:%s:%s:%s", strVal(re.Introduced), strVal(re.Fixed), strVal(re.LastAffected), strVal(re.Limit), re.State)
|
||||
// reMap[reKey] = re
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // extract unique range events
|
||||
// var uniqueRangeEvents []*RangeEvent
|
||||
// for i := range reMap {
|
||||
// re := reMap[i]
|
||||
// uniqueRangeEvents = append(uniqueRangeEvents, &re)
|
||||
// }
|
||||
//
|
||||
// // insert unique range events into the database or fetch existing ones
|
||||
// for i, re := range uniqueRangeEvents {
|
||||
// var existing RangeEvent
|
||||
// err := db.Where("introduced = ? AND fixed = ? AND last_affected = ? AND range_limit = ? AND state = ?", re.Introduced, re.Fixed, re.LastAffected, re.Limit, re.State).
|
||||
// FirstOrCreate(&existing, re).Error
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// uniqueRangeEvents[i] = &existing
|
||||
//
|
||||
// }
|
||||
//
|
||||
// return uniqueRangeEvents, nil
|
||||
//}
|
||||
//
|
||||
//func updateAffectedsWithRanges(vulns []*Vulnerability, uniqueRangeEvents []*RangeEvent) {
|
||||
// reMap := make(map[string]int64)
|
||||
// for _, re := range uniqueRangeEvents {
|
||||
// reKey := fmt.Sprintf("%s:%s:%s:%s:%s", strVal(re.Introduced), strVal(re.Fixed), strVal(re.LastAffected), strVal(re.Limit), re.State)
|
||||
// reMap[reKey] = re.ID
|
||||
// }
|
||||
//
|
||||
// for i, v := range vulns {
|
||||
// for j, a := range *v.Affected {
|
||||
// if a.Range == nil {
|
||||
// continue
|
||||
// }
|
||||
// for k, r := range *a.Range {
|
||||
// if r.Events == nil {
|
||||
// continue
|
||||
// }
|
||||
// for l, re := range *r.Events {
|
||||
// reKey := fmt.Sprintf("%s:%s:%s:%s:%s", strVal(re.Introduced), strVal(re.Fixed), strVal(re.LastAffected), strVal(re.Limit), re.State)
|
||||
// val := reMap[reKey]
|
||||
// (*(*(*vulns[i].Affected)[j].Range)[k].Events)[l].ID = val
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//func strVal(s *string) string {
|
||||
// if s == nil {
|
||||
// return ""
|
||||
// }
|
||||
// return *s
|
||||
//}
|
||||
|
||||
func (s *vulnerabilityStore) handleOSs(vulns []*Vulnerability) error {
|
||||
// ensure unique operating systems
|
||||
uniqueOSList, err := ensureUniqueOperatingSystems(s.db, vulns)
|
||||
|
|
Loading…
Reference in a new issue