utils/checkpackagelib: add check for CPE variables set to default values

Now that we can specify that the default values for the CPE_ID variables
are valid, without having to actually set one (or more) to their
default, add a check-package check that validates that the CPE_ID
variables are indeed not set to their default.

It also validates that CPE_ID_VALID is not set when another CPE_ID
variable is set to a non-default value.

Add an anchor in the manual so that we can easily point to it.

Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Cc: Ricardo Martincoski <ricardo.martincoski@gmail.com>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
This commit is contained in:
Yann E. MORIN 2024-02-10 22:24:59 +01:00 committed by Thomas Petazzoni
parent c19cca0452
commit fcf465d04b
2 changed files with 74 additions and 1 deletions

View File

@ -511,7 +511,7 @@ LIBFOO_IGNORE_CVES += CVE-2020-12345
LIBFOO_IGNORE_CVES += CVE-2020-54321
----------------------
* +LIBFOO_CPE_ID_*+ variables is a set of variables that allows the
* [[cpe-id]] +LIBFOO_CPE_ID_*+ variables is a set of variables that allows the
package to define its https://nvd.nist.gov/products/cpe[CPE
identifier]. The available variables are:
+

View File

@ -366,3 +366,76 @@ class VariableWithBraces(_CheckFunction):
return ["{}:{}: use $() to delimit variables, not ${{}}"
.format(self.filename, lineno),
text]
class CPEVariables(_CheckFunction):
"""
Check that the values for the CPE variables are not the default.
- CPE_ID_* variables must not be set to their default
- CPE_ID_VALID must not be set if a non-default CPE_ID variable is set
"""
def before(self):
pkg, _ = os.path.splitext(os.path.basename(self.filename))
self.CPE_fields_defaults = {
"VALID": "NO",
"PREFIX": "cpe:2.3:a",
"VENDOR": f"{pkg}_project",
"PRODUCT": pkg,
"VERSION": None,
"UPDATE": "*",
}
self.valid = None
self.non_defaults = 0
self.CPE_FIELDS_RE = re.compile(
r"^\s*(.+_CPE_ID_({}))\s*=\s*(.+)$"
.format("|".join(self.CPE_fields_defaults)),
)
self.VERSION_RE = re.compile(
rf"^(HOST_)?{pkg.upper().replace('-', '_')}_VERSION\s*=\s*(.+)$",
)
self.COMMENT_RE = re.compile(r"^\s*#.*")
def check_line(self, lineno, text):
text = self.COMMENT_RE.sub('', text.rstrip())
# WARNING! The VERSION_RE can _also_ match the same lines as CPE_FIELDS_RE,
# but not the other way around. So we must first check for CPE_FIELDS_RE,
# and if not matched, then and only then check for VERSION_RE.
match = self.CPE_FIELDS_RE.match(text)
if match:
var, field, val = match.groups()
return self._check_field(lineno, text, field, var, val)
match = self.VERSION_RE.match(text)
if match:
self.CPE_fields_defaults["VERSION"] = match.groups()[1]
def after(self):
# "VALID" counts in the non-defaults; so when "VALID" is present,
# 1 non-default means only "VALID" is present, so that's OK.
if self.valid and self.non_defaults > 1:
return ["{}:{}: 'YES' is implied when a non-default CPE_ID field is specified: {} ({}#cpe-id)".format(
self.filename,
self.valid["lineno"],
self.valid["text"],
self.url_to_manual,
)]
def _check_field(self, lineno, text, field, var, val):
if field == "VERSION" and self.CPE_fields_defaults[field] is None:
return ["{}:{}: expecting package version to be set before CPE_ID_VERSION".format(
self.filename,
lineno,
)]
if val == self.CPE_fields_defaults[field]:
return ["{}:{}: '{}' is the default value for {} ({}#cpe-id)".format(
self.filename,
lineno,
val,
var,
self.url_to_manual,
)]
else:
if field == "VALID":
self.valid = {"lineno": lineno, "text": text}
self.non_defaults += 1