-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding the new NIST CVE Tracking feature for 3.x release. #365
base: next3.0
Are you sure you want to change the base?
Conversation
9e9de39
to
7cf3d04
Compare
3dfb613
to
1d7f8bd
Compare
"""Converts CVE info into DLC Model compatibility.""" | ||
cve = cve_json | ||
|
||
# cve_base = cve["vulnerabilities"][0]['cve'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the last commit resolved this.
nautobot_device_lifecycle_mgmt/migrations/0031_cvelcm_last_modified_date.py
Outdated
Show resolved
Hide resolved
def __init__(self): | ||
"""Initializing job with extra options.""" | ||
super().__init__() | ||
self.nist_api_key = getenv("NAUTOBOT_DLM_NIST_API_KEY") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking about this again. We should move this to the plugin config and set the default in app init. Then we can do:
self.nist_api_key = PLUGIN_CFG["NAUTOBOT_DLM_NIST_API_KEY"]
Also, we should guard for this being empty and return early with error.
@staticmethod | ||
def create_cpe_software_search_urls(vendor: str, platform: str, version: str) -> list: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this method is needed. We are making call to the external code, we could move it to the caller method.
self.associate_software_to_cve(software.id, matching_dlc_cve.id) | ||
if str(cve_info["modified_date"][0:10]) != str(matching_dlc_cve.last_modified_date): | ||
self.update_cve(matching_dlc_cve, cve_info) | ||
continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not needed.
continue |
def associate_software_to_cve(self, software_id, cve_id): | ||
"""A function to associate software to a CVE.""" | ||
cve = CVELCM.objects.get(id=cve_id) | ||
software = SoftwareVersion.objects.get(id=software_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have those objects in the method that's calling this one. Perhaps we could get rid of this method and do the association directly in the calling method.
|
||
self.logger.info("Created New CVEs.", extra={"grouping": "CVE Creation"}) | ||
|
||
def get_cve_info(self, cpe_software_search_urls: list, software_id=None) -> dict: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have SoftwareVersion object in the calling method so it's probably better to use that instead of passing software_id
around.
extra={"object": SoftwareVersion.objects.get(id=software_id), "grouping": "CVE Creation"}, | ||
) | ||
cve_list = [cve["cve"] for cve in result["vulnerabilities"]] | ||
dlc_cves = [cve.name for cve in CVELCM.objects.all()] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dlc_cves = [cve.name for cve in CVELCM.objects.all()] | |
dlc_cves = CVELCM.objects.values_list("name", flat=True) |
if cve_list: | ||
for cve in cve_list: | ||
cve_name = cve["id"] | ||
if cve_name.startswith("CVE"): | ||
if cve_name not in dlc_cves: | ||
processed_cve_info["new"].update({cve_name: self.prep_cve_for_dlc(cve)}) | ||
else: | ||
processed_cve_info["existing"].update({cve_name: self.prep_cve_for_dlc(cve)}) | ||
self.logger.info( | ||
"Prepared %s CVE for creation." % len(processed_cve_info["new"]), | ||
extra={"object": SoftwareVersion.objects.get(id=software_id), "grouping": "CVE Creation"}, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if cve_list: | |
for cve in cve_list: | |
cve_name = cve["id"] | |
if cve_name.startswith("CVE"): | |
if cve_name not in dlc_cves: | |
processed_cve_info["new"].update({cve_name: self.prep_cve_for_dlc(cve)}) | |
else: | |
processed_cve_info["existing"].update({cve_name: self.prep_cve_for_dlc(cve)}) | |
self.logger.info( | |
"Prepared %s CVE for creation." % len(processed_cve_info["new"]), | |
extra={"object": SoftwareVersion.objects.get(id=software_id), "grouping": "CVE Creation"}, | |
) | |
if not cve_list: | |
return processed_cve_info | |
for cve in cve_list: | |
cve_name = cve["id"] | |
if not cve_name.startswith("CVE"): | |
continue | |
if cve_name not in dlc_cves: | |
processed_cve_info["new"].update({cve_name: self.prep_cve_for_dlc(cve)}) | |
else: | |
processed_cve_info["existing"].update({cve_name: self.prep_cve_for_dlc(cve)}) | |
self.logger.info( | |
"Prepared %s CVE for creation." % len(processed_cve_info["new"]), | |
extra={"object": SoftwareVersion.objects.get(id=software_id), "grouping": "CVE Creation"}, | |
) |
dict: Dictionary of returned results if successful. | ||
""" | ||
try: | ||
result = self.session.get(url, headers=self.headers) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll set headers when we init session.
result = self.session.get(url, headers=self.headers) | |
result = self.session.get(url) |
"The NIST Service is currently unavailable. Status Code: %s. Try running the job again later.", code | ||
) | ||
|
||
return result.json() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need try..except in case JSON decoding fails?
Creating a batched commit with several of the syntax update recommendations. Co-authored-by: Przemek Rogala <progala@progala.net>
Creating a batched commit with several of the syntax update recommendations. Co-authored-by: Przemek Rogala <progala@progala.net>
8153f18
to
ad25fde
Compare
Closes: #80
This issue was marked as closed, but then briefly discussed in #81 that is open regarding
last_modified_date
(or similar). See summary below.What's Changed
Summary:
last_modified_date
(Issue Feature Request: Last Updated Date field (for the vendor's update timestamps) #80) that is used as a method for NIST to know when a record needs updating.New "NIST - Software CVE Search" Job
Job Results