Skip to content

Commit ab6bbb3

Browse files
committed
Review comments
1 parent e01cca0 commit ab6bbb3

4 files changed

Lines changed: 54 additions & 33 deletions

File tree

dfetch/reporting/sbom_reporter.py

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
"""
109109

110110
from decimal import Decimal
111+
from importlib.metadata import PackageNotFoundError
111112
from importlib.metadata import version as pkg_version
112113

113114
from cyclonedx.builder.this import this_component as cdx_lib_component
@@ -140,6 +141,7 @@
140141
from dfetch.manifest.manifest import Manifest
141142
from dfetch.manifest.project import ProjectEntry
142143
from dfetch.reporting.reporter import Reporter
144+
from dfetch.util.license import License as DfetchLicense
143145
from dfetch.util.license import LicenseScanResult
144146
from dfetch.util.purl import vcs_url_to_purl
145147
from dfetch.vcs.archive import archive_url_to_purl, is_archive_url
@@ -152,7 +154,10 @@
152154

153155

154156
#: Version of the *infer-license* library used for license text analysis.
155-
INFER_LICENSE_VERSION: str = pkg_version("infer-license")
157+
try:
158+
INFER_LICENSE_VERSION: str = pkg_version("infer-license")
159+
except PackageNotFoundError:
160+
INFER_LICENSE_VERSION = "unknown"
156161

157162
# Map from dfetch hash-field algorithm prefix to CycloneDX HashAlgorithm name
158163
DFETCH_TO_CDX_HASH_ALGORITHM: dict[str, str] = {
@@ -361,6 +366,28 @@ def _apply_vcs_refs(component: Component, purl: PackageURL) -> None:
361366
)
362367
)
363368

369+
@staticmethod
370+
def _attach_identified_licenses(
371+
component: Component, identified: list[DfetchLicense]
372+
) -> None:
373+
"""Add each identified license to *component* and record its confidence."""
374+
for lic in identified:
375+
cdx_license = (
376+
CycloneDxLicense(id=lic.spdx_id)
377+
if lic.spdx_id
378+
else CycloneDxLicense(name=lic.name)
379+
)
380+
component.licenses.add(cdx_license)
381+
if component.evidence:
382+
component.evidence.licenses.add(cdx_license)
383+
label = lic.spdx_id or lic.name or "unknown"
384+
component.properties.add(
385+
Property(
386+
name=f"dfetch:license:{label}:confidence",
387+
value=f"{lic.probability:.2f}",
388+
)
389+
)
390+
364391
@staticmethod
365392
def _apply_licenses(component: Component, license_scan: LicenseScanResult) -> None:
366393
"""Attach license information to *component* and its evidence block.
@@ -397,38 +424,28 @@ def _apply_licenses(component: Component, license_scan: LicenseScanResult) -> No
397424
)
398425

399426
if license_scan.identified:
400-
for lic in license_scan.identified:
401-
cdx_license = (
402-
CycloneDxLicense(id=lic.spdx_id)
403-
if lic.spdx_id
404-
else CycloneDxLicense(name=lic.name)
405-
)
406-
component.licenses.add(cdx_license)
407-
if component.evidence:
408-
component.evidence.licenses.add(cdx_license)
409-
# Record per-license confidence so auditors can compare against
410-
# the threshold and re-evaluate if the threshold changes.
411-
label = lic.spdx_id or lic.name or "unknown"
412-
component.properties.add(
413-
Property(
414-
name=f"dfetch:license:{label}:confidence",
415-
value=f"{lic.probability:.2f}",
416-
)
417-
)
418-
return
419-
420-
noassertion = CycloneDxLicense(name="NOASSERTION")
421-
component.licenses.add(noassertion)
422-
if component.evidence:
423-
component.evidence.licenses.add(noassertion)
427+
SbomReporter._attach_identified_licenses(component, license_scan.identified)
428+
else:
429+
noassertion = CycloneDxLicense(name="NOASSERTION")
430+
component.licenses.add(noassertion)
431+
if component.evidence:
432+
component.evidence.licenses.add(noassertion)
424433

425434
if license_scan.unclassified_files:
426435
files_str = ", ".join(sorted(license_scan.unclassified_files))
427-
finding = f"License file(s) found ({files_str}) but could not be classified"
428-
else:
429-
finding = "No license file found in source tree"
430-
431-
component.properties.add(Property(name="dfetch:license:finding", value=finding))
436+
component.properties.add(
437+
Property(
438+
name="dfetch:license:finding",
439+
value=f"License file(s) found ({files_str}) but could not be classified",
440+
)
441+
)
442+
elif not license_scan.identified:
443+
component.properties.add(
444+
Property(
445+
name="dfetch:license:finding",
446+
value="No license file found in source tree",
447+
)
448+
)
432449

433450
def dump_to_file(self, outfile: str) -> bool:
434451
"""Dump the SBoM to file."""

features/report-sbom-license.feature

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Feature: SBOM license transparency for unresolved licenses
5151
},
5252
{
5353
"name": "dfetch:license:tool",
54-
"value": "infer-license 0.2.0"
54+
"value": "<infer-license-version>"
5555
}
5656
],
5757
"evidence": {
@@ -108,7 +108,7 @@ Feature: SBOM license transparency for unresolved licenses
108108
},
109109
{
110110
"name": "dfetch:license:tool",
111-
"value": "infer-license 0.2.0"
111+
"value": "<infer-license-version>"
112112
}
113113
],
114114
"evidence": {

features/report-sbom.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ Feature: Create an CycloneDX sbom
105105
},
106106
{
107107
"name": "dfetch:license:tool",
108-
"value": "infer-license 0.2.0"
108+
"value": "<infer-license-version>"
109109
}
110110
],
111111
"type": "library",

features/steps/generic_steps.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from dfetch.__main__ import DfetchFatalException, run
2020
from dfetch.log import DLogger
21+
from dfetch.reporting.sbom_reporter import INFER_LICENSE_VERSION
2122
from dfetch.util.util import in_directory
2223

2324
ansi_escape = re.compile(r"\[/?[a-z\_ ]+\]")
@@ -94,6 +95,9 @@ def apply_archive_substitutions(text: str, context) -> str:
9495
text = text.replace("<archive-sha512>", context.archive_sha512)
9596
if hasattr(context, "archive_url"):
9697
text = text.replace("<archive-url>", context.archive_url)
98+
text = text.replace(
99+
"<infer-license-version>", f"infer-license {INFER_LICENSE_VERSION}"
100+
)
97101
return text
98102

99103

0 commit comments

Comments
 (0)