예제 #1
0
파일: cvemap.py 프로젝트: tkasparek/vmaas
    def __init__(self, filename, lastmodified):
        self.lastmodified = lastmodified
        self.cves = {}
        root = None
        updated = None
        for event, elem in eT.iterparse(filename, events=("start", "end")):
            if elem.tag == "cvemap" and event == "start":
                root = elem
                updated = parse_datetime(elem.get('updated'))
            elif elem.tag == "Vulnerability" and event == "end":
                name = elem.get('name')
                self.cves[name] = {
                    'impact': text_strip(elem.find('ThreatSeverity')),
                    'published_date': parse_datetime(text_strip(elem.find('PublicDate'))),
                    'modified_date': updated,
                    'cvss2_score': text_strip(elem.find('CVSS/CVSSBaseScore')),
                    'cvss2_metrics': text_strip(elem.find('CVSS/CVSSScoringVector')),
                    'cvss3_score': text_strip(elem.find('CVSS3/CVSS3BaseScore')),
                    'cvss3_metrics': text_strip(elem.find('CVSS3/CVSS3ScoringVector')),
                    'cwe_list': self._cwe_list(text_strip(elem.find('CWE'))),
                    'description': self._cve_description(elem.findall('Details[@{%s}lang="en:us"]' % NS)),
                    'iava': text_strip(elem.find('IAVA')),
                    'redhat_url': "https://access.redhat.com/security/cve/" + str.lower(name),
                    'secondary_url': text_strip(elem.find('References'))
                }

                # Clear the XML tree continuously
                root.clear()
예제 #2
0
 def _read_head(self, failed):
     """Reads downloaded meta files and checks for updates."""
     header_path = self._tmp_head()
     if not failed:
         header = CvemapHead(header_path)
         # already synced before?
         db_lastmodified = parse_datetime(self.cvemap_store.lastmodified())
         self.lastmodified = parse_datetime(header.get_lastmodified())
         # if header doesn't have last-modified
         if self.lastmodified is None:
             self.lastmodified = now()
         # synced for the first time or has newer revision
         if (db_lastmodified is None
                 or self.lastmodified > db_lastmodified):
             self.updated = True
         else:
             self.logger.info("Cve map has not been updated (since %s).",
                              str(db_lastmodified))
     else:
         FAILED_CVEMAP.inc()
         self.logger.warning("Download failed: %s (HTTP CODE %d)", URL, failed[header_path])
예제 #3
0
    def check_repo(self, dbdump):
        """Check repo data in dump."""
        repo_detail = {}
        repolabel2ids = {}
        pkgid2repoids = {}
        for row in dbdump.execute("select * from repo_detail"):
            repo_id = row[0]
            repo = (row[1], row[2], row[3], row[4], row[5], row[6], row[7],
                    parse_datetime(row[8]), bool(row[9]))
            repo_detail[repo_id] = repo
            repolabel2ids.setdefault(repo[0], []).append(repo_id)
        for row in dbdump.execute("select pkg_id, repo_id from pkg_repo"):
            pkgid2repoids.setdefault(row[0], []).append(row[1])

        assert 801 in repo_detail
        assert repo_detail[801][0] == "content set 1"
        assert repo_detail[801][1] == "content-set-name-1"
        assert repo_detail[801][2] == "https://www.repourl.com/repo1"
        assert repo_detail[801][3] == "noarch"
        assert repo_detail[801][4] == "1"
        assert repo_detail[801][5] == "product1"
        assert repo_detail[801][6] == 501
        assert repo_detail[801][7] == parse_datetime(
            "2019-08-01T01:00:00-05:00")

        assert "content set 1" in repolabel2ids
        assert repolabel2ids["content set 1"] == [801]

        assert 301 in pkgid2repoids
        assert 302 in pkgid2repoids
        assert 303 in pkgid2repoids
        assert 304 in pkgid2repoids
        assert 305 in pkgid2repoids
        assert 306 in pkgid2repoids
        repo_list = pkgid2repoids[306]
        assert 801 in repo_list
        assert 802 in repo_list
        assert 307 in pkgid2repoids
예제 #4
0
    def __init__(self, filename):
        self.lastmodified = None
        self.cpes = {}
        root = None
        for event, elem in eT.iterparse(filename, events=("start", "end")):
            if elem.tag == "{%s}cpe-list" % NS["cpe"] and event == "start":
                root = elem
            elif elem.tag == "{%s}generator" % NS["cpe"] and event == "end":
                self.lastmodified = parse_datetime(text_strip(elem.find('cpe:timestamp', NS)))
            elif elem.tag == "{%s}cpe-item" % NS["cpe"] and event == "end":
                name = elem.get('name')
                self.cpes[name] = text_strip(elem.find('cpe:title', NS))

                # Clear the XML tree continuously
                root.clear()
