Skip to content

Commit 1f3c5d0

Browse files
hogo6002CharlyReux
authored andcommitted
Sort Debian OSV pkgInfos (#2120)
- Sorts the Debian OSV outputs to remain consistent each runs (#2103) - Fixes the `AffectedVersions` - modifies `first_package_finder.py` to support future Debian releases, like Debian 13.
1 parent 00a2e99 commit 1f3c5d0

File tree

5 files changed

+105
-33
lines changed

5 files changed

+105
-33
lines changed

vulnfeeds/cmd/debian/main.go

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"net/http"
77
"os"
88
"path"
9+
"sort"
10+
"strconv"
911

1012
"github.com/google/osv/vulnfeeds/cves"
1113
"github.com/google/osv/vulnfeeds/utility"
@@ -81,25 +83,29 @@ func getDebianReleaseMap() (map[string]string, error) {
8183
}
8284

8385
for _, row := range data[1:] {
84-
if row[seriesIndex] == "experimental" || row[seriesIndex] == "sid" {
86+
if row[versionIndex] == "" {
8587
continue
8688
}
87-
8889
releaseMap[row[seriesIndex]] = row[versionIndex]
8990
}
9091

9192
return releaseMap, err
9293
}
9394

9495
// updateOSVPkgInfos adds new release entries to osvPkgInfos.
95-
func updateOSVPkgInfos(pkgName string, cveId string, releases map[string]Release, osvPkgInfos map[string][]vulns.PackageInfo, debianReleaseMap map[string]string) {
96+
func updateOSVPkgInfos(pkgName string, cveId string, releases map[string]Release, osvPkgInfos map[string][]vulns.PackageInfo, debianReleaseMap map[string]string, releaseNames []string) {
9697
var pkgInfos []vulns.PackageInfo
9798
if value, ok := osvPkgInfos[cveId]; ok {
9899
pkgInfos = value
99100
}
100-
for releaseName, release := range releases {
101+
102+
for _, releaseName := range releaseNames {
101103
// Skips 'not yet assigned' entries because their status may change in the future.
102104
// For reference on urgency levels, see: https://security-team.debian.org/security_tracker.html#severity-levels
105+
release, ok := releases[releaseName]
106+
if !ok {
107+
continue
108+
}
103109
if release.Urgency == "not yet assigned" {
104110
continue
105111
}
@@ -114,17 +120,14 @@ func updateOSVPkgInfos(pkgName string, cveId string, releases map[string]Release
114120
}
115121
pkgInfo.EcosystemSpecific = make(map[string]string)
116122

123+
pkgInfo.VersionInfo = cves.VersionInfo{
124+
AffectedVersions: []cves.AffectedVersion{{Introduced: "0"}},
125+
}
117126
if release.Status == "resolved" {
118127
if release.FixedVersion == "0" { // not affected
119128
continue
120129
}
121-
pkgInfo.VersionInfo = cves.VersionInfo{
122-
AffectedVersions: []cves.AffectedVersion{{Introduced: "0", Fixed: release.FixedVersion}},
123-
}
124-
} else {
125-
pkgInfo.VersionInfo = cves.VersionInfo{
126-
AffectedVersions: []cves.AffectedVersion{{Introduced: "0"}},
127-
}
130+
pkgInfo.VersionInfo.AffectedVersions = append(pkgInfo.VersionInfo.AffectedVersions, cves.AffectedVersion{Fixed: release.FixedVersion})
128131
}
129132
pkgInfo.EcosystemSpecific["urgency"] = release.Urgency
130133
pkgInfos = append(pkgInfos, pkgInfo)
@@ -138,9 +141,30 @@ func updateOSVPkgInfos(pkgName string, cveId string, releases map[string]Release
138141
func generateDebianSecurityTrackerOSV(debianData DebianSecurityTrackerData, debianReleaseMap map[string]string) map[string][]vulns.PackageInfo {
139142
Logger.Infof("Converting Debian Security Tracker data to OSV package infos.")
140143
osvPkgInfos := make(map[string][]vulns.PackageInfo)
141-
for pkgName, pkg := range debianData {
144+
145+
// Sorts packages to ensure results remain consistent between runs.
146+
var pkgNames []string
147+
for name := range debianData {
148+
pkgNames = append(pkgNames, name)
149+
}
150+
sort.Strings(pkgNames)
151+
152+
// Sorts releases to ensure pkgInfos remain consistent between runs.
153+
releaseNames := make([]string, 0, len(debianReleaseMap))
154+
for k := range debianReleaseMap {
155+
releaseNames = append(releaseNames, k)
156+
}
157+
158+
sort.Slice(releaseNames, func(i, j int) bool {
159+
vi, _ := strconv.ParseFloat(debianReleaseMap[releaseNames[i]], 64)
160+
vj, _ := strconv.ParseFloat(debianReleaseMap[releaseNames[j]], 64)
161+
return vi < vj
162+
})
163+
164+
for _, pkgName := range pkgNames {
165+
pkg := debianData[pkgName]
142166
for cveId, cve := range pkg {
143-
updateOSVPkgInfos(pkgName, cveId, cve.Releases, osvPkgInfos, debianReleaseMap)
167+
updateOSVPkgInfos(pkgName, cveId, cve.Releases, osvPkgInfos, debianReleaseMap, releaseNames)
144168
}
145169
}
146170

vulnfeeds/cmd/debian/main_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ func Test_generateDebianSecurityTrackerOSV(t *testing.T) {
1818
_ = json.NewDecoder(file).Decode(&decodedDebianData)
1919

2020
debianReleaseMap := make(map[string]string)
21+
debianReleaseMap["trixie"] = "13"
2122
debianReleaseMap["buster"] = "10"
2223
debianReleaseMap["bullseye"] = "11"
2324
debianReleaseMap["bookworm"] = "12"
24-
debianReleaseMap["trixie"] = "13"
25-
debianReleaseMap["forky"] = "14"
25+
debianReleaseMap["sarge"] = "3.1"
26+
debianReleaseMap["stretch"] = "9"
2627

2728
osvPkgInfos := generateDebianSecurityTrackerOSV(decodedDebianData, debianReleaseMap)
2829
expectedCount := 2
Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,54 @@
11
[
22
{
33
"pkg_name": "apparmor",
4-
"ecosystem": "Debian12",
5-
"fixed_version": {},
4+
"ecosystem": "Debian:10",
5+
"fixed_version": {
6+
"affected_versions": [
7+
{
8+
"introduced": "0"
9+
}
10+
]
11+
},
612
"ecosystem_specific": {
713
"urgency": "unimportant"
814
}
915
},
1016
{
1117
"pkg_name": "apparmor",
12-
"ecosystem": "Debian11",
13-
"fixed_version": {},
18+
"ecosystem": "Debian:11",
19+
"fixed_version": {
20+
"affected_versions": [
21+
{
22+
"introduced": "0"
23+
}
24+
]
25+
},
1426
"ecosystem_specific": {
1527
"urgency": "unimportant"
1628
}
1729
},
1830
{
1931
"pkg_name": "apparmor",
20-
"ecosystem": "Debian10",
21-
"fixed_version": {},
32+
"ecosystem": "Debian:12",
33+
"fixed_version": {
34+
"affected_versions": [
35+
{
36+
"introduced": "0"
37+
}
38+
]
39+
},
2240
"ecosystem_specific": {
2341
"urgency": "unimportant"
2442
}
2543
},
2644
{
2745
"pkg_name": "apparmor",
28-
"ecosystem": "Debian13",
46+
"ecosystem": "Debian:13",
2947
"fixed_version": {
3048
"affected_versions": [
49+
{
50+
"introduced": "0"
51+
},
3152
{
3253
"fixed": "3.0.12-1"
3354
}
@@ -37,4 +58,4 @@
3758
"urgency": "unimportant"
3859
}
3960
}
40-
]
61+
]

vulnfeeds/test_data/parts/debian/CVE-2018-1000500.debian.json

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,56 @@
11
[
22
{
33
"pkg_name": "busybox",
4-
"ecosystem": "Debian10",
5-
"fixed_version": {},
4+
"ecosystem": "Debian:10",
5+
"fixed_version": {
6+
"affected_versions": [
7+
{
8+
"introduced": "0"
9+
}
10+
]
11+
},
612
"ecosystem_specific": {
7-
"urgency": "unimportant"
13+
"urgency": "end-of-life"
814
}
915
},
1016
{
1117
"pkg_name": "busybox",
12-
"ecosystem": "Debian13",
13-
"fixed_version": {},
18+
"ecosystem": "Debian:11",
19+
"fixed_version": {
20+
"affected_versions": [
21+
{
22+
"introduced": "0"
23+
}
24+
]
25+
},
1426
"ecosystem_specific": {
1527
"urgency": "unimportant"
1628
}
1729
},
1830
{
1931
"pkg_name": "busybox",
20-
"ecosystem": "Debian12",
21-
"fixed_version": {},
32+
"ecosystem": "Debian:12",
33+
"fixed_version": {
34+
"affected_versions": [
35+
{
36+
"introduced": "0"
37+
}
38+
]
39+
},
2240
"ecosystem_specific": {
2341
"urgency": "unimportant"
2442
}
2543
},
2644
{
2745
"pkg_name": "busybox",
28-
"ecosystem": "Debian11",
29-
"fixed_version": {},
46+
"ecosystem": "Debian:13",
47+
"fixed_version": {
48+
"affected_versions": [
49+
{
50+
"introduced": "0"
51+
}
52+
]
53+
},
3054
"ecosystem_specific": {
3155
"urgency": "unimportant"
3256
}

vulnfeeds/tools/debian/debian_converter/first_package_finder.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ def retrieve_codename_to_version() -> pd.DataFrame:
7171
df = pd.read_csv(csv, dtype=str)
7272
# `series` appears to be `codename` but with no caps
7373
df['sources'] = ''
74-
df.dropna(subset=['release'], inplace=True)
74+
df.dropna(subset=['version'], inplace=True)
75+
# Set `release` to `created` if not yet released
76+
df['release'] = df['release'].fillna(df['created'])
7577
codename_to_version = df.set_index('series')
7678

7779
return codename_to_version

0 commit comments

Comments
 (0)