Skip to content

Commit 7b2b40f

Browse files
committed
add and expose daily fixable vulnerability history fields for artifacts (model/DTO/transformer/migrations/aggregation/query wiring)
Current problem: open_dependency_vulns is populated correctly, but fixable_* and cve_purl_fixable_* are still written as 0
1 parent 0feb361 commit 7b2b40f

13 files changed

Lines changed: 174 additions & 1370 deletions

cmd/devguard-cli/commands/daemon.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ func runPipelineForAsset(assetIDStr, assetVersionSlug string) error {
100100
integrations.Module,
101101
vulndb.Module,
102102
daemons.Module,
103+
fixedversion.Module,
103104
fx.Populate(&daemonRunner, &dependencyVulnRepository, &dependencyVulnService, &assetRepository, &assetVersionRepository),
104105
)
105106

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- Recovery migration placeholder for missing historical version.
2+
-- Intentionally left empty.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-- Recovery migration placeholder for missing historical version.
2+
-- Intentionally left empty to unblock environments that already reference
3+
-- migration version 20260304170435 in schema_migrations.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
ALTER TABLE public.artifact_risk_history
2+
DROP COLUMN IF EXISTS cve_purl_fixable_critical,
3+
DROP COLUMN IF EXISTS cve_purl_fixable_high,
4+
DROP COLUMN IF EXISTS cve_purl_fixable_medium,
5+
DROP COLUMN IF EXISTS cve_purl_fixable_low,
6+
DROP COLUMN IF EXISTS fixable_critical,
7+
DROP COLUMN IF EXISTS fixable_high,
8+
DROP COLUMN IF EXISTS fixable_medium,
9+
DROP COLUMN IF EXISTS fixable_low;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
ALTER TABLE public.artifact_risk_history
2+
ADD COLUMN IF NOT EXISTS fixable_low INTEGER DEFAULT 0,
3+
ADD COLUMN IF NOT EXISTS fixable_medium INTEGER DEFAULT 0,
4+
ADD COLUMN IF NOT EXISTS fixable_high INTEGER DEFAULT 0,
5+
ADD COLUMN IF NOT EXISTS fixable_critical INTEGER DEFAULT 0,
6+
ADD COLUMN IF NOT EXISTS cve_purl_fixable_low INTEGER DEFAULT 0,
7+
ADD COLUMN IF NOT EXISTS cve_purl_fixable_medium INTEGER DEFAULT 0,
8+
ADD COLUMN IF NOT EXISTS cve_purl_fixable_high INTEGER DEFAULT 0,
9+
ADD COLUMN IF NOT EXISTS cve_purl_fixable_critical INTEGER DEFAULT 0;
10+
11+
UPDATE public.artifact_risk_history
12+
SET
13+
fixable_low = COALESCE(fixable_low, 0),
14+
fixable_medium = COALESCE(fixable_medium, 0),
15+
fixable_high = COALESCE(fixable_high, 0),
16+
fixable_critical = COALESCE(fixable_critical, 0),
17+
cve_purl_fixable_low = COALESCE(cve_purl_fixable_low, 0),
18+
cve_purl_fixable_medium = COALESCE(cve_purl_fixable_medium, 0),
19+
cve_purl_fixable_high = COALESCE(cve_purl_fixable_high, 0),
20+
cve_purl_fixable_critical = COALESCE(cve_purl_fixable_critical, 0);

