Пример #1
0
    def test_empty_specifier(self, version):
        spec = SpecifierSet(prereleases=True)

        assert version in spec
        assert spec.contains(version)
        assert parse(version) in spec
        assert spec.contains(parse(version))
Пример #2
0
    def test_specifier_contains_prereleases(self):
        spec = SpecifierSet()
        assert spec.prereleases is None
        assert not spec.contains("1.0.dev1")
        assert spec.contains("1.0.dev1", prereleases=True)

        spec = SpecifierSet(prereleases=True)
        assert spec.prereleases
        assert spec.contains("1.0.dev1")
        assert not spec.contains("1.0.dev1", prereleases=False)
Пример #3
0
    def test_specifier_contains_prereleases(self):
        spec = SpecifierSet()
        assert spec.prereleases is None
        assert not spec.contains("1.0.dev1")
        assert spec.contains("1.0.dev1", prereleases=True)

        spec = SpecifierSet(prereleases=True)
        assert spec.prereleases
        assert spec.contains("1.0.dev1")
        assert not spec.contains("1.0.dev1", prereleases=False)
Пример #4
0
    def check_if_package_is_vulnerable(
        self,
        dependency: Dependency,
    ) -> Optional[Vulnerability]:
        """Check if the specified dependency has a vulnerability reported."""
        if not self.data:
            raise VerificationError(
                "Cannot check vulnerability status, error when downloading database"
            )

        database_entry = self.data.get(dependency.name)
        if database_entry is None:
            return None

        for vulnerability_entry in database_entry:
            constraint = vulnerability_entry["v"]
            specifier_set = SpecifierSet(constraint)

            if specifier_set.contains(dependency.version):
                return Vulnerability(
                    advisory=vulnerability_entry["advisory"],
                    cve=vulnerability_entry.get("cve"),
                    versions_impacted=constraint,
                )

        return None
Пример #5
0
def check():
    db = fetch_database()
    db_full = None
    packages = frozenset(db.keys())
    vulnerable = []
    for pkg in pip.get_installed_distributions():
        # normalize the package name, the safety-db is converting underscores to dashes and uses
        # lowercase
        name = pkg.key.replace("_", "-").lower()

        if name in packages:
            # we have a candidate here, build the spec set
            for specifier in db[name]:
                spec_set = SpecifierSet(specifiers=specifier)
                if spec_set.contains(pkg.version):
                    if not db_full:
                        db_full = fetch_database(full=True)
                    for data in get_vulnerabilities(pkg=name,
                                                    spec=specifier,
                                                    db=db_full):
                        vulnerable.append(
                            Vulnerability(name=name,
                                          spec=specifier,
                                          version=pkg.version,
                                          data=data))
    return vulnerable
Пример #6
0
def check(packages, key, db_mirror, cached, ignore_ids):

    key = key if key else os.environ.get("SAFETY_API_KEY", False)
    db = fetch_database(key=key, db=db_mirror, cached=cached)
    db_full = None
    vulnerable_packages = frozenset(db.keys())
    vulnerable = []
    for pkg in packages:
        # normalize the package name, the safety-db is converting underscores to dashes and uses
        # lowercase
        name = pkg.key.replace("_", "-").lower()

        if name in vulnerable_packages:
            # we have a candidate here, build the spec set
            for specifier in db[name]:
                spec_set = SpecifierSet(specifiers=specifier)
                if spec_set.contains(pkg.version):
                    if not db_full:
                        db_full = fetch_database(full=True, key=key, db=db_mirror)
                    for data in get_vulnerabilities(pkg=name, spec=specifier, db=db_full):
                        vuln_id = data.get("id").replace("pyup.io-", "")
                        if vuln_id and vuln_id not in ignore_ids:
                            vulnerable.append(
                                Vulnerability(
                                    name=name,
                                    spec=specifier,
                                    version=pkg.version,
                                    advisory=data.get("advisory"),
                                    vuln_id=vuln_id
                                )
                            )
    return vulnerable
Пример #7
0
def check(packages, key, db_mirror, cached):

    db = fetch_database(key=key, db=db_mirror, cached=cached)
    db_full = None
    vulnerable_packages = frozenset(db.keys())
    vulnerable = []
    found_ids = set()
    for pkg in packages:
        # normalize the package name, the safety-db is converting underscores to dashes and uses
        # lowercase
        name = pkg.key.replace("_", "-").lower()

        if name in vulnerable_packages:
            # we have a candidate here, build the spec set
            for specifier in db[name]:
                spec_set = SpecifierSet(specifiers=specifier)
                if spec_set.contains(pkg.version):
                    if not db_full:
                        db_full = fetch_database(full=True,
                                                 key=key,
                                                 db=db_mirror)
                    for data in get_vulnerabilities(pkg=name,
                                                    spec=specifier,
                                                    db=db_full):
                        if data.get("id") not in found_ids:
                            vulnerable.append(
                                Vulnerability(name=name,
                                              spec=specifier,
                                              version=pkg.version,
                                              advisory=data.get("advisory"),
                                              vuln_id=data.get("id")))
                            found_ids.add(data.get("id"))
    return vulnerable