예제 #5
0
    def store(self):  # pylint: disable=too-many-branches,too-many-statements
        """Sync all OVAL feeds. Process files in batches due to disk space and memory usage."""
        self.logger.info("Checking OVAL feed.")
        failed = self._download_feed()
        if failed:
            for path in failed:
                FAILED_IMPORT_OVAL.inc()
                self.logger.warning("OVAL feed failed to download, %s (HTTP CODE %d).", path, failed[path])
            self.clean()
            return

        db_oval_files = self.oval_store.oval_file_map.copy()
        batches = BatchList()
        up_to_date = 0

        # Filter out all not updated OVAL definition files
        with open(self.feed_path, 'r', encoding='utf8') as feed_file:
            feed = json.load(feed_file)
        feed_oval_files = {entry["id"]: entry for entry in feed["feed"]["entry"]}
        for entry in feed_oval_files.values():
            if self._skip_oval_definition_file(entry['id'], feed_oval_files):
                continue
            db_timestamp = db_oval_files.get(entry['id'])
            feed_timestamp = parse_datetime(entry["updated"])
            if not db_timestamp or feed_timestamp > db_timestamp[1]:
                local_path = os.path.join(self.tmp_directory, entry["content"]["src"].replace(OVAL_FEED_BASE_URL, ""))
                oval_definitions_file = OvalDefinitions(entry["id"], feed_timestamp,
                                                        entry["content"]["src"], local_path)
                batches.add_item(oval_definitions_file)
            else:
                up_to_date += 1
            db_oval_files.pop(entry["id"], None)
        feed_updated = parse_datetime(feed["feed"]["updated"])

        self.logger.info("%d OVAL definition files are up to date.", up_to_date)
        total_oval_files = batches.get_total_items()
        completed_oval_files = 0
        self.logger.info("%d OVAL definition files need to be synced.", total_oval_files)
        self.logger.info("%d OVAL definition files need to be deleted.", len(db_oval_files))

        try:
            for batch in batches:
                self.logger.info("Syncing a batch of %d OVAL definition files", len(batch))
                failed = self._download_definitions(batch)
                if failed:
                    self.logger.warning("%d OVAL definition files failed to download.", len(failed))
                    batch = [oval_file for oval_file in batch if oval_file.local_path not in failed]
                self._unpack_definitions(batch)
                for oval_definitions_file in batch:
                    completed_oval_files += 1
                    try:
                        oval_definitions_file.load_metadata()
                        self.logger.info("Syncing OVAL definition file: %s [%s/%s]", oval_definitions_file.oval_id,
                                         completed_oval_files, total_oval_files)
                        self.oval_store.store(oval_definitions_file)
                    finally:
                        oval_definitions_file.unload_metadata()
            self.delete_oval_file(list(db_oval_files))
            # Timestamp of main feed file
            self.oval_store.save_lastmodified(feed_updated)
        finally:
            self.clean()
