3232)
3333from cyclonedx .model .contact import OrganizationalEntity
3434from cyclonedx .model .license import DisjunctiveLicense as CycloneDxLicense
35+ from cyclonedx .model .license import LicenseAcknowledgement
3536from cyclonedx .output import make_outputter
3637from cyclonedx .schema import OutputFormat , SchemaVersion
3738
@@ -55,7 +56,9 @@ class SbomReporter(Reporter):
5556 name = "dfetch" ,
5657 version = dfetch .__version__ ,
5758 bom_ref = f"dfetch-{ dfetch .__version__ } " ,
58- licenses = [CycloneDxLicense (name = "MIT License" , id = "MIT" )],
59+ licenses = [
60+ CycloneDxLicense (id = "MIT" , acknowledgement = LicenseAcknowledgement .DECLARED )
61+ ],
5962 external_references = [
6063 ExternalReference (
6164 type = ExternalReferenceType .VCS ,
@@ -96,8 +99,9 @@ class SbomReporter(Reporter):
9699
97100 name = "SBoM"
98101
99- def __init__ (self ) -> None :
102+ def __init__ (self , manifest_path : str ) -> None :
100103 """Start the report."""
104+ super ().__init__ (manifest_path )
101105 self ._bom = Bom ()
102106 self ._bom .metadata .tools .components .add (self .dfetch_tool )
103107 self ._bom .metadata .tools .components .add (cdx_lib_component ())
@@ -113,13 +117,20 @@ def add_project(
113117 project .remote_url , version = version , subpath = project .source or None
114118 )
115119
120+ name = project .name if purl .type == "generic" else purl .name
121+
122+ line_nr , start , _ = self .find_name_in_manifest (project .name )
123+
116124 component = Component (
117- name = project . name ,
125+ name = name ,
118126 version = version ,
127+ bom_ref = f"{ project .name } -{ version } " ,
119128 type = ComponentType .LIBRARY ,
120129 purl = purl ,
121130 evidence = ComponentEvidence (
122- occurrences = [Occurrence (location = "dfetch.yaml" )],
131+ occurrences = [
132+ Occurrence (location = self ._manifest_path , line = line_nr , offset = start )
133+ ],
123134 identity = [
124135 Identity (
125136 field = IdentityField .NAME ,
@@ -131,7 +142,7 @@ def add_project(
131142 value = "Name as used for project in dfetch.yaml" ,
132143 )
133144 ],
134- concluded_value = project . name ,
145+ concluded_value = name ,
135146 ),
136147 Identity (
137148 field = IdentityField .VERSION ,
@@ -152,7 +163,8 @@ def add_project(
152163 Method (
153164 technique = AnalysisTechnique .MANIFEST_ANALYSIS ,
154165 confidence = Decimal .from_float (0.4 ),
155- value = "Determined from the VCS url as used for project in dfetch.yaml" ,
166+ value = f"Determined from { project .remote_url } as used"
167+ f" for the project { project .name } in dfetch.yaml" ,
156168 )
157169 ],
158170 concluded_value = purl .to_string (),
@@ -189,11 +201,17 @@ def add_project(
189201 )
190202
191203 for lic in licenses :
192- cdx_license = CycloneDxLicense (name = lic .name , id = lic .spdx_id )
204+
205+ # License wants either an SPDX id or a name, prefer SPDX id when available
206+ cdx_license = (
207+ CycloneDxLicense (id = lic .spdx_id )
208+ if lic .spdx_id
209+ else CycloneDxLicense (name = lic .name )
210+ )
193211
194212 component .licenses .add (cdx_license )
195213 if component .evidence :
196- component .evidence .licenses .add (cdx_license . bom_ref )
214+ component .evidence .licenses .add (cdx_license )
197215
198216 self ._bom .components .add (component )
199217
0 commit comments