diff options
Diffstat (limited to 'meta/lib/oeqa/selftest/cases/cve_check.py')
-rw-r--r-- | meta/lib/oeqa/selftest/cases/cve_check.py | 208 |
1 files changed, 207 insertions, 1 deletions
diff --git a/meta/lib/oeqa/selftest/cases/cve_check.py b/meta/lib/oeqa/selftest/cases/cve_check.py index 3f343a2841..60cecd1328 100644 --- a/meta/lib/oeqa/selftest/cases/cve_check.py +++ b/meta/lib/oeqa/selftest/cases/cve_check.py | |||
@@ -1,9 +1,19 @@ | |||
1 | from oe.cve_check import Version | 1 | # |
2 | # Copyright OpenEmbedded Contributors | ||
3 | # | ||
4 | # SPDX-License-Identifier: MIT | ||
5 | # | ||
6 | |||
7 | import json | ||
8 | import os | ||
2 | from oeqa.selftest.case import OESelftestTestCase | 9 | from oeqa.selftest.case import OESelftestTestCase |
10 | from oeqa.utils.commands import bitbake, get_bb_vars | ||
3 | 11 | ||
4 | class CVECheck(OESelftestTestCase): | 12 | class CVECheck(OESelftestTestCase): |
5 | 13 | ||
6 | def test_version_compare(self): | 14 | def test_version_compare(self): |
15 | from oe.cve_check import Version | ||
16 | |||
7 | result = Version("100") > Version("99") | 17 | result = Version("100") > Version("99") |
8 | self.assertTrue( result, msg="Failed to compare version '100' > '99'") | 18 | self.assertTrue( result, msg="Failed to compare version '100' > '99'") |
9 | result = Version("2.3.1") > Version("2.2.3") | 19 | result = Version("2.3.1") > Version("2.2.3") |
@@ -34,3 +44,199 @@ class CVECheck(OESelftestTestCase): | |||
34 | self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' < '1.0r'") | 44 | self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' < '1.0r'") |
35 | result = Version("1.0b","alphabetical") > Version("1.0","alphabetical") | 45 | result = Version("1.0b","alphabetical") > Version("1.0","alphabetical") |
36 | self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' > '1.0'") | 46 | self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' > '1.0'") |
47 | |||
48 | # consider the trailing "p" and "patch" as patched released when comparing | ||
49 | result = Version("1.0","patch") < Version("1.0p1","patch") | ||
50 | self.assertTrue( result ,msg="Failed to compare version with suffix '1.0' < '1.0p1'") | ||
51 | result = Version("1.0p2","patch") > Version("1.0p1","patch") | ||
52 | self.assertTrue( result ,msg="Failed to compare version with suffix '1.0p2' > '1.0p1'") | ||
53 | result = Version("1.0_patch2","patch") < Version("1.0_patch3","patch") | ||
54 | self.assertTrue( result ,msg="Failed to compare version with suffix '1.0_patch2' < '1.0_patch3'") | ||
55 | |||
56 | |||
57 | def test_convert_cve_version(self): | ||
58 | from oe.cve_check import convert_cve_version | ||
59 | |||
60 | # Default format | ||
61 | self.assertEqual(convert_cve_version("8.3"), "8.3") | ||
62 | self.assertEqual(convert_cve_version(""), "") | ||
63 | |||
64 | # OpenSSL format version | ||
65 | self.assertEqual(convert_cve_version("1.1.1t"), "1.1.1t") | ||
66 | |||
67 | # OpenSSH format | ||
68 | self.assertEqual(convert_cve_version("8.3_p1"), "8.3p1") | ||
69 | self.assertEqual(convert_cve_version("8.3_p22"), "8.3p22") | ||
70 | |||
71 | # Linux kernel format | ||
72 | self.assertEqual(convert_cve_version("6.2_rc8"), "6.2-rc8") | ||
73 | self.assertEqual(convert_cve_version("6.2_rc31"), "6.2-rc31") | ||
74 | |||
75 | |||
76 | def test_recipe_report_json(self): | ||
77 | config = """ | ||
78 | INHERIT += "cve-check" | ||
79 | CVE_CHECK_FORMAT_JSON = "1" | ||
80 | """ | ||
81 | self.write_config(config) | ||
82 | |||
83 | vars = get_bb_vars(["CVE_CHECK_SUMMARY_DIR", "CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) | ||
84 | summary_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], vars["CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) | ||
85 | recipe_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], "m4-native_cve.json") | ||
86 | |||
87 | try: | ||
88 | os.remove(summary_json) | ||
89 | os.remove(recipe_json) | ||
90 | except FileNotFoundError: | ||
91 | pass | ||
92 | |||
93 | bitbake("m4-native -c cve_check") | ||
94 | |||
95 | def check_m4_json(filename): | ||
96 | with open(filename) as f: | ||
97 | report = json.load(f) | ||
98 | self.assertEqual(report["version"], "1") | ||
99 | self.assertEqual(len(report["package"]), 1) | ||
100 | package = report["package"][0] | ||
101 | self.assertEqual(package["name"], "m4-native") | ||
102 | found_cves = { issue["id"]: issue["status"] for issue in package["issue"]} | ||
103 | self.assertIn("CVE-2008-1687", found_cves) | ||
104 | self.assertEqual(found_cves["CVE-2008-1687"], "Patched") | ||
105 | |||
106 | self.assertExists(summary_json) | ||
107 | check_m4_json(summary_json) | ||
108 | self.assertExists(recipe_json) | ||
109 | check_m4_json(recipe_json) | ||
110 | |||
111 | |||
112 | def test_image_json(self): | ||
113 | config = """ | ||
114 | INHERIT += "cve-check" | ||
115 | CVE_CHECK_FORMAT_JSON = "1" | ||
116 | """ | ||
117 | self.write_config(config) | ||
118 | |||
119 | vars = get_bb_vars(["CVE_CHECK_DIR", "CVE_CHECK_SUMMARY_DIR", "CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) | ||
120 | report_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], vars["CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) | ||
121 | print(report_json) | ||
122 | try: | ||
123 | os.remove(report_json) | ||
124 | except FileNotFoundError: | ||
125 | pass | ||
126 | |||
127 | bitbake("core-image-minimal-initramfs") | ||
128 | self.assertExists(report_json) | ||
129 | |||
130 | # Check that the summary report lists at least one package | ||
131 | with open(report_json) as f: | ||
132 | report = json.load(f) | ||
133 | self.assertEqual(report["version"], "1") | ||
134 | self.assertGreater(len(report["package"]), 1) | ||
135 | |||
136 | # Check that a random recipe wrote a recipe report to deploy/cve/ | ||
137 | recipename = report["package"][0]["name"] | ||
138 | recipe_report = os.path.join(vars["CVE_CHECK_DIR"], recipename + "_cve.json") | ||
139 | self.assertExists(recipe_report) | ||
140 | with open(recipe_report) as f: | ||
141 | report = json.load(f) | ||
142 | self.assertEqual(report["version"], "1") | ||
143 | self.assertEqual(len(report["package"]), 1) | ||
144 | self.assertEqual(report["package"][0]["name"], recipename) | ||
145 | |||
146 | |||
147 | def test_recipe_report_json_unpatched(self): | ||
148 | config = """ | ||
149 | INHERIT += "cve-check" | ||
150 | CVE_CHECK_FORMAT_JSON = "1" | ||
151 | CVE_CHECK_REPORT_PATCHED = "0" | ||
152 | """ | ||
153 | self.write_config(config) | ||
154 | |||
155 | vars = get_bb_vars(["CVE_CHECK_SUMMARY_DIR", "CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) | ||
156 | summary_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], vars["CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) | ||
157 | recipe_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], "m4-native_cve.json") | ||
158 | |||
159 | try: | ||
160 | os.remove(summary_json) | ||
161 | os.remove(recipe_json) | ||
162 | except FileNotFoundError: | ||
163 | pass | ||
164 | |||
165 | bitbake("m4-native -c cve_check") | ||
166 | |||
167 | def check_m4_json(filename): | ||
168 | with open(filename) as f: | ||
169 | report = json.load(f) | ||
170 | self.assertEqual(report["version"], "1") | ||
171 | self.assertEqual(len(report["package"]), 1) | ||
172 | package = report["package"][0] | ||
173 | self.assertEqual(package["name"], "m4-native") | ||
174 | #m4 had only Patched CVEs, so the issues array will be empty | ||
175 | self.assertEqual(package["issue"], []) | ||
176 | |||
177 | self.assertExists(summary_json) | ||
178 | check_m4_json(summary_json) | ||
179 | self.assertExists(recipe_json) | ||
180 | check_m4_json(recipe_json) | ||
181 | |||
182 | |||
183 | def test_recipe_report_json_ignored(self): | ||
184 | config = """ | ||
185 | INHERIT += "cve-check" | ||
186 | CVE_CHECK_FORMAT_JSON = "1" | ||
187 | CVE_CHECK_REPORT_PATCHED = "1" | ||
188 | """ | ||
189 | self.write_config(config) | ||
190 | |||
191 | vars = get_bb_vars(["CVE_CHECK_SUMMARY_DIR", "CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) | ||
192 | summary_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], vars["CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) | ||
193 | recipe_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], "logrotate_cve.json") | ||
194 | |||
195 | try: | ||
196 | os.remove(summary_json) | ||
197 | os.remove(recipe_json) | ||
198 | except FileNotFoundError: | ||
199 | pass | ||
200 | |||
201 | bitbake("logrotate -c cve_check") | ||
202 | |||
203 | def check_m4_json(filename): | ||
204 | with open(filename) as f: | ||
205 | report = json.load(f) | ||
206 | self.assertEqual(report["version"], "1") | ||
207 | self.assertEqual(len(report["package"]), 1) | ||
208 | package = report["package"][0] | ||
209 | self.assertEqual(package["name"], "logrotate") | ||
210 | found_cves = {} | ||
211 | for issue in package["issue"]: | ||
212 | found_cves[issue["id"]] = { | ||
213 | "status" : issue["status"], | ||
214 | "detail" : issue["detail"] if "detail" in issue else "", | ||
215 | "description" : issue["description"] if "description" in issue else "" | ||
216 | } | ||
217 | # m4 CVE should not be in logrotate | ||
218 | self.assertNotIn("CVE-2008-1687", found_cves) | ||
219 | # logrotate has both Patched and Ignored CVEs | ||
220 | self.assertIn("CVE-2011-1098", found_cves) | ||
221 | self.assertEqual(found_cves["CVE-2011-1098"]["status"], "Patched") | ||
222 | self.assertEqual(len(found_cves["CVE-2011-1098"]["detail"]), 0) | ||
223 | self.assertEqual(len(found_cves["CVE-2011-1098"]["description"]), 0) | ||
224 | detail = "not-applicable-platform" | ||
225 | description = "CVE is debian, gentoo or SUSE specific on the way logrotate was installed/used" | ||
226 | self.assertIn("CVE-2011-1548", found_cves) | ||
227 | self.assertEqual(found_cves["CVE-2011-1548"]["status"], "Ignored") | ||
228 | self.assertEqual(found_cves["CVE-2011-1548"]["detail"], detail) | ||
229 | self.assertEqual(found_cves["CVE-2011-1548"]["description"], description) | ||
230 | self.assertIn("CVE-2011-1549", found_cves) | ||
231 | self.assertEqual(found_cves["CVE-2011-1549"]["status"], "Ignored") | ||
232 | self.assertEqual(found_cves["CVE-2011-1549"]["detail"], detail) | ||
233 | self.assertEqual(found_cves["CVE-2011-1549"]["description"], description) | ||
234 | self.assertIn("CVE-2011-1550", found_cves) | ||
235 | self.assertEqual(found_cves["CVE-2011-1550"]["status"], "Ignored") | ||
236 | self.assertEqual(found_cves["CVE-2011-1550"]["detail"], detail) | ||
237 | self.assertEqual(found_cves["CVE-2011-1550"]["description"], description) | ||
238 | |||
239 | self.assertExists(summary_json) | ||
240 | check_m4_json(summary_json) | ||
241 | self.assertExists(recipe_json) | ||
242 | check_m4_json(recipe_json) | ||