Пример #8
0
def check(packages, key, db_mirror, cached, ignore_ids, proxy):
    key = key if key else os.environ.get("SAFETY_API_KEY", False)
    db = fetch_database(key=key, db=db_mirror, cached=cached, proxy=proxy)
    db_full = None
    vulnerable_packages = frozenset(db.keys())
    vulnerable = []
    for pkg in packages:
        # normalize the package name, the safety-db is converting underscores to dashes and uses
        # lowercase
        name = pkg.key.replace("_", "-").lower()

        if name in vulnerable_packages:
            # we have a candidate here, build the spec set
            for specifier in db[name]:
                spec_set = SpecifierSet(specifiers=specifier)
                if spec_set.contains(pkg.version):
                    if not db_full:
                        db_full = fetch_database(full=True,
                                                 key=key,
                                                 db=db_mirror,
                                                 cached=cached,
                                                 proxy=proxy)
                    for data in get_vulnerabilities(pkg=name,
                                                    spec=specifier,
                                                    db=db_full):
                        vuln_id = data.get("id").replace("pyup.io-", "")
                        if vuln_id and vuln_id not in ignore_ids:
                            vulnerable.append(
                                Vulnerability(name=name,
                                              spec=specifier,
                                              version=pkg.version,
                                              advisory=data.get("advisory"),
                                              vuln_id=vuln_id))
    return vulnerable
def clean_requires_python(candidates):
    """Get a cleaned list of all the candidates with valid specifiers in the `requires_python` attributes."""
    all_candidates = []
    sys_version = ".".join(map(str, sys.version_info[:3]))
    from packaging.version import parse as parse_version

    py_version = parse_version(
        os.environ.get("PIP_PYTHON_VERSION", sys_version))
    for c in candidates:
        from_location = attrgetter("location.requires_python")
        requires_python = getattr(c, "requires_python", from_location(c))
        if requires_python:
            # Old specifications had people setting this to single digits
            # which is effectively the same as '>=digit,<digit+1'
            if requires_python.isdigit():
                requires_python = ">={0},<{1}".format(requires_python,
                                                      int(requires_python) + 1)
            try:
                specifierset = SpecifierSet(requires_python)
            except InvalidSpecifier:
                continue
            else:
                if not specifierset.contains(py_version):
                    continue
        all_candidates.append(c)
    return all_candidates
Пример #10
0
 def is_insecure(self, version):
     r = requests.get(settings.API_URL)
     if r.status_code == 200:
         for spec_str in r.json()['insecure']:
             spec = SpecifierSet(spec_str)
             if spec.contains(version):
                 return True
     return False
Пример #11
0
    def test_specifier_prereleases_explicit(self):
        spec = SpecifierSet()
        assert not spec.prereleases
        assert "1.0.dev1" not in spec
        assert not spec.contains("1.0.dev1")
        spec.prereleases = True
        assert spec.prereleases
        assert "1.0.dev1" in spec
        assert spec.contains("1.0.dev1")

        spec = SpecifierSet(prereleases=True)
        assert spec.prereleases
        assert "1.0.dev1" in spec
        assert spec.contains("1.0.dev1")
        spec.prereleases = False
        assert not spec.prereleases
        assert "1.0.dev1" not in spec
        assert not spec.contains("1.0.dev1")

        spec = SpecifierSet(prereleases=True)
        assert spec.prereleases
        assert "1.0.dev1" in spec
        assert spec.contains("1.0.dev1")
        spec.prereleases = None
        assert not spec.prereleases
        assert "1.0.dev1" not in spec
        assert not spec.contains("1.0.dev1")
Пример #12
0
    def is_satisfied_by(self, installed_package):
        if not self.name == installed_package.name:
            return False

        # Any version matches
        if not self.has_version():
            return True

        specifier_str = '%s%s' % (self.operator, self.version)
        specifier = SpecifierSet(specifier_str)
        version = Version(installed_package.version)

        return specifier.contains(version)
