The idea is good but this really needs a test suite.  If the class is
added to a new file meta/lib/oe/cvecheck.py or similar then you can
add a test suite too.

Ross

On Thu, 21 Jan 2021 at 02:26, Lee Chee Yang <[email protected]> wrote:
>
> From: Lee Chee Yang <[email protected]>
>
> The way distutils.version.LooseVersion compare version are tricky, it treat
> all these ( "1.0-beta2", "1.0-rc1", "1.0A", "1.0p2" and "1.0pre1") as greater
> version than "1.0". This might be right for "1.0A" and "1.0p1" but not for
> the rest, also these version could be confusing, the "p" in "1.0p1" can be
> "pre" or "patched" version or even other meaning.
>
> replace Looseversion with custom class, it uses regex to capture common
> version format like "1.1.1" or tag format using date like "2020-12-12" as
> release section, check for following known string/label (beta, rc, pre, dev,
> alpha, preview) as pre-release section, any other trailing characters
> are difficult to understand and define so dont consider these when
> comparing. compare release section and pre-release section saperately.
>
> [YOCTO#14127]
>
> Signed-off-by: Lee Chee Yang <[email protected]>
> ---
>  meta/classes/cve-check.bbclass | 55 ++++++++++++++++++++++++++++++----
>  1 file changed, 50 insertions(+), 5 deletions(-)
>
> diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
> index d843e7c4ac..b119353781 100644
> --- a/meta/classes/cve-check.bbclass
> +++ b/meta/classes/cve-check.bbclass
> @@ -206,7 +206,52 @@ def check_cves(d, patched_cves):
>      """
>      Connect to the NVD database and find unpatched cves.
>      """
> -    from distutils.version import LooseVersion
> +    import collections, re, itertools
> +
> +    _Version = collections.namedtuple(
> +        "_Version", ["release", "pre_l", "pre_v"]
> +    )
> +
> +    class Version():
> +        _version_pattern =  
> r"""v?(?:(?P<release>[0-9]+(?:[-\.][0-9]+)*)(?P<pre>[-_\.]?(?P<pre_l>(rc|alpha|beta|pre|preview|dev))[-_\.]?(?P<pre_v>[0-9]+)?)?)(.*)?"""
> +        _regex = re.compile(r"^\s*" + _version_pattern + r"\s*$", re.VERBOSE 
> | re.IGNORECASE)
> +        def __init__(self, version):
> +            match = self._regex.search(version)
> +            if not match:
> +                raise Exception("Invalid version: '{0}'".format(version))
> +
> +            self._version = _Version(
> +                release=tuple(int(i) for i in 
> match.group("release").replace("-",".").split(".")),
> +                pre_l=match.group("pre_l"),
> +                pre_v=match.group("pre_v")
> +            )
> +
> +            self._key = _cmpkey(
> +                self._version.release,
> +                self._version.pre_l,
> +                self._version.pre_v
> +            )
> +
> +        def __ge__(self, other):
> +            if not isinstance(other, Version):
> +                return NotImplemented
> +            return self._key >= other._key
> +
> +        def __gt__(self, other):
> +            if not isinstance(other, Version):
> +                return NotImplemented
> +            return self._key > other._key
> +
> +    def _cmpkey(release, pre_l, pre_v):
> +        # remove leading 0
> +        _release = tuple(
> +            reversed(list(itertools.dropwhile(lambda x: x == 0, 
> reversed(release))))
> +        )
> +        if pre_l is None and pre_v is None:
> +            _pre = float('inf')
> +        else:
> +            _pre = float(pre_v) if pre_v else float('-inf')
> +        return _release, _pre
>
>      pn = d.getVar("PN")
>      real_pv = d.getVar("PV")
> @@ -263,8 +308,8 @@ def check_cves(d, patched_cves):
>                  else:
>                      if operator_start:
>                          try:
> -                            vulnerable_start =  (operator_start == '>=' and 
> LooseVersion(pv) >= LooseVersion(version_start))
> -                            vulnerable_start |= (operator_start == '>' and 
> LooseVersion(pv) > LooseVersion(version_start))
> +                            vulnerable_start =  (operator_start == '>=' and 
> Version(pv) >= Version(version_start))
> +                            vulnerable_start |= (operator_start == '>' and 
> Version(pv) > Version(version_start))
>                          except:
>                              bb.warn("%s: Failed to compare %s %s %s for %s" %
>                                      (product, pv, operator_start, 
> version_start, cve))
> @@ -274,8 +319,8 @@ def check_cves(d, patched_cves):
>
>                      if operator_end:
>                          try:
> -                            vulnerable_end  = (operator_end == '<=' and 
> LooseVersion(pv) <= LooseVersion(version_end))
> -                            vulnerable_end |= (operator_end == '<' and 
> LooseVersion(pv) < LooseVersion(version_end))
> +                            vulnerable_end  = (operator_end == '<=' and 
> Version(version_end) >= Version(pv))
> +                            vulnerable_end |= (operator_end == '<' and 
> Version(version_end) > Version(pv) )
>                          except:
>                              bb.warn("%s: Failed to compare %s %s %s for %s" %
>                                      (product, pv, operator_end, version_end, 
> cve))
> --
> 2.17.1
>
>
> 
>
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#147059): 
https://lists.openembedded.org/g/openembedded-core/message/147059
Mute This Topic: https://lists.openembedded.org/mt/79995299/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to