database/models/statistic_model.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ type Distribution struct {
2323
Medium int `json:"medium"`
2424
Critical int `json:"critical"`
2525

26+
FixableLow int `json:"fixableLow"`
27+
FixableMedium int `json:"fixableMedium"`
28+
FixableHigh int `json:"fixableHigh"`
29+
FixableCritical int `json:"fixableCritical"`
30+
2631
LowCVSS int `json:"lowCvss"`
2732
MediumCVSS int `json:"mediumCvss"`
2833
HighCVSS int `json:"highCvss"`
@@ -37,6 +42,11 @@ type Distribution struct {
3742
CVEPurlMediumCVSS int `json:"cvePurlMediumCvss"`
3843
CVEPurlHighCVSS int `json:"cvePurlHighCvss"`
3944
CVEPurlCriticalCVSS int `json:"cvePurlCriticalCvss"`
45+
46+
CVEPurlFixableLow int `json:"cvePurlFixableLow"`
47+
CVEPurlFixableMedium int `json:"cvePurlFixableMedium"`
48+
CVEPurlFixableHigh int `json:"cvePurlFixableHigh"`
49+
CVEPurlFixableCritical int `json:"cvePurlFixableCritical"`
4050
}
4151

4252
type History struct {

database/repositories/artifact_risk_history_repository.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ func (r *artifactRiskHistoryRepository) GetRiskHistoryByRelease(ctx context.Cont
7373
arh.sum_closed_risk, arh.avg_closed_risk, arh.max_closed_risk, arh.min_closed_risk,
7474
arh.open_dependency_vulns, arh.fixed_dependency_vulns,
7575
arh.low, arh.medium, arh.high, arh.critical,
76+
arh.fixable_low, arh.fixable_medium, arh.fixable_high, arh.fixable_critical,
7677
arh.cve_purl_low, arh.cve_purl_medium, arh.cve_purl_high, arh.cve_purl_critical,
78+
arh.cve_purl_fixable_low, arh.cve_purl_fixable_medium, arh.cve_purl_fixable_high, arh.cve_purl_fixable_critical,
7779
arh.low_cvss, arh.medium_cvss, arh.high_cvss, arh.critical_cvss,
7880
arh.cve_purl_low_cvss, arh.cve_purl_medium_cvss, arh.cve_purl_high_cvss, arh.cve_purl_critical_cvss
7981
FROM artifact_risk_history arh
@@ -98,8 +100,10 @@ func (r *artifactRiskHistoryRepository) GetRiskHistoryForOrg(ctx context.Context
98100
SELECT
99101
day,
100102
SUM(low) low, SUM(medium) medium, SUM(high) high, SUM(critical) critical,
103+
SUM(fixable_low) fixable_low, SUM(fixable_medium) fixable_medium, SUM(fixable_high) fixable_high, SUM(fixable_critical) fixable_critical,
101104
SUM(low_cvss) low_cvss, SUM(medium_cvss) medium_cvss, SUM(high_cvss) high_cvss, SUM(critical_cvss) critical_cvss,
102105
SUM(cve_purl_low) cve_purl_low, SUM(cve_purl_medium) cve_purl_medium, SUM(cve_purl_high) cve_purl_high, SUM(cve_purl_critical) cve_purl_critical,
106+
SUM(cve_purl_fixable_low) cve_purl_fixable_low, SUM(cve_purl_fixable_medium) cve_purl_fixable_medium, SUM(cve_purl_fixable_high) cve_purl_fixable_high, SUM(cve_purl_fixable_critical) cve_purl_fixable_critical,
103107
SUM(cve_purl_low_cvss) cve_purl_low_cvss, SUM(cve_purl_medium_cvss) cve_purl_medium_cvss, SUM(cve_purl_high_cvss) cve_purl_high_cvss, SUM(cve_purl_critical_cvss) cve_purl_critical_cvss
104108
FROM
105109
artifact_risk_history a

database/repositories/statistics_repository.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,21 @@ func (r *statisticsRepository) TimeTravelDependencyVulnState(ctx context.Context
3737
dependencyVulns := []models.DependencyVuln{}
3838
var err error
3939
if artifactName == nil && assetVersionName == nil {
40-
err = r.GetDB(ctx, tx).Model(&models.DependencyVuln{}).Preload("CVE").Preload("Events", func(db *gorm.DB) *gorm.DB {
40+
err = r.GetDB(ctx, tx).Model(&models.DependencyVuln{}).Select("dependency_vulns.*").Preload("CVE").Preload("Events", func(db *gorm.DB) *gorm.DB {
4141
return db.Where("created_at <= ?", time).Order("created_at ASC")
4242
}).
4343
Joins("JOIN artifact_dependency_vulns adv ON adv.dependency_vuln_id = dependency_vulns.id").
4444
Where("dependency_vulns.asset_id = ?", assetID).Where("created_at <= ?", time).
4545
Find(&dependencyVulns).Error
4646
} else if artifactName != nil {
47-
err = r.GetDB(ctx, tx).Model(&models.DependencyVuln{}).Preload("CVE").Preload("Events", func(db *gorm.DB) *gorm.DB {
47+
err = r.GetDB(ctx, tx).Model(&models.DependencyVuln{}).Select("dependency_vulns.*").Preload("CVE").Preload("Events", func(db *gorm.DB) *gorm.DB {
4848
return db.Where("created_at <= ?", time).Order("created_at ASC")
4949
}).
5050
Joins("JOIN artifact_dependency_vulns adv ON adv.dependency_vuln_id = dependency_vulns.id").
51-
Where("adv.artifact_asset_version_name = ?", *assetVersionName).Where("adv.artifact_asset_id = ?", assetID).Where("adv.artifact_artifact_name = ?", artifactName).Where("created_at <= ?", time).
51+
Where("adv.artifact_asset_version_name = ?", *assetVersionName).Where("adv.artifact_asset_id = ?", assetID).Where("adv.artifact_artifact_name = ?", *artifactName).Where("created_at <= ?", time).
5252
Find(&dependencyVulns).Error
5353
} else {
54-
err = r.GetDB(ctx, tx).Model(&models.DependencyVuln{}).Preload("CVE").Preload("Events", func(db *gorm.DB) *gorm.DB {
54+
err = r.GetDB(ctx, tx).Model(&models.DependencyVuln{}).Select("dependency_vulns.*").Preload("CVE").Preload("Events", func(db *gorm.DB) *gorm.DB {
5555
return db.Where("created_at <= ?", time).Order("created_at ASC")
5656
}).Where("adv.artifact_asset_id = ?", assetID).Where("adv.artifact_artifact_name = ?", artifactName).Where("created_at <= ?", time).
5757
Find(&dependencyVulns).Error

dtos/statistics_dto.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ type Distribution struct {
3838
Medium int `json:"medium"`
3939
Critical int `json:"critical"`
4040

41+
FixableLow int `json:"fixableLow"`
42+
FixableMedium int `json:"fixableMedium"`
43+
FixableHigh int `json:"fixableHigh"`
44+
FixableCritical int `json:"fixableCritical"`
45+
4146
LowCVSS int `json:"lowCvss"`
4247
MediumCVSS int `json:"mediumCvss"`
4348
HighCVSS int `json:"highCvss"`
@@ -52,6 +57,11 @@ type Distribution struct {
5257
CVEPurlMediumCVSS int `json:"cvePurlMediumCvss"`
5358
CVEPurlHighCVSS int `json:"cvePurlHighCvss"`
5459
CVEPurlCriticalCVSS int `json:"cvePurlCriticalCvss"`
60+
61+
CVEPurlFixableLow int `json:"cvePurlFixableLow"`
62+
CVEPurlFixableMedium int `json:"cvePurlFixableMedium"`
63+
CVEPurlFixableHigh int `json:"cvePurlFixableHigh"`
64+
CVEPurlFixableCritical int `json:"cvePurlFixableCritical"`
5565
}
5666

5767
type History struct {

0 commit comments

Comments
 (0)