Пример #13
0
 def get_latest_version_within_specs(specs, versions, prereleases=None):
     # build up a spec set and convert compatible specs to pinned ones
     spec_set = SpecifierSet(
         ",".join(["".join(s._spec).replace("~=", "==") for s in specs])
     )
     candidates = []
     for version in versions:
         if spec_set.contains(version, prereleases=prereleases):
             candidates.append(version)
     candidates = sorted(candidates, key=lambda v: parse_version(v), reverse=True)
     if len(candidates) > 0:
         return candidates[0]
     return None
Пример #14
0
def _check_nox_version_satisfies(needs_version: str) -> None:
    """Check if the Nox version satisfies the given specifiers."""
    version = Version(get_nox_version())

    try:
        specifiers = SpecifierSet(needs_version)
    except InvalidSpecifier as error:
        message = f"Cannot parse `nox.needs_version`: {error}"
        with contextlib.suppress(InvalidVersion):
            Version(needs_version)
            message += f", did you mean '>= {needs_version}'?"
        raise InvalidVersionSpecifier(message)

    if not specifiers.contains(version, prereleases=True):
        raise VersionCheckFailed(
            f"The Noxfile requires Nox {specifiers}, you have {version}")
Пример #15
0
def process_requirements(requirements, version=None):
    """
    Examples
    --------
    >>> process_requirements(None)
    []
    >>> process_requirements({"== 0.1": ["foo"]}, "0.1")
    ['foo']
    >>> process_requirements({"< 0.2": ["foo"]}, "0.1")
    ['foo']
    >>> process_requirements({"> 0.1, != 0.2": ["foo"]}, "0.3")
    ['foo']
    >>> process_requirements({"== 0.1": ["foo"], "== 0.2": ["bar"]}, "0.2")
    ['bar']
    >>> process_requirements({">= 0.1": ["foo"], ">= 0.2": ["bar"]}, "0.2")
    ['bar', 'foo']
    >>> process_requirements({"== dev": ["foo"]}, "0.1")
    []
    >>> process_requirements({"< dev": ["foo"]}, "0.1")
    ['foo']
    >>> process_requirements({"> 0.1": ["foo"]}, "dev")
    ['foo']
    >>> process_requirements({"== dev": ["foo"]}, "dev")
    ['foo']
    >>> process_requirements({"> 0.1, != dev": ["foo"]}, "dev")
    []
    """
    if requirements is None:
        return []

    if isinstance(requirements, list):
        return requirements

    if isinstance(requirements, dict):
        reqs = set()
        for specifier, packages in requirements.items():
            specifier_set = SpecifierSet(
                specifier.replace(DEV_VERSION, DEV_NUMERIC))
            if specifier_set.contains(DEV_NUMERIC if version ==
                                      DEV_VERSION else version):
                reqs = reqs.union(packages)
        return sorted(reqs)

    raise TypeError("Invalid object type for `requirements`: '{}'".format(
        type(requirements)))
Пример #16
0
def check(packages, key, db_mirror, cached, ignore_ids, proxy):
    key = key if key else os.environ.get("SAFETY_API_KEY", False)
    db = fetch_database(key=key, db=db_mirror, cached=cached, proxy=proxy)
    db_full = None
    vulnerable_packages = frozenset(db.keys())
    vulnerable = []
    for pkg in packages:
        # Ignore recursive files not resolved
        if isinstance(pkg, RequirementFile):
            continue

        # normalize the package name, the safety-db is converting underscores to dashes and uses
        # lowercase
        name = pkg.key.replace("_", "-").lower()

        if name in vulnerable_packages:
            # we have a candidate here, build the spec set
            for specifier in db[name]:
                spec_set = SpecifierSet(specifiers=specifier)
                if spec_set.contains(pkg.version):
                    if not db_full:
                        db_full = fetch_database(full=True, key=key, db=db_mirror, cached=cached, proxy=proxy)
                    for data in get_vulnerabilities(pkg=name, spec=specifier, db=db_full):
                        vuln_id = data.get("id").replace("pyup.io-", "")
                        cve_id = data.get("cve")
                        if cve_id:
                            cve_id = cve_id.split(",")[0].strip()
                        if vuln_id and vuln_id not in ignore_ids:
                            cve_meta = db_full.get("$meta", {}).get("cve", {}).get(cve_id, {})
                            vulnerable.append(
                                Vulnerability(
                                    name=name,
                                    spec=specifier,
                                    version=pkg.version,
                                    advisory=data.get("advisory"),
                                    vuln_id=vuln_id,
                                    cvssv2=cve_meta.get("cvssv2", None),
                                    cvssv3=cve_meta.get("cvssv3", None),
                                )
                            )
    return vulnerable
