def get_vulnerable_packages(vulnerability_list): """ Run the pipeline for updating image vulnerabilities on the specified list of new/updated/removed records. :param vulnerability_list: a list of vulnerability update events :return: list of image ids that were modified """ vulnerability_events_by_namespace = {} affected = [] for event in vulnerability_list: if event['namespace'] not in vulnerability_events_by_namespace: vulnerability_events_by_namespace[event['namespace']] = [] vulnerability_events_by_namespace[event['namespace']].append(event) db = get_thread_scoped_session() for namespace, vulns in vulnerability_events_by_namespace.items(): for vuln in vulns: packages = find_vulnerable_image_packages(vuln) for pkg in packages: img_pkg_v = ImagePackageVulnerability.from_pair(pkg, vuln) img_pkg_v = db.merge(img_pkg_v) affected.append(img_pkg_v) return affected
def process_updated_vulnerability(db, vulnerability): """ Update vulnerability matches for this vulnerability. This function will add objects to the db session but will not commit. The caller is expected to manage the session lifecycle. :param: item: The updated vulnerability object :param: db: The db session to use, should be valid and open :return: list of (user_id, image_id) that were affected """ log.spew('Processing CVE update for: {}'.format(vulnerability.id)) changed_images = [] # Find any packages already matched with the CVE ID. current_affected = vulnerability.current_package_vulnerabilities(db) # May need to remove vuln from some packages. if vulnerability.is_empty(): log.spew('Detected an empty CVE. Removing all existing matches on this CVE') # This is a flush, nothing can be vulnerable to this, so remove it from packages. if current_affected: log.debug('Detected {} existing matches on CVE {} to remove'.format(len(current_affected), vulnerability.id)) for pkgVuln in current_affected: log.debug('Removing match on image: {}/{}'.format(pkgVuln.pkg_user_id, pkgVuln.pkg_image_id)) db.delete(pkgVuln) changed_images.append((pkgVuln.pkg_user_id, pkgVuln.pkg_image_id)) else: # Find impacted images for the current vulnerability new_vulnerable_packages = [ImagePackageVulnerability.from_pair(x, vulnerability) for x in find_vulnerable_image_packages(vulnerability)] unique_vuln_pkgs = set(new_vulnerable_packages) current_match = set(current_affected) if len(new_vulnerable_packages) > 0: log.debug('Found {} packages vulnerable to cve {}'.format(len(new_vulnerable_packages), vulnerability.id)) log.debug('Dedup matches from {} to {}'.format(len(new_vulnerable_packages), len(unique_vuln_pkgs))) # Find the diffs of any packages that were vulnerable but are no longer. no_longer_affected = current_match.difference(unique_vuln_pkgs) possibly_updated = current_match.intersection(unique_vuln_pkgs) new_matches = unique_vuln_pkgs.difference(current_match) if len(no_longer_affected) > 0: log.debug('Found {} packages no longer vulnerable to cve {}'.format(len(no_longer_affected), vulnerability.id)) for img_pkg_vuln in no_longer_affected: log.debug('Removing old invalid match for pkg {} on cve {}'.format(img_pkg_vuln, vulnerability.id)) db.delete(img_pkg_vuln) db.flush() for v in new_matches: log.debug('Adding new vulnerability match: {}'.format(v)) db.add(v) changed_images.append((v.pkg_user_id, v.pkg_image_id)) db.flush() log.spew('Images changed for cve {}: {}'.format(vulnerability.id, changed_images)) return changed_images