Skip to content

Commit 8aa9f41

Browse files
committed
rhcc: modify matching to account for CPE matching
With the introduction on the labels.json file to identify RH produced container images Clair needs to start accounting for the CPE surfaced in the labels.json file and the VEX data. Care is taken here to ensure the original Dockerfile parsing process still works as expected (although, dockerfile images will require a re-index to include needed metadata). Signed-off-by: crozzy <[email protected]>
1 parent e5dfc70 commit 8aa9f41

9 files changed

+159
-8
lines changed

internal/matcher/controller.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ func (mc *Controller) dbFilter() (bool, bool) {
109109
func (mc *Controller) findInterested(records []*claircore.IndexRecord) []*claircore.IndexRecord {
110110
out := []*claircore.IndexRecord{}
111111
for _, record := range records {
112+
if record.Package.NormalizedVersion.Kind == claircore.UnmatchableKind {
113+
continue
114+
}
112115
if mc.m.Filter(record) {
113116
out = append(out, record)
114117
}

rhel/matcher.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func (m *Matcher) Query() []driver.MatchConstraint {
5050
//
5151
// TODO(crozzy) Remove once RH VEX data updates CPEs with standard matching
5252
// expressions.
53-
func isCPESubstringMatch(recordCPE cpe.WFN, vulnCPE cpe.WFN) bool {
53+
func IsCPESubstringMatch(recordCPE cpe.WFN, vulnCPE cpe.WFN) bool {
5454
return strings.HasPrefix(recordCPE.String(), strings.TrimRight(vulnCPE.String(), ":*"))
5555
}
5656

@@ -78,7 +78,7 @@ func (m *Matcher) Vulnerable(ctx context.Context, record *claircore.IndexRecord,
7878
Msg("unable to unbind repo CPE")
7979
return false, nil
8080
}
81-
if !cpe.Compare(vuln.Repo.CPE, record.Repository.CPE).IsSuperset() && !isCPESubstringMatch(record.Repository.CPE, vuln.Repo.CPE) {
81+
if !cpe.Compare(vuln.Repo.CPE, record.Repository.CPE).IsSuperset() && !IsCPESubstringMatch(record.Repository.CPE, vuln.Repo.CPE) {
8282
return false, nil
8383
}
8484

rhel/matcher_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ func TestIsCPEStringSubsetMatch(t *testing.T) {
290290
for _, tc := range testcases {
291291
t.Run(tc.name, func(t *testing.T) {
292292
tt := tc
293-
matched := isCPESubstringMatch(tt.recordCPE, tt.vulnCPE)
293+
matched := IsCPESubstringMatch(tt.recordCPE, tt.vulnCPE)
294294
if matched != tt.match {
295295
t.Errorf("unexpected matching %s and %s", tt.recordCPE, tt.vulnCPE)
296296
}

rhel/rhcc/matcher.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88

99
"github.com/quay/claircore"
1010
"github.com/quay/claircore/libvuln/driver"
11+
"github.com/quay/claircore/rhel"
12+
"github.com/quay/claircore/toolkit/types/cpe"
1113
)
1214

1315
// Matcher is an instance of the rhcc matcher. It's exported so it can be used
@@ -26,16 +28,31 @@ func (*matcher) Name() string { return "rhel-container-matcher" }
2628
// Filter implements [driver.Matcher].
2729
func (*matcher) Filter(r *claircore.IndexRecord) bool {
2830
return r.Repository != nil &&
29-
r.Repository.Name == GoldRepo.Name
31+
r.Repository.Key == RepositoryKey
3032
}
3133

3234
// Query implements [driver.Matcher].
3335
func (*matcher) Query() []driver.MatchConstraint {
34-
return []driver.MatchConstraint{driver.RepositoryName}
36+
return []driver.MatchConstraint{driver.RepositoryKey}
3537
}
3638

3739
// Vulnerable implements [driver.Matcher].
3840
func (*matcher) Vulnerable(ctx context.Context, record *claircore.IndexRecord, vuln *claircore.Vulnerability) (bool, error) {
41+
var err error
42+
if record.Repository.Name != GoldRepo.Name {
43+
// This is not a gold repo record, so we need to check if the CPE matches.
44+
vuln.Repo.CPE, err = cpe.Unbind(vuln.Repo.Name)
45+
if err != nil {
46+
zlog.Warn(ctx).
47+
Str("vulnerability name", vuln.Name).
48+
Err(err).
49+
Msg("unable to unbind repo CPE")
50+
return false, nil
51+
}
52+
if !cpe.Compare(vuln.Repo.CPE, record.Repository.CPE).IsSuperset() && !rhel.IsCPESubstringMatch(record.Repository.CPE, vuln.Repo.CPE) {
53+
return false, nil
54+
}
55+
}
3956
pkgVer, fixedInVer := rpmVersion.NewVersion(record.Package.Version), rpmVersion.NewVersion(vuln.FixedInVersion)
4057
zlog.Debug(ctx).
4158
Str("record", record.Package.Version).

test/rhel/rhcc_matcher_integration_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ func TestMatcherIntegration(t *testing.T) {
5858
cveID: "CVE-2020-8565",
5959
match: false,
6060
},
61+
{
62+
Name: "Clair labels",
63+
indexReport: "clair-rhel8-v3.5.5-4-labels",
64+
cveID: "CVE-2021-3762",
65+
match: true,
66+
},
6167
}
6268

6369
integration.NeedDB(t)

test/rhel/testdata/clair-rhel8-v3.5.5-4-indexreport.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@
7575
"repository": {
7676
"1": {
7777
"name": "Red Hat Container Catalog",
78-
"uri": "https://catalog.redhat.com/software/containers/explore"
78+
"uri": "https://catalog.redhat.com/software/containers/explore",
79+
"key": "rhcc-container-repository"
7980
}
8081
},
8182
"environments": {
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
{
2+
"err": "",
3+
"state": "IndexFinished",
4+
"success": true,
5+
"packages": {
6+
"32": {
7+
"id": "32",
8+
"cpe": "",
9+
"arch": "x86_64",
10+
"kind": "source",
11+
"name": "quay-clair-container",
12+
"source": {
13+
"id": "1",
14+
"cpe": "",
15+
"name": "",
16+
"version": "",
17+
"normalized_version": ""
18+
},
19+
"version": "v3.5.5-4",
20+
"normalized_version": "rhctag:3.5.0.0.0.0.0.0.0.0"
21+
},
22+
"34": {
23+
"id": "34",
24+
"cpe": "",
25+
"arch": "x86_64",
26+
"kind": "binary",
27+
"name": "quay/clair-rhel8",
28+
"source": {
29+
"id": "32",
30+
"cpe": "",
31+
"arch": "x86_64",
32+
"kind": "source",
33+
"name": "quay-clair-container",
34+
"version": "v3.5.5-4",
35+
"normalized_version": ""
36+
},
37+
"version": "v3.5.5-4",
38+
"normalized_version": "rhctag:3.5.0.0.0.0.0.0.0.0"
39+
},
40+
"36": {
41+
"id": "36",
42+
"cpe": "",
43+
"arch": "x86_64",
44+
"kind": "source",
45+
"name": "ubi8-container",
46+
"source": {
47+
"id": "1",
48+
"cpe": "",
49+
"name": "",
50+
"version": "",
51+
"normalized_version": ""
52+
},
53+
"version": "8.4-206.1626828523",
54+
"normalized_version": "rhctag:8.4.0.0.0.0.0.0.0.0"
55+
},
56+
"38": {
57+
"id": "38",
58+
"cpe": "",
59+
"arch": "x86_64",
60+
"kind": "binary",
61+
"name": "ubi8",
62+
"source": {
63+
"id": "36",
64+
"cpe": "",
65+
"arch": "x86_64",
66+
"kind": "source",
67+
"name": "ubi8-container",
68+
"version": "8.4-206.1626828523",
69+
"normalized_version": ""
70+
},
71+
"version": "8.4-206.1626828523",
72+
"normalized_version": "rhctag:8.4.0.0.0.0.0.0.0.0"
73+
}
74+
},
75+
"repository": {
76+
"1": {
77+
"id": "1",
78+
"name": "cpe:2.3:a:redhat:quay:3:*:el8:*:*:*:*:*",
79+
"key": "rhcc-container-repository",
80+
"cpe": "cpe:2.3:a:redhat:quay:3:*:el8:*:*:*:*:*"
81+
}
82+
},
83+
"environments": {
84+
"32": [
85+
{
86+
"package_db": "root/buildinfo/labels.json",
87+
"introduced_in": "sha256:a5ac7bbd6645d6b98e41600a1510d7378d74e6b0b858622b57fce2a8a05a87e5",
88+
"repository_ids": [
89+
"1"
90+
]
91+
}
92+
],
93+
"34": [
94+
{
95+
"package_db": "root/buildinfo/labels.json",
96+
"introduced_in": "sha256:a5ac7bbd6645d6b98e41600a1510d7378d74e6b0b858622b57fce2a8a05a87e5",
97+
"repository_ids": [
98+
"1"
99+
]
100+
}
101+
],
102+
"36": [
103+
{
104+
"package_db": "root/buildinfo/labels.json",
105+
"introduced_in": "sha256:a50df8fd88fecefc26fd331f832672108deb08cf9d2b303a5b86156a7f51b5d8",
106+
"repository_ids": [
107+
"1"
108+
]
109+
}
110+
],
111+
"38": [
112+
{
113+
"package_db": "root/buildinfo/labels.json",
114+
"introduced_in": "sha256:a50df8fd88fecefc26fd331f832672108deb08cf9d2b303a5b86156a7f51b5d8",
115+
"repository_ids": [
116+
"1"
117+
]
118+
}
119+
]
120+
},
121+
"manifest_hash": "sha256:e7a9c9de4b2375d2d846b6b3d3e476f9a180d5d2a27282f62ff8f5d6fb96889c"
122+
}

test/rhel/testdata/rook-ceph-operator-container-4.6-115.d1788e1.release_4.6-indexreport.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
"repository": {
4242
"1": {
4343
"name": "Red Hat Container Catalog",
44-
"uri": "https://catalog.redhat.com/software/containers/explore"
44+
"uri": "https://catalog.redhat.com/software/containers/explore",
45+
"key": "rhcc-container-repository"
4546
}
4647
},
4748
"environments": {

test/rhel/testdata/rook-ceph-operator-container-4.7-159.76b9b11.release_4.7-indexreport.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
"repository": {
4242
"1": {
4343
"name": "Red Hat Container Catalog",
44-
"uri": "https://catalog.redhat.com/software/containers/explore"
44+
"uri": "https://catalog.redhat.com/software/containers/explore",
45+
"key": "rhcc-container-repository"
4546
}
4647
},
4748
"environments": {

0 commit comments

Comments
 (0)