예제 #6
0
    def _load_sqlite(self, data):

        for (id, arch) in self._sqlite_execute(data,
                                               'select id, arch from arch'):
            self.id2arch[int(id)] = arch
            self.arch2id[arch] = int(id)

        for (src, dst) in self._sqlite_execute(
                data, 'select from_arch_id, to_arch_id from arch_compat'):
            self.arch_compat.setdefault(src, set()).add(int(dst))

        for (id,
             string) in self._sqlite_execute(data,
                                             'select id, string from string'):
            self.strings[int(id)] = string

        for (id, label) in self._sqlite_execute(
                data, 'select id, label from content_set'):
            self.content_set_id2label[id] = label
            self.label2content_set_id[label] = id

        for (id, name) in self._sqlite_execute(
                data, 'select id, packagename from packagename'):
            self.packagename2id[str(name)] = int(id)
            self.id2packagename[int(id)] = str(name)

        for (cs_id, name_id) in self._sqlite_execute(
                data,
                "select content_set_id, pkg_name_id from content_set_pkg_name"
        ):
            self.content_set_id2pkg_name_ids.setdefault(
                cs_id, array.array('q')).append(name_id)

        for (cs_id, src_name_id) in self._sqlite_execute(
                data,
                "select content_set_id, src_pkg_name_id from content_set_src_pkg_name"
        ):
            self.src_pkg_name_id2cs_ids.setdefault(
                src_name_id, array.array('q')).append(cs_id)

        for (cpe_id,
             label) in self._sqlite_execute(data, "select id, label from cpe"):
            self.cpe_id2label[cpe_id] = label
            self.label2cpe_id[label] = cpe_id

        for (cpe_id, cs_id) in self._sqlite_execute(
                data, "select cpe_id, content_set_id from cpe_content_set"):
            self.content_set_id2cpe_ids.setdefault(
                cs_id, array.array('q')).append(cpe_id)

        for (cpe_id, repo_id) in self._sqlite_execute(
                data, "select cpe_id, repo_id from cpe_repo"):
            self.repo_id2cpe_ids.setdefault(repo_id,
                                            array.array('q')).append(cpe_id)

        for (name_id, pkg_id) in self._sqlite_execute(
                data,
                'select name_id, package_id from updates order by name_id, package_order'
        ):
            self.updates.setdefault(int(name_id), []).append(int(pkg_id))

        for (name_id, evr_id, order) in self._sqlite_execute(
                data,
                'select name_id, evr_id, package_order from updates_index order by name_id, package_order'
        ):
            name_id = int(name_id)
            evr_id = int(evr_id)
            order = int(order)
            self.updates_index.setdefault(name_id,
                                          {}).setdefault(evr_id,
                                                         []).append(order)

        for (id, epoch, ver, rel) in self._sqlite_execute(
                data, 'select id, epoch, version, release from evr'):
            evr = (str(epoch), str(ver), str(rel))
            self.id2evr[int(id)] = evr
            self.evr2id[evr] = int(id)

        for (id, name_id, evr_id, arch_id, sum_id, descr_id, src_pkg_id,
             modified_str) in self._sqlite_execute(
                 data, 'select * from package_detail'):
            detail = array.array('q')
            modified_dt = datetime.datetime.strptime(modified_str,
                                                     '%Y-%m-%d %H:%M:%S.%f')
            modified_int = int(modified_dt.timestamp())
            detail.fromlist([
                name_id, evr_id, arch_id, sum_id, descr_id, src_pkg_id or 0,
                modified_int
            ])
            self.package_details[id] = detail
            self.nevra2pkgid[(name_id, evr_id, arch_id)] = id

            if src_pkg_id:
                self.src_pkg_id2pkg_ids.setdefault(src_pkg_id,
                                                   array.array('q')).append(id)

        for row in self._sqlite_execute(data, "select * from repo_detail"):
            id = row[0]
            repo = (row[1], row[2], row[3], row[4], row[5], row[6], row[7],
                    parse_datetime(row[8]), bool(row[9]))
            self.repo_detail[id] = repo
            self.repolabel2ids.setdefault(repo[0], array.array('q')).append(id)

        for row in self._sqlite_execute(
                data, "select pkg_id, repo_id from pkg_repo"):
            self.pkgid2repoids.setdefault(row[0],
                                          array.array('q')).append(row[1])

        errataid2cves = {}
        cve2eid = {}
        for row in self._sqlite_execute(
                data, "select errata_id, cve from errata_cve"):
            errataid2cves.setdefault(row[0], []).append(row[1])
            cve2eid.setdefault(row[1], array.array('q')).append(row[0])

        errataid2pkgid = {}
        for row in self._sqlite_execute(
                data, "select pkg_id, errata_id from pkg_errata "):
            self.pkgid2errataids.setdefault(row[0],
                                            array.array('q')).append(row[1])
            errataid2pkgid.setdefault(row[1], array.array('q')).append(row[0])

        errataid2bzs = {}
        for row in self._sqlite_execute(
                data, "select errata_id, bugzilla from errata_bugzilla"):
            errataid2bzs.setdefault(row[0], []).append(row[1])

        errataid2refs = {}
        for row in self._sqlite_execute(
                data, "select errata_id, ref from errata_refs"):
            errataid2refs.setdefault(row[0], []).append(row[1])

        errataidmodulestream2pkgid = {}
        for row in self._sqlite_execute(
                data,
                "select pkg_id, errata_id, module_stream_id from errata_modulepkg"
        ):
            self.pkgerrata2module.setdefault((row[0], row[1]),
                                             set()).add(row[2])
            errataidmodulestream2pkgid.setdefault(
                (row[1], row[2]), array.array('q')).append(row[0])

        errataid2modules = {}
        for row in self._sqlite_execute(
                data,
                """select errata_id, module_name, module_stream_id, module_stream,
                                                 module_version, module_context from errata_module"""
        ):
            if row[0] not in errataid2modules:
                errataid2modules[row[0]] = {}
            if (row[1], row[3], row[4],
                    row[5]) not in errataid2modules[row[0]]:
                errataid2modules[row[0]][(row[1], row[3], row[4], row[5])] = {
                    "module_name":
                    row[1],
                    "module_stream":
                    row[3],
                    "module_version":
                    row[4],
                    "module_context":
                    row[5],
                    "package_list":
                    errataidmodulestream2pkgid.get((row[0], row[2]),
                                                   array.array('q')),
                    "source_package_list": []  # populated in API
                }
            else:
                # Add packages from module with same name but different architecture, etc.
                errataid2modules[row[0]][(row[1], row[3], row[4],
                                          row[5])]["package_list"].extend(
                                              errataidmodulestream2pkgid.get(
                                                  (row[0], row[2]),
                                                  array.array('q')))

        for row in self._sqlite_execute(data, "select * from errata_detail"):
            id = row[0]
            name = row[1]
            errata = (
                row[2],
                row[3],
                row[4],
                row[5],
                row[6],
                row[7],
                parse_datetime(row[8]),
                parse_datetime(row[9]),
                errataid2cves.get(id, []),
                errataid2pkgid.get(id, array.array('q')),
                errataid2bzs.get(id, []),
                errataid2refs.get(id, []),
                list(errataid2modules.get(id, {}).values()),
                row[10],
                bool(row[11]),
                bool(row[12]),
                id,
            )
            self.errata_detail[name] = errata
            self.errataid2name[id] = name

        for row in self._sqlite_execute(
                data, "select errata_id, repo_id from errata_repo"):
            self.errataid2repoids.setdefault(row[0],
                                             array.array('q')).append(row[1])

        for row in self._sqlite_execute(
                data, "select module, stream, stream_id from module_stream"):
            self.modulename2id.setdefault((row[0], row[1]), set()).add(row[2])

        for row in self._sqlite_execute(
                data,
                "select stream_id, require_id from module_stream_require"):
            self.modulerequire.setdefault(row[0], set()).add(row[1])

        cveid2cwe = {}
        for row in self._sqlite_execute(data,
                                        "select cve_id, cwe from cve_cwe"):
            cveid2cwe.setdefault(row[0], []).append(row[1])

        cveid2pid = {}
        for row in self._sqlite_execute(data,
                                        "select cve_id, pkg_id from cve_pkg"):
            cveid2pid.setdefault(row[0], array.array('q')).append(row[1])

        for row in self._sqlite_execute(data, "select * from cve_detail"):
            id = row[0]
            name = row[1]
            item = (row[2], row[3], row[4], row[5], row[6],
                    parse_datetime(row[7]), parse_datetime(row[8]), row[9],
                    row[10], cveid2cwe.get(id, []),
                    cveid2pid.get(id, array.array('q')),
                    cve2eid.get(name,
                                array.array('q')), row[11], row[12], row[13])
            self.cve_detail[name] = item

        for row in self._sqlite_execute(data,
                                        "select * from oval_definition_cpe"):
            self.cpe_id2ovaldefinition_ids.setdefault(
                row[0], array.array('q')).append(row[1])

        for row in self._sqlite_execute(
                data, "select * from packagename_oval_definition"):
            self.packagename_id2definition_ids.setdefault(
                row[0], array.array('q')).append(row[1])

        for row in self._sqlite_execute(
                data, "select * from oval_definition_detail"):
            self.ovaldefinition_detail[row[0]] = (row[1], row[2])

        for row in self._sqlite_execute(data,
                                        "select * from oval_definition_cve"):
            self.ovaldefinition_id2cves.setdefault(row[0], []).append(row[1])

        for row in self._sqlite_execute(data,
                                        "select * from oval_criteria_type"):
            self.ovalcriteria_id2type[row[0]] = row[1]

        for row in self._sqlite_execute(
                data, "select * from oval_criteria_dependency"):
            if row[2] is None and row[3] is None:
                self.ovalcriteria_id2depcriteria_ids.setdefault(
                    row[0], array.array('q')).append(row[1])
            elif row[1] is None and row[3] is None:
                self.ovalcriteria_id2deptest_ids.setdefault(
                    row[0], array.array('q')).append(row[2])
            else:
                self.ovalcriteria_id2depmoduletest_ids.setdefault(
                    row[0], array.array('q')).append(row[3])

        for row in self._sqlite_execute(data,
                                        "select * from oval_test_detail"):
            self.ovaltest_detail[row[0]] = (row[1], row[2])

        for row in self._sqlite_execute(data, "select * from oval_test_state"):
            self.ovaltest_id2states.setdefault(row[0], []).append(
                (row[1], row[2], row[3]))

        for row in self._sqlite_execute(data, "select * from oval_state_arch"):
            self.ovalstate_id2arches.setdefault(row[0], set()).add(row[1])

        for row in self._sqlite_execute(
                data, "select * from oval_module_test_detail"):
            self.ovalmoduletest_detail[row[0]] = row[1]

        names = [
            "exported", "last_change", "repository_changes", "cve_changes",
            "errata_changes"
        ]

        for row in self._sqlite_execute(
                data, "select %s from dbchange" % ','.join(names)):
            for (i, v) in enumerate(row):
                self.dbchange[names[i]] = v
예제 #7
0
 def test_parse_string(self):
     """Test parsing datetime from string."""
     assert isinstance(
         date_utils.parse_datetime("2018-10-24 15:27:40.058353"), datetime)
예제 #8
0
 def test_parse_none(self):
     """Test parsing date = None."""
     assert date_utils.parse_datetime(None) is None