def test_distromappings(anchore_db): _init_distro_mappings() c7 = DistroNamespace(name='centos', version='7', like_distro='centos') assert c7.mapped_names() == [] assert c7.like_namespace_names == ['rhel:7'] r7 = DistroNamespace(name='rhel', version='7', like_distro='centos') assert set(r7.mapped_names()) == {'centos', 'fedora', 'rhel'} assert r7.like_namespace_names == ['rhel:7'] assert sorted(DistroMapping.distros_mapped_to('rhel', '7')) == sorted([ DistroTuple('rhel', '7', 'RHEL'), DistroTuple('centos', '7', 'RHEL'), DistroTuple('fedora', '7', 'RHEL') ])
def find_vulnerable_image_packages(vulnerability_obj): """ Given a vulnerability object, find images that are affected via their package manifests. Result may have duplicates based on match type, caller must de-dup if desired. :param vulnerability_obj: :return: list of ImagePackage objects """ db = get_thread_scoped_session() distro, version = vulnerability_obj.namespace_name.split(":", 1) dist = DistroNamespace(distro, version) related_names = ( dist.mapped_names() ) # Returns list of names that map to this one, not including itself necessarily # related_names = get_namespace_related_names(distro, version, mapped_names) # TODO would like a better way to do the pkg_type <-> namespace_name mapping, with other side in ImagePackage.vulnerabilities_for_package likematch = None if (":maven" in vulnerability_obj.namespace_name or "java" in vulnerability_obj.namespace_name): likematch = "java" elif (":ruby" in vulnerability_obj.namespace_name or "gem" in vulnerability_obj.namespace_name): likematch = "gem" elif (":js" in vulnerability_obj.namespace_name or "npm" in vulnerability_obj.namespace_name): likematch = "npm" elif "python" in vulnerability_obj.namespace_name: likematch = "python" try: affected = [] if vulnerability_obj.fixed_in: # Check the fixed_in records for fix_rec in vulnerability_obj.fixed_in: package_candidates = [] # Find packages of related distro names with compatible versions, this does not have to be precise, just an initial filter. pkgs = (db.query(ImagePackage).filter( ImagePackage.distro_name.in_(related_names), ImagePackage.distro_version.like(dist.version + "%"), or_( ImagePackage.name == fix_rec.name, ImagePackage.normalized_src_pkg == fix_rec.name, ), ).all()) package_candidates += pkgs # add non distro candidates if likematch: pkgs = (db.query(ImagePackage).filter( ImagePackage.pkg_type.in_(nonos_package_types), ImagePackage.pkg_type.like(likematch), or_( ImagePackage.name == fix_rec.name, ImagePackage.normalized_src_pkg == fix_rec.name, ), ).all()) package_candidates += pkgs for candidate in package_candidates: if fix_rec.match_but_not_fixed(candidate): affected.append(candidate) if vulnerability_obj.vulnerable_in: # Check the vulnerable_in records for vuln_rec in vulnerability_obj.vulnerable_in: package_candidates = [] # Find packages of related distro names with compatible versions, this does not have to be precise, just an initial filter. pkgs = (db.query(ImagePackage).filter( ImagePackage.distro_name.in_(related_names), ImagePackage.distro_version.like(dist.version + "%"), or_( ImagePackage.name == vuln_rec.name, ImagePackage.normalized_src_pkg == vuln_rec.name, ), ).all()) package_candidates += pkgs for candidate in package_candidates: if vuln_rec.match_and_vulnerable(candidate): affected.append(candidate) return affected except Exception as e: logger.exception( "Failed to query and find packages affected by vulnerability: {}". format(vulnerability_obj)) raise
def find_vulnerable_image_packages(vulnerability_obj): """ Given a vulnerability object, find images that are affected via their package manifests. Result may have duplicates based on match type, caller must de-dup if desired. :param vulnerability_obj: :return: list of ImagePackage objects """ db = get_thread_scoped_session() distro, version = vulnerability_obj.namespace_name.split(':', 1) dist = DistroNamespace(distro, version) related_names = dist.mapped_names() # Returns list of names that map to this one, not including itself necessarily # Filter related_names down based on the presence of actual feeds/cve data. If there is an actual feed for a name, remove it from the list. # Only do this if the list of related names is not just the name itself. (e.g. alpine = [alpine]). if related_names != [distro]: # Ensure we don't include any names that actually have a feed (can happen when new feeds arrive before the mapped_names() source # is updated to break the 'like' relation between the distros. related_names = [x for x in related_names if namespace_has_no_feed(x, version)] # This is a weird case because it basically means that this distro doesn't map to itself as far as mapped_names() is # concerned, but since that could be code lagging data (e.g. new feed group added for a new distro), add the name itself # back into the list. if distro not in related_names and not namespace_has_no_feed(distro, version): related_names.append(distro) # TODO would like a better way to do the pkg_type <-> namespace_name mapping, with other side in ImagePackage.vulnerabilities_for_package likematch = None if ':maven' in vulnerability_obj.namespace_name or 'java' in vulnerability_obj.namespace_name: likematch = 'java' elif ':ruby' in vulnerability_obj.namespace_name or 'gem' in vulnerability_obj.namespace_name: likematch = 'gem' elif ':js' in vulnerability_obj.namespace_name or 'npm' in vulnerability_obj.namespace_name: likematch = 'npm' elif 'python' in vulnerability_obj.namespace_name: likematch = 'python' try: affected = [] if vulnerability_obj.fixed_in: # Check the fixed_in records for fix_rec in vulnerability_obj.fixed_in: package_candidates = [] # Find packages of related distro names with compatible versions, this does not have to be precise, just an initial filter. pkgs = db.query(ImagePackage).filter(ImagePackage.distro_name.in_(related_names), ImagePackage.distro_version.like(dist.version + '%'), or_(ImagePackage.name == fix_rec.name, ImagePackage.normalized_src_pkg == fix_rec.name)).all() package_candidates += pkgs # add non distro candidates if likematch: pkgs = db.query(ImagePackage).filter(ImagePackage.pkg_type.in_(nonos_package_types), ImagePackage.pkg_type.like(likematch), or_(ImagePackage.name == fix_rec.name, ImagePackage.normalized_src_pkg == fix_rec.name)).all() package_candidates += pkgs for candidate in package_candidates: if fix_rec.match_but_not_fixed(candidate): affected.append(candidate) # if vulnerability_obj.vulnerable_in: # # Check the vulnerable_in records # for vuln_rec in vulnerability_obj.vulnerable_in: # package_candidates = [] # # Find packages of related distro names with compatible versions, this does not have to be precise, just an initial filter. # pkgs = db.query(ImagePackage).filter(ImagePackage.distro_name.in_(related_names), # ImagePackage.distro_version.like(dist.version + '%'), # or_(ImagePackage.name == fix_rec.name, # ImagePackage.normalized_src_pkg == fix_rec.name)).all() # package_candidates += pkgs # for candidate in package_candidates: # if vuln_rec.match_and_vulnerable(candidate): # affected.append(candidate) return affected except Exception as e: log.exception('Failed to query and find packages affected by vulnerability: {}'.format(vulnerability_obj)) raise