Skip to content
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

platform(sca): Fix bom report #3867

Merged
merged 21 commits into from
Nov 15, 2022
29 changes: 29 additions & 0 deletions checkov/common/output/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from dataclasses import dataclass, field

UNKNOWN_LICENSE = 'Unknown'


@dataclass
class SCADetails:
Expand All @@ -15,3 +17,30 @@ class ImageDetails(SCADetails):
image_id: str = ''
name: str | None = ''
related_resource_id: str | None = ''


def is_raw_formatted(licenses: str) -> bool:
return '","' in licenses


def format_licenses_to_string(licenses_lst: list[str]) -> str:
if isinstance(licenses_lst, list):
if len(licenses_lst) > 1:
joined_str = '","'.join(licenses_lst)
return f'"{joined_str}"'
elif licenses_lst:
return licenses_lst[0]
return UNKNOWN_LICENSE


def format_string_to_licenses(licenses_str: str) -> list[str]:
if licenses_str == UNKNOWN_LICENSE:
return [licenses_str]
elif licenses_str:
# remove first and last quotes
licenses_str = licenses_str[1:-1] if licenses_str.startswith('"') and licenses_str.endswith('"') else licenses_str
license_lst = licenses_str.split('","')
AdamDev marked this conversation as resolved.
Show resolved Hide resolved

return license_lst
else:
return []
18 changes: 18 additions & 0 deletions checkov/common/output/csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from typing import Any, TYPE_CHECKING

from checkov.common.models.enums import CheckResult
from checkov.common.output.common import format_string_to_licenses, is_raw_formatted
from checkov.common.output.record import Record, SCA_PACKAGE_SCAN_CHECK_NAME
from checkov.common.output.report import Report, CheckType

Expand Down Expand Up @@ -75,6 +76,7 @@ def add_sca_package_resources(self, resource: Record | ExtraResource, git_org: s
CheckType.SCA_PACKAGE: self.package_rows,
CheckType.SCA_IMAGE: self.container_rows
}

csv_table[check_type].append(
{
"Package": resource.vulnerability_details["package_name"],
Expand Down Expand Up @@ -157,8 +159,22 @@ def persist_report_oss_packages(self, file_name: str, is_api_key: bool, output_p
is_api_key=is_api_key,
)

@staticmethod
def arrange_rows(rows: list[dict[str, Any]]) -> None:
AdamDev marked this conversation as resolved.
Show resolved Hide resolved
# we search for formatted rows and convert them back into csv formatted file.
for row in rows:
for key, value in row.items():
val = str(value)

if is_raw_formatted(val):
val = ', '.join(format_string_to_licenses(val))
val = val[1:-1] if val.startswith('"') and val.endswith('"') else val
row[key] = '' if val == 'None' else val

@staticmethod
def write_section(file: str, header: list[str], rows: list[dict[str, Any]], is_api_key: bool) -> None:
CSVSBOM.arrange_rows(rows)
AdamDev marked this conversation as resolved.
Show resolved Hide resolved

with open(file, "w", newline="") as f:
print(f"Persisting SBOM to {os.path.abspath(file)}")
if is_api_key:
Expand All @@ -184,6 +200,8 @@ def get_csv_output_packages(self, check_type: str) -> str:
if header == 'Package':
csv_output += f'\"{field}\"'
elif header == 'Licenses':
field = str(field).replace('","', ", ")
field = field[1:-1] if field.startswith('"') and field.endswith('"') else field
csv_output += f',\"{field}\"'
else:
csv_output += f',{field}'
Expand Down
3 changes: 2 additions & 1 deletion checkov/common/output/cyclonedx.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from datetime import datetime
from pathlib import Path
from typing import TYPE_CHECKING, cast, Any
from checkov.common.output.common import format_string_to_licenses

from cyclonedx.model import (
XsUri,
Expand Down Expand Up @@ -221,7 +222,7 @@ def create_library_component(self, resource: Record | ExtraResource, check_type:
licenses = resource.vulnerability_details.get("licenses")
if licenses:
license_choices = [
LicenseChoice(license_=License(license_name=license)) for license in licenses.split(", ")
LicenseChoice(license_=License(license_name=license)) for license in format_string_to_licenses(licenses)
]

purl = PackageURL(
Expand Down
8 changes: 3 additions & 5 deletions checkov/common/sca/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
)
from checkov.common.util.http_utils import request_wrapper
from checkov.runner_filter import RunnerFilter
from checkov.common.output.common import format_licenses_to_string

if TYPE_CHECKING:
from checkov.common.output.common import SCADetails
Expand Down Expand Up @@ -258,7 +259,7 @@ def add_to_reports_cves_and_packages(
file_abs_path=scanned_file_path,
check_class=check_class or "",
vulnerability_details=vulnerability,
licenses=", ".join(licenses_per_package_map[get_package_alias(package_name, package_version)]) or "Unknown",
licenses=format_licenses_to_string(licenses_per_package_map[get_package_alias(package_name, package_version)]),
runner_filter=runner_filter,
sca_details=sca_details,
scan_data_format=scan_data_format,
Expand Down Expand Up @@ -292,10 +293,7 @@ def add_to_reports_cves_and_packages(
vulnerability_details={
"package_name": package["name"],
"package_version": package["version"],
"licenses": ", ".join(
licenses_per_package_map[get_package_alias(package["name"], package["version"])]
)
or "Unknown",
"licenses": format_licenses_to_string(licenses_per_package_map[get_package_alias(package["name"], package["version"])]),
"package_type": get_package_type(package["name"], package["version"], sca_details),
},
)
Expand Down
Loading