@@ -60,6 +60,7 @@ public final class CargoProvider extends Provider {
6060 private static final ObjectMapper MAPPER =
6161 new ObjectMapper ().configure (DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false );
6262 private static final Logger log = LoggersFactory .getLogger (CargoProvider .class .getName ());
63+ private static final String VIRTUAL_VERSION = "1.0.0" ;
6364 private static final String PACKAGE_NAME = "package.name" ;
6465 private static final String PACKAGE_VERSION = "package.version" ;
6566 private static final String PACKAGE_VERSION_WORKSPACE = "package.version.workspace" ;
@@ -69,14 +70,18 @@ public final class CargoProvider extends Provider {
6970 private final String cargoExecutable ;
7071
7172 private void addDependencies (
72- Sbom sbom , PackageURL root , Set <String > ignoredDeps , AnalysisType analysisType ) {
73+ Sbom sbom ,
74+ PackageURL root ,
75+ Set <String > ignoredDeps ,
76+ AnalysisType analysisType ,
77+ ProjectInfo projectInfo ) {
7378 try {
7479 CargoMetadata metadata = executeCargoMetadata ();
7580 if (metadata != null && metadata .resolve () != null && metadata .resolve ().nodes () != null ) {
7681 // Build maps and find root once, reuse for better performance
7782 Map <String , CargoPackage > packageMap = buildPackageMap (metadata );
7883 Map <String , CargoNode > nodeMap = buildNodeMap (metadata );
79- CargoNode rootNode = findRootNodeForAnalysis (metadata , nodeMap );
84+ CargoNode rootNode = findRootNodeForAnalysis (metadata , nodeMap , projectInfo );
8085
8186 if (rootNode == null ) {
8287 return ;
@@ -228,21 +233,21 @@ private Map<String, CargoNode> buildNodeMap(CargoMetadata metadata) {
228233 }
229234
230235 private CargoNode findRootNodeForAnalysis (
231- CargoMetadata metadata , Map <String , CargoNode > nodeMap ) {
236+ CargoMetadata metadata , Map <String , CargoNode > nodeMap , ProjectInfo projectInfo ) {
232237 /* The package in the current working directory (if --manifest-path is not given).
233238 This is null if there is a virtual workspace. Otherwise, it is
234239 the Package ID of the package.
235240 */
236241 String rootId = metadata .resolve ().root ();
237242 // Handle workspace-only projects (no root package)
238243 if (rootId == null ) {
239- return createRootNodeFromVirtualWorkspace (metadata , nodeMap );
244+ return createRootNodeFromVirtualWorkspace (metadata , nodeMap , projectInfo );
240245 }
241246 return nodeMap .get (rootId );
242247 }
243248
244249 private CargoNode createRootNodeFromVirtualWorkspace (
245- CargoMetadata metadata , Map <String , CargoNode > nodeMap ) {
250+ CargoMetadata metadata , Map <String , CargoNode > nodeMap , ProjectInfo projectInfo ) {
246251 if (metadata .workspaceMembers () == null || metadata .workspaceMembers ().isEmpty ()) {
247252 log .warning ("No workspace members found for workspace-only project" );
248253 return null ;
@@ -275,8 +280,8 @@ private CargoNode createRootNodeFromVirtualWorkspace(
275280 }
276281
277282 // Create a virtual root node with combined dependencies
278- // Use the workspace name/version for the virtual root
279- String virtualRootId = "virtual-workspace-root" ;
283+ // Use the actual workspace name/version from ProjectInfo
284+ String virtualRootId = String . format ( "%s#%s" , projectInfo . name (), projectInfo . version ()) ;
280285 return new CargoNode (virtualRootId , null , new ArrayList <>(depMap .values ()));
281286 }
282287
@@ -483,9 +488,9 @@ private Sbom createSbom(boolean includeTransitiveDependencies) throws IOExceptio
483488 Set <String > ignoredDeps = getIgnoredDependencies (tomlResult , cargoContent );
484489
485490 if (includeTransitiveDependencies ) {
486- addDependencies (sbom , root , ignoredDeps , AnalysisType .STACK );
491+ addDependencies (sbom , root , ignoredDeps , AnalysisType .STACK , projectInfo );
487492 } else {
488- addDependencies (sbom , root , ignoredDeps , AnalysisType .COMPONENT );
493+ addDependencies (sbom , root , ignoredDeps , AnalysisType .COMPONENT , projectInfo );
489494 }
490495 return sbom ;
491496 } catch (Exception e ) {
@@ -513,9 +518,10 @@ private ProjectInfo parseCargoToml(TomlParseResult result) throws IOException {
513518 "Parsed project info: name="
514519 + packageName
515520 + ", version="
516- + (packageVersion != null ? packageVersion : "0.0.0" ));
521+ + (packageVersion != null ? packageVersion : VIRTUAL_VERSION ));
517522 }
518- return new ProjectInfo (packageName , packageVersion != null ? packageVersion : "0.0.0" );
523+ return new ProjectInfo (
524+ packageName , packageVersion != null ? packageVersion : VIRTUAL_VERSION );
519525 }
520526 // Check for workspace section as fallback (when there's no [package] section)
521527 boolean hasWorkspace = result .contains ("workspace" );
@@ -527,9 +533,10 @@ private ProjectInfo parseCargoToml(TomlParseResult result) throws IOException {
527533 "Using workspace fallback: name="
528534 + dirName
529535 + ", version="
530- + (workspaceVersion != null ? workspaceVersion : "0.0.0" ));
536+ + (workspaceVersion != null ? workspaceVersion : VIRTUAL_VERSION ));
531537 }
532- return new ProjectInfo (dirName , workspaceVersion != null ? workspaceVersion : "0.0.0" );
538+ return new ProjectInfo (
539+ dirName , workspaceVersion != null ? workspaceVersion : VIRTUAL_VERSION );
533540 }
534541 throw new IOException ("Invalid Cargo.toml: no [package] or [workspace] section found" );
535542 }
0 commit comments