2525import datetime
2626import json
2727import logging
28- from typing import Set
28+ from typing import List
2929from typing import Iterable
3030
3131
3232from vulnerabilities import models
3333from vulnerabilities .models import Advisory
34- from vulnerabilities .data_source import AdvisoryData
34+ from vulnerabilities .importer import AdvisoryData
35+ from vulnerabilities .importer import Importer
3536
3637logger = logging .getLogger (__name__ )
3738
3839
3940class ImportRunner :
4041 """
4142 The ImportRunner is responsible for inserting and updating data about vulnerabilities and
42- affected/unaffected/fixed packages in the database. The two main goals for the implementation
43- are correctness and efficiency.
43+ affected/unaffected/fixed packages in the database. The main goal for the implementation
44+ is correctness
4445
4546 Correctness:
4647 - There must be no duplicates in the database (should be enforced by the schema).
4748 - No valid data from the data source must be skipped or truncated.
48-
49- Efficiency:
50- - Bulk inserts should be used whenever possible.
51- - Checking whether a record already exists should be kept to a minimum
52- (the data source should know this instead).
53- - All update and select operations must use indexed columns.
5449 """
5550
56- def __init__ (self , importer : models . Importer ):
51+ def __init__ (self , importer : Importer ):
5752 self .importer = importer
5853
59- def run (self , cutoff_date : datetime . datetime = None ) -> None :
54+ def run (self ) -> None :
6055 """
6156 Create a data source for the given importer and store the data retrieved in the database.
62-
63- cutoff_date - optional timestamp of the oldest data to include in the import
64-
65- NB: Data sources provide two kinds of records; vulnerabilities and packages. Vulnerabilities
66- are potentially shared across many packages, from the same data source and from different
67- data sources. For example, a vulnerability in the Linux kernel is mentioned by advisories
68- from all Linux distributions that package this kernel version.
6957 """
70- logger .info (f"Starting import for { self .importer .name } ." )
71- data_source = self .importer .make_data_source (cutoff_date = cutoff_date )
72- with data_source :
73- advisory_data = data_source .advisory_data ()
74- importer_name = data_source .qualified_name ()
75- process_advisories (advisory_datas = advisory_data , importer_name = importer_name )
76- self .importer .last_run = datetime .datetime .now (tz = datetime .timezone .utc )
77- self .importer .data_source_cfg = dataclasses .asdict (data_source .config )
78- self .importer .save ()
79-
80- logger .info (f"Finished import for { self .importer .name } ." )
81-
58+ importer_name = self .importer .qualified_name
59+ importer_class = self .importer
60+ logger .info (f"Starting import for { importer_name } " )
61+ advisory_datas = importer_class ().advisory_data ()
62+ count = process_advisories (advisory_datas = advisory_datas , importer_name = importer_name )
63+ logger .info (f"Finished import for { importer_name } . Imported { count } advisories." )
8264
83- def vuln_ref_exists (vulnerability , url , reference_id ):
84- return models .VulnerabilityReference .objects .filter (
85- vulnerability = vulnerability , reference_id = reference_id , url = url
86- ).exists ()
8765
88-
89- def get_vuln_pkg_refs (vulnerability , package ):
90- return models .PackageRelatedVulnerability .objects .filter (
91- vulnerability = vulnerability ,
92- package = package ,
93- )
94-
95-
96- def process_advisories (advisory_datas : Iterable [AdvisoryData ], importer_name : str ) -> None :
66+ def process_advisories (advisory_datas : Iterable [AdvisoryData ], importer_name : str ) -> List :
9767 """
9868 Insert advisories into the database
69+ Return the number of inserted advisories.
9970 """
100-
71+ count = 0
10172 for data in advisory_datas :
10273 obj , created = Advisory .objects .get_or_create (
10374 aliases = data .aliases ,
@@ -114,5 +85,8 @@ def process_advisories(advisory_datas: Iterable[AdvisoryData], importer_name: st
11485 logger .info (
11586 f"[*] New Advisory with aliases: { obj .aliases !r} , created_by: { obj .created_by } "
11687 )
88+ count += 1
11789 else :
11890 logger .debug (f"Advisory with aliases: { obj .aliases !r} already exists. Skipped." )
91+
92+ return count
0 commit comments