Пример #17
0
def get_all_candidates(requirement):
    session = HTMLSession()
    url = f"https://pypi.org/simple/{requirement.key}"
    resp = session.get(url)
    for a in resp.html.find('a'):
        link = a.attrs['href']
        python_requires = a.attrs.get('data-requires-python')
        filename = a.text

        if python_requires:
            spec = SpecifierSet(python_requires)
            if not spec.contains(PYTHON_VERSION):
                # Discard candidates that don't match the Python version.
                continue

        if not filename.endswith(".whl"):
            # Only parse wheels for this demo
            continue
        name, version = filename.split("-")[:2]
        if requirement.specifier.contains(version):
            yield Candidate(name, version, link)
Пример #18
0
    def _match_node_at_path(self, key: str, metadata):

        # Grab any tags prepended to key
        tags = key.split(":")

        # Take anything following the last semicolon as the path to the node
        path = tags.pop()

        # Set our default matching rules for each key
        nulls_match = self.nulls_match

        # Interpret matching rules in tags
        if tags:
            for tag in tags:
                if tag == "not-null":
                    nulls_match = False
                if tag == "match-null":
                    nulls_match = True

        # Get value (List) of node using dotted path given by key
        node = self._find_element_by_dotted_path(path, metadata)

        # Check for null matching
        if nulls_match and not node:
            return True

        # Check if SpeciferSet matches target versions
        # TODO: Figure out proper intersection of SpecifierSets
        ospecs = SpecifierSet(node)
        ispecs = self.specifiers[key]
        if any(ospecs.contains(ispec, prereleases=True) for ispec in ispecs):
            return True
        # Otherwise, fail
        logger.info(
            f"Failed check for {key}='{ospecs}' against '{ispecs}'"  # noqa: E501
        )
        return False
Пример #19
0
 def test_legacy_specifiers_combined(self):
     spec = SpecifierSet("<3,>1-1-1")
     assert spec.contains("2.0")
Пример #20
0
 def test_legacy_specifiers_combined(self):
     spec = SpecifierSet("<3,>1-1-1")
     assert spec.contains("2.0")
Пример #21
0
    def test_empty_specifier(self, version):
        spec = SpecifierSet(prereleases=True)

        assert spec.contains(version)
        assert spec.contains(parse(version))
Пример #22
0
def check(packages,
          key=False,
          db_mirror=False,
          cached=0,
          ignore_vulns=None,
          ignore_severity_rules=None,
          proxy=None,
          include_ignored=False,
          is_env_scan=True,
          telemetry=True,
          params=None):
    SafetyContext().command = 'check'
    db = fetch_database(key=key,
                        db=db_mirror,
                        cached=cached,
                        proxy=proxy,
                        telemetry=telemetry)
    db_full = None
    vulnerable_packages = frozenset(db.keys())
    vulnerabilities = []

    for pkg in packages:
        # Ignore recursive files not resolved
        if isinstance(pkg, RequirementFile):
            continue

        # normalize the package name, the safety-db is converting underscores to dashes and uses
        # lowercase
        name = canonicalize_name(pkg.name)

        if name in vulnerable_packages:
            # we have a candidate here, build the spec set
            for specifier in db[name]:
                spec_set = SpecifierSet(specifiers=specifier)
                if spec_set.contains(pkg.version):
                    if not db_full:
                        db_full = fetch_database(full=True,
                                                 key=key,
                                                 db=db_mirror,
                                                 cached=cached,
                                                 proxy=proxy,
                                                 telemetry=telemetry)
                    for data in get_vulnerabilities(pkg=name,
                                                    spec=specifier,
                                                    db=db_full):
                        vuln_id = data.get("id").replace("pyup.io-", "")
                        cve = get_cve_from(data, db_full)

                        ignore_vuln_if_needed(vuln_id, cve, ignore_vulns,
                                              ignore_severity_rules)

                        vulnerability = get_vulnerability_from(
                            vuln_id, cve, data, specifier, db, name, pkg,
                            ignore_vulns)

                        should_add_vuln = not (vulnerability.is_transitive
                                               and is_env_scan)

                        if (include_ignored or vulnerability.vulnerability_id
                                not in ignore_vulns) and should_add_vuln:
                            vulnerabilities.append(vulnerability)

    return vulnerabilities, db_full
Пример #23
0
 def version_matches(self, requirement):
     specifier_set = SpecifierSet(requirement.specifiers)
     return specifier_set.contains(self.package_version)