Skip to content

Commit 1da5284

Browse files
committed
vex: skip source RPM archs for fixed and known_not_affected
Ignore src/nosrc when building vulnerabilities so they do not overwrite empty archs from binary entries that share an arch-agnostic status key. Signed-off-by: crozzy <joseph.crosland@gmail.com>
1 parent eeaaf00 commit 1da5284

2 files changed

Lines changed: 86 additions & 5 deletions

File tree

rhel/vex/parser.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,12 @@ func (c *creator) fixedVulnerabilities(ctx context.Context, v *csaf.Vulnerabilit
920920
if err != nil {
921921
return nil, err
922922
}
923+
// Skip source RPMs: they share a Key with no-arch binary siblings when
924+
// arch is ignored, and would otherwise set Arch=src (no binary match)
925+
// or, if ignored in extractArch, emit duplicate binary vulns.
926+
if isSourceArch(st.PURL) {
927+
continue
928+
}
923929

924930
key := st.Key()
925931
vuln, created := lookup(key)
@@ -1031,6 +1037,9 @@ func (c *creator) knownNotAffectedVulnerabilities(ctx context.Context, v *csaf.V
10311037
if err != nil {
10321038
return nil, err
10331039
}
1040+
if isSourceArch(st.PURL) {
1041+
continue
1042+
}
10341043

10351044
key := st.Key()
10361045
vuln, created := lookup(key)
@@ -1348,3 +1357,11 @@ func extractArch(p *packageurl.PackageURL) string {
13481357
return arch
13491358
}
13501359
}
1360+
1361+
// IsSourceArch reports whether the pURL names a source RPM (arch=src/nosrc).
1362+
// Those are not installable binary arches and must not create or reshape
1363+
// binary-package vulnerabilities.
1364+
func isSourceArch(p *packageurl.PackageURL) bool {
1365+
arch, _ := qualifier(p, "arch")
1366+
return arch == "src" || arch == "nosrc"
1367+
}

rhel/vex/parser_test.go

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -380,20 +380,20 @@ func TestParse(t *testing.T) {
380380
{
381381
name: "cve-2022-1705",
382382
filenames: []string{"testdata/cve-2022-1705.json"},
383-
expectedVulns: 2009,
383+
expectedVulns: 1641,
384384
expectedDeleted: 0,
385385
},
386386
{
387387
name: "cve-2024-24786",
388388
filenames: []string{"testdata/cve-2024-24786.json"},
389-
expectedVulns: 1837,
389+
expectedVulns: 1764,
390390
expectedDeleted: 0,
391391
expectedAncestry: 732,
392392
},
393393
{
394394
name: "cve-2022-38752",
395395
filenames: []string{"testdata/cve-2022-38752.json"},
396-
expectedVulns: 1788,
396+
expectedVulns: 1494,
397397
expectedDeleted: 0,
398398
},
399399
{
@@ -405,13 +405,13 @@ func TestParse(t *testing.T) {
405405
{
406406
name: "cve-2024-24786-new-module-format",
407407
filenames: []string{"testdata/cve-2024-24786-1.json"},
408-
expectedVulns: 2731,
408+
expectedVulns: 2661,
409409
expectedDeleted: 0,
410410
},
411411
{
412412
name: "cve-2023-38545",
413413
filenames: []string{"testdata/cve-2023-38545.json"},
414-
expectedVulns: 269,
414+
expectedVulns: 265,
415415
expectedDeleted: 0,
416416
},
417417
{
@@ -828,3 +828,67 @@ func TestDocLinkFromBase(t *testing.T) {
828828
t.Fatalf("nil base: got %q, want empty", got)
829829
}
830830
}
831+
832+
func TestExtractArch(t *testing.T) {
833+
t.Parallel()
834+
tests := []struct {
835+
name string
836+
purl packageurl.PackageURL
837+
want string
838+
}{
839+
{
840+
name: "no arch",
841+
purl: packageurl.PackageURL{Type: packageurl.TypeRPM, Namespace: "redhat", Name: "binutils", Version: "2.45.1-5.1.hum1"},
842+
want: "",
843+
},
844+
{
845+
name: "x86_64",
846+
purl: packageurl.PackageURL{
847+
Type: packageurl.TypeRPM, Namespace: "redhat", Name: "binutils", Version: "2.45.1-5.1.hum1",
848+
Qualifiers: packageurl.QualifiersFromMap(map[string]string{"arch": "x86_64"}),
849+
},
850+
want: "amd64|x86_64",
851+
},
852+
{
853+
name: "aarch64",
854+
purl: packageurl.PackageURL{
855+
Type: packageurl.TypeRPM, Namespace: "redhat", Name: "binutils", Version: "2.45.1-5.1.hum1",
856+
Qualifiers: packageurl.QualifiersFromMap(map[string]string{"arch": "aarch64"}),
857+
},
858+
want: "aarch64",
859+
},
860+
}
861+
for _, tc := range tests {
862+
t.Run(tc.name, func(t *testing.T) {
863+
got := extractArch(&tc.purl)
864+
if got != tc.want {
865+
t.Fatalf("got %q, want %q", got, tc.want)
866+
}
867+
})
868+
}
869+
}
870+
871+
func TestIsSourceArch(t *testing.T) {
872+
t.Parallel()
873+
tests := []struct {
874+
name string
875+
arch string
876+
want bool
877+
}{
878+
{name: "empty", arch: "", want: false},
879+
{name: "x86_64", arch: "x86_64", want: false},
880+
{name: "src", arch: "src", want: true},
881+
{name: "nosrc", arch: "nosrc", want: true},
882+
}
883+
for _, tc := range tests {
884+
t.Run(tc.name, func(t *testing.T) {
885+
p := &packageurl.PackageURL{Type: packageurl.TypeRPM, Name: "binutils"}
886+
if tc.arch != "" {
887+
p.Qualifiers = packageurl.QualifiersFromMap(map[string]string{"arch": tc.arch})
888+
}
889+
if got := isSourceArch(p); got != tc.want {
890+
t.Fatalf("got %v, want %v", got, tc.want)
891+
}
892+
})
893+
}
894+
}

0 commit comments

Comments
 (0)