[ssci] Check CPE metadata field for both 2.3 and 2.2 formats

Bug: b:277147404
Change-Id: Ib817f374b8a33ab7463d93ccef7ad852b16dd9d1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4834898
Reviewed-by: Rachael Newitt <renewitt@google.com>
Commit-Queue: Anne Redulla <aredulla@google.com>
changes/98/4834898/3
Anne Redulla 2 years ago committed by LUCI CQ
parent e7c4e2ade9
commit 693e0b3121

@ -19,7 +19,46 @@ import metadata.fields.field_types as field_types
import metadata.fields.util as util
import metadata.validation_result as vr
_PATTERN_CPE_PREFIX = re.compile(r"^cpe:(2.3:|/).+:.+:.+(:.+)*$", re.IGNORECASE)
# Pattern for CPE 2.3 URI binding (also compatible with CPE 2.2).
_PATTERN_CPE_URI = re.compile(
r"^c[pP][eE]:/[AHOaho]?(:[A-Za-z0-9._\-~%]*){0,6}$")
# Pattern that will match CPE 2.3 formatted string binding.
_PATTERN_CPE_FORMATTED_STRING = re.compile(r"^cpe:2\.3:[aho\-\*](:[^:]+){10}$")
def is_uri_cpe(value: str) -> bool:
"""Returns whether the value conforms to the CPE 2.3 URI binding (which is
compatible with CPE 2.2), with the additional constraint that at least one
component other than "part" has been specified.
For reference, see section 6.1 of the CPE Naming Specification Version 2.3 at
https://nvlpubs.nist.gov/nistpubs/Legacy/IR/nistir7695.pdf
"""
if not util.matches(_PATTERN_CPE_URI, value):
return False
components = value.split(":")
if len(components) < 3:
# At most, only part was provided.
return False
# Check at least one component other than "part" has been specified.
for component in components[2:]:
if component:
return True
return False
def is_formatted_string_cpe(value: str) -> bool:
"""Returns whether the value conforms to the CPE 2.3 formatted string
binding.
For reference, see section 6.2 of the CPE Naming Specification Version 2.3 at
https://nvlpubs.nist.gov/nistpubs/Legacy/IR/nistir7695.pdf
"""
return util.matches(_PATTERN_CPE_FORMATTED_STRING, value)
class CPEPrefixField(field_types.MetadataField):
@ -31,7 +70,8 @@ class CPEPrefixField(field_types.MetadataField):
"""Checks the given value is either 'unknown', or conforms to either the
CPE 2.3 or 2.2 format.
"""
if util.is_unknown(value) or util.matches(_PATTERN_CPE_PREFIX, value):
if (util.is_unknown(value) or is_formatted_string_cpe(value)
or is_uri_cpe(value)):
return None
return vr.ValidationError(
@ -40,4 +80,5 @@ class CPEPrefixField(field_types.MetadataField):
"This field should be a CPE (version 2.3 or 2.2), or 'unknown'.",
"Search for a CPE tag for the package at "
"https://nvd.nist.gov/products/cpe/search.",
f"Current value: '{value}'.",
])

@ -28,13 +28,13 @@ class FieldValidationTest(unittest.TestCase):
warning_values: List[str] = []):
"""Helper to run a field's validation for different values."""
for value in valid_values:
self.assertIsNone(field.validate(value))
self.assertIsNone(field.validate(value), value)
for value in error_values:
self.assertIsInstance(field.validate(value), vr.ValidationError)
self.assertIsInstance(field.validate(value), vr.ValidationError, value)
for value in warning_values:
self.assertIsInstance(field.validate(value), vr.ValidationWarning)
self.assertIsInstance(field.validate(value), vr.ValidationWarning, value)
def test_freeform_text_validation(self):
# Check validation of a freeform text field that should be on one line.
@ -71,12 +71,21 @@ class FieldValidationTest(unittest.TestCase):
field=known_fields.CPE_PREFIX,
valid_values=[
"unknown",
"Cpe:2.3:a:sqlite:sqlite:3.0.0",
"cpe:2.3:a:sqlite:sqlite",
"CPE:/a:sqlite:sqlite:3.0.0",
"cpe:/a:sqlite:sqlite",
"cpe:2.3:a:sqlite:sqlite:3.0.0:*:*:*:*:*:*:*",
"cpe:2.3:a:sqlite:sqlite:*:*:*:*:*:*:*:*",
"cpe:/a:vendor:product:version:update:edition:lang",
"cpe:/a::product:",
"cpe:/:vendor::::edition",
"cpe:/:vendor",
],
error_values=[
"",
"\n",
"cpe:2.3:a:sqlite:sqlite:3.0.0",
"cpe:2.3:a:sqlite:sqlite::::::::",
"cpe:/",
"cpe:/a:vendor:product:version:update:edition:lang:",
],
error_values=["", "\n"],
)
def test_date_validation(self):

Loading…
Cancel
Save