diff --git a/cvelib/common.py b/cvelib/common.py index 8e4c5a1..023173f 100644 --- a/cvelib/common.py +++ b/cvelib/common.py @@ -95,6 +95,16 @@ r"^[a-z0-9+.-]{1,%(software_len)d}$" % ({"software_len": _patLengths["pkg-software"]}) ), + # foo, foo1, foo-bar, foo.bar, for-bar-1.0, foo_bar + "pkg-modifier": re.compile( + r"^[a-z0-9+._-]{1,%(modifier_len)d}$" + % ({"modifier_len": _patLengths["pkg-modifier"]}) + ), + # foo, foo1, foo-bar, foo.bar, for-bar-1.0 + "pkg-modifier-ubuntu": re.compile( + r"^[a-z0-9+.-]{1,%(modifier_len)d}$" + % ({"modifier_len": _patLengths["pkg-modifier"]}) + ), # add others distros and build artifacts (oci, etc) as desired "pkg-product": re.compile( r"^(upstream|%s)$" @@ -116,7 +126,7 @@ ), # the string form "pkg-full": re.compile( - r"^(upstream|%(products)s)(/[a-z0-9+.-]{1,%(where_len)d})?_[a-zA-Z0-9+._-]{1,%(software_len)d}(/[a-z0-9+.-]{1,%(modifier_len)d})?: (needs-triage|needed|pending|released|deferred|ignored|DNE|not-affected)( \([a-zA-Z0-9 +.,/'\":~\[\]_()<>#=|`-]{1,%(when_len)d}\))?$" + r"^(upstream|%(products)s)(/[a-z0-9+.-]{1,%(where_len)d})?_[a-zA-Z0-9+._-]{1,%(software_len)d}(/[a-z0-9+._-]{1,%(modifier_len)d})?: (needs-triage|needed|pending|released|deferred|ignored|DNE|not-affected)( \([a-zA-Z0-9 +.,/'\":~\[\]_()<>#=|`-]{1,%(when_len)d}\))?$" % ( { "products": "|".join( @@ -241,7 +251,7 @@ ), # TODO: reuse product/where "pkg-tags-key": re.compile( - r"^Tags_[a-zA-Z0-9+.-][a-zA-Z0-9+._-]{0,%(software_len1)d}[a-zA-Z0-9+.-](/[a-z0-9+.-]{1,%(software_len2)d})?$" + r"^Tags_[a-zA-Z0-9+.-][a-zA-Z0-9+._-]{0,%(software_len1)d}[a-zA-Z0-9+.-](/[a-z0-9+._-]{1,%(software_len2)d})?$" % ( { "software_len1": _patLengths["pkg-software"] - 2, @@ -254,7 +264,7 @@ % ({"software_len": _patLengths["pkg-software"]}) ), "pkg-priority-key": re.compile( - r"^Priority_[a-zA-Z0-9+.-][a-zA-Z0-9+._-]{0,%(software_len1)d}[a-zA-Z0-9+.-](/[a-z0-9+.-]{1,%(software_len2)d})?$" + r"^Priority_[a-zA-Z0-9+.-][a-zA-Z0-9+._-]{0,%(software_len1)d}[a-zA-Z0-9+.-](/[a-z0-9+._-]{1,%(software_len2)d})?$" % ( { "software_len1": _patLengths["pkg-software"] - 2, diff --git a/cvelib/pkg.py b/cvelib/pkg.py index 228480c..4b0f8d6 100644 --- a/cvelib/pkg.py +++ b/cvelib/pkg.py @@ -124,9 +124,9 @@ def setModifier(self, modifier: str) -> None: if len(modifier) > _patLengths["pkg-modifier"]: raise CveException("invalid modifier '%s'" % modifier) if self.compatUbuntu: - if not rePatterns["pkg-software-ubuntu"].search(modifier): + if not rePatterns["pkg-modifier-ubuntu"].search(modifier): raise CveException("invalid compat modifier '%s'" % modifier) - elif not rePatterns["pkg-software"].search(modifier): + elif not rePatterns["pkg-modifier"].search(modifier): raise CveException("invalid modifier '%s'" % modifier) self.modifier = modifier @@ -226,7 +226,6 @@ def parse(s: str, compatUbuntu: bool = False) -> CvePkg: else: product = product_where - # compatUbuntu allows foo_bar/baz, otherwise allow foo/bar/baz if "/" in software_mod: software, modifier = software_mod.split("/") else: diff --git a/extras/vim/syntax/cve.vim b/extras/vim/syntax/cve.vim index bc062f9..386dd57 100644 --- a/extras/vim/syntax/cve.vim +++ b/extras/vim/syntax/cve.vim @@ -57,19 +57,19 @@ syn match cveScanReportsValue contained /^ \(- type: oci\| \(component\|detecte syn match cveKey "^\%(Candidate\|OpenDate\|PublicDate\|CRD\|References\|Description\|GitHub-Advanced-Security\|Scan-Reports\|Notes\|Mitigation\|CVSS\|Bugs\|Discovered-by\|Assigned-to\): *" " CloseDate[_[/]]: -syn match cveCloseDateKey "^CloseDate\(_[a-zA-Z0-9][a-zA-Z0-9+._-]\+\(/[a-z0-9+.-]\+\)\?\)\?: *" +syn match cveCloseDateKey "^CloseDate\(_[a-zA-Z0-9][a-zA-Z0-9+._-]\+\(/[a-z0-9+._-]\+\)\?\)\?: *" " Priority[_[/]]: -syn match cvePriorityKey "^Priority\(_[a-zA-Z0-9][a-zA-Z0-9+._-]\+\(/[a-z0-9+.-]\+\)\?\)\?: *" +syn match cvePriorityKey "^Priority\(_[a-zA-Z0-9][a-zA-Z0-9+._-]\+\(/[a-z0-9+._-]\+\)\?\)\?: *" " Patches_: syn match cvePatchesKey "^Patches_[a-zA-Z0-9][a-zA-Z0-9+._-]\+: *" " Tags_[/]: -syn match cveTagKey "^Tags_[a-zA-Z0-9][a-zA-Z0-9+._-]\+\(/[a-z0-9+.-]\+\)\?: *" +syn match cveTagKey "^Tags_[a-zA-Z0-9][a-zA-Z0-9+._-]\+\(/[a-z0-9+._-]\+\)\?: *" " [/]_[/]: -syn match cveProductKey "^\%(upstream\|bzr\|cvs\|git\|hg\|svn\|appimage\|archive\|deb\|dmg\|exe\|flatpak\|oci\|rpm\|shell\|snap\|alpine\|android\|centos\|debian\|distroless\|flatcar\|ios\|opensuse\|osx\|rhel\|suse\|ubuntu\|windows\)\(/[a-z0-9+.-]\+\)\?_[a-zA-Z0-9][a-zA-Z0-9+._-]\+\(/[a-z0-9+.-]\+\)\?: *" +syn match cveProductKey "^\%(upstream\|bzr\|cvs\|git\|hg\|svn\|appimage\|archive\|deb\|dmg\|exe\|flatpak\|oci\|rpm\|shell\|snap\|alpine\|android\|centos\|debian\|distroless\|flatcar\|ios\|opensuse\|osx\|rhel\|suse\|ubuntu\|windows\)\(/[a-z0-9+.-]\+\)\?_[a-zA-Z0-9][a-zA-Z0-9+._-]\+\(/[a-z0-9+._-]\+\)\?: *" " diff --git a/tests/test_cve.py b/tests/test_cve.py index 9317c1e..7fc13fb 100644 --- a/tests/test_cve.py +++ b/tests/test_cve.py @@ -837,18 +837,30 @@ def test_setData(self): hdrs = self._mockHeaders(t) cvelib.cve.CVE().setData(hdrs) - # valid Tags_foo_bar ('_' in name) + # valid Tags_foo/bar ('_' in modifier) + t = self._cve_template() + t["Tags_foo/bar"] = "apparmor" + hdrs = self._mockHeaders(t) + cvelib.cve.CVE().setData(hdrs) + + # valid Tags_foo_bar ('_' in software) t = self._cve_template() t["Tags_foo_bar"] = "apparmor pie" hdrs = self._mockHeaders(t) cvelib.cve.CVE().setData(hdrs) - # valid Tags_foo_bar/baz ('_' in name) + # valid Tags_foo_bar/baz ('_' in software) t = self._cve_template() t["Tags_foo_bar/baz"] = "apparmor pie" hdrs = self._mockHeaders(t) cvelib.cve.CVE().setData(hdrs) + # valid Tags_foo_bar/baz ('_' in software and modifier) + t = self._cve_template() + t["Tags_foo_bar/baz_norf"] = "apparmor pie" + hdrs = self._mockHeaders(t) + cvelib.cve.CVE().setData(hdrs) + # valid Priority_foo t = self._cve_template() t["Priority_foo"] = "medium" @@ -867,18 +879,30 @@ def test_setData(self): hdrs = self._mockHeaders(t) cvelib.cve.CVE().setData(hdrs) - # valid Priority_foo_bar ('_' in name) + # valid Priority_foo/bar_baz ('_' in modifier) + t = self._cve_template() + t["Priority_foo/bar_baz"] = "medium" + hdrs = self._mockHeaders(t) + cvelib.cve.CVE().setData(hdrs) + + # valid Priority_foo_bar ('_' in software) t = self._cve_template() t["Priority_foo_bar"] = "medium" hdrs = self._mockHeaders(t) cvelib.cve.CVE().setData(hdrs) - # valid Priority_foo_bar/baz ('_' in name) + # valid Priority_foo_bar/baz ('_' in software) t = self._cve_template() t["Priority_foo_bar/baz"] = "medium" hdrs = self._mockHeaders(t) cvelib.cve.CVE().setData(hdrs) + # valid Priority_foo_bar/baz ('_' in software and modifier) + t = self._cve_template() + t["Priority_foo_bar/baz_norf"] = "medium" + hdrs = self._mockHeaders(t) + cvelib.cve.CVE().setData(hdrs) + # invalid hdrs = self._mockHeaders(self._cve_template()) del hdrs["Candidate"] @@ -997,7 +1021,13 @@ def test_setDataPriorityKeys(self): ("Priority_foo", False, True), ("Priority_%s" % ("a" * 50), False, True), ("Priority_foo_bar", False, True), # non-compat allows '_' in software + ("Priority_foo/bar_baz", False, True), # non-compat allows '_' in modifier ("Priority_foo_bar/baz", False, True), + ( + "Priority_foo_bar/baz_norf", + False, + True, + ), # non-compat allows '_' in modifier ("Priority_%s/foo" % ("a" * 50), False, True), ("Priority_foo/%s" % ("a" * 50), False, True), ("Priority_FOO", False, True), @@ -1023,6 +1053,7 @@ def test_setDataPriorityKeys(self): ("Priority_foo_%s" % ("a" * 51), True, False), ("Priority_foo/bar", True, False), ("Priority_foo_bar_baz", True, False), + ("Priority_foo_precise/esm_bad", True, False), ("Priority_FOO", True, False), ] for key, compat, valid in tsts: diff --git a/tests/test_pkg.py b/tests/test_pkg.py index acfe344..dfbbf5f 100644 --- a/tests/test_pkg.py +++ b/tests/test_pkg.py @@ -256,13 +256,22 @@ def test_setModifier(self): tsts = [ # valid ("foo", True, False), + ("foo1", True, False), + ("foo-bar", True, False), + ("foo.bar", True, False), + ("for-bar-1.0", True, False), ("foo_bar", True, False), ("a" * 40, True, False), # valid compat ("foo", True, True), + ("foo1", True, True), + ("foo-bar", True, True), + ("foo.bar", True, True), + ("for-bar-1.0", True, True), ("a" * 40, True, True), # invalid ("b@d", False, False), + ("FOO", False, False), ("foo ", False, False), (" foo ", False, False), ("a" * 41, False, False), @@ -621,6 +630,7 @@ def test_parse(self): ("alpine/3.16_foo: needed (123-4)", False, True), ("debian/buster_foo: needed (123-4)", False, True), ("debian/buster_foo/bar: needed (123-4)", False, True), + ("debian/buster_foo/bar_baz: needed (123-4)", False, True), ("ubuntu/focal_foo: needed", False, True), ( "ubuntu/trusty_gcc-snapshot: DNE (trusty was not-affected 20140405-0ubuntu1)", @@ -738,6 +748,7 @@ def test_parse(self): ("focal_foo/%s: needed" % ("a" * 40), False, False), ("focal_foo: needed (%s)" % ("a" * 101), True, False), ("upstream_foo_bar: needed (123-4)", True, False), + ("upstream_foo/bar_baz: needed (123-4)", True, False), ("upstream_FOO: needed", True, False), ("upstream_foo-BAR: needed", True, False), ("upstream/foo: needed", True, False),