github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/java/package_url.go (about)

     1  package java
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/anchore/packageurl-go"
     7  	"github.com/anchore/syft/syft/pkg"
     8  	"github.com/anchore/syft/syft/pkg/cataloger/common/cpe"
     9  )
    10  
    11  // PackageURL returns the PURL for the specific java package (see https://github.com/package-url/purl-spec)
    12  func packageURL(name, version string, metadata pkg.JavaMetadata) string {
    13  	var groupID = name
    14  
    15  	if gID := groupIDFromJavaMetadata(name, metadata); gID != "" {
    16  		groupID = gID
    17  	}
    18  
    19  	pURL := packageurl.NewPackageURL(
    20  		packageurl.TypeMaven, // TODO: should we filter down by package types here?
    21  		groupID,
    22  		name,
    23  		version,
    24  		nil, // TODO: there are probably several qualifiers that can be specified here
    25  		"")
    26  	return pURL.ToString()
    27  }
    28  
    29  // GroupIDFromJavaPackage returns the authoritative group ID for a Java package.
    30  // The order of precedence is:
    31  // 1. The group ID from the POM properties
    32  // 2. The group ID from the POM project
    33  // 3. The group ID from a select map of known group IDs
    34  // 4. The group ID from the Java manifest
    35  func groupIDFromJavaMetadata(pkgName string, metadata pkg.JavaMetadata) (groupID string) {
    36  	if groupID = groupIDFromPomProperties(metadata.PomProperties); groupID != "" {
    37  		return groupID
    38  	}
    39  
    40  	if groupID = groupIDFromPomProject(metadata.PomProject); groupID != "" {
    41  		return groupID
    42  	}
    43  
    44  	if groupID = groupIDFromKnownPackageList(pkgName); groupID != "" {
    45  		return groupID
    46  	}
    47  
    48  	if groupID = groupIDFromJavaManifest(metadata.Manifest); groupID != "" {
    49  		return groupID
    50  	}
    51  
    52  	return groupID
    53  }
    54  
    55  func groupIDFromKnownPackageList(pkgName string) (groupID string) {
    56  	if groupID, ok := cpe.DefaultArtifactIDToGroupID[pkgName]; ok {
    57  		return groupID
    58  	}
    59  	return groupID
    60  }
    61  
    62  func groupIDFromJavaManifest(manifest *pkg.JavaManifest) (groupID string) {
    63  	if manifest == nil {
    64  		return groupID
    65  	}
    66  
    67  	groupIDS := cpe.GetManifestFieldGroupIDs(manifest, cpe.PrimaryJavaManifestGroupIDFields)
    68  	// assumes that primaryJavaManifestNameFields are ordered by priority
    69  	if len(groupIDS) != 0 {
    70  		return groupIDS[0]
    71  	}
    72  
    73  	groupIDS = cpe.GetManifestFieldGroupIDs(manifest, cpe.SecondaryJavaManifestGroupIDFields)
    74  
    75  	if len(groupIDS) != 0 {
    76  		return groupIDS[0]
    77  	}
    78  
    79  	return groupID
    80  }
    81  
    82  func groupIDFromPomProperties(properties *pkg.PomProperties) (groupID string) {
    83  	if properties == nil {
    84  		return groupID
    85  	}
    86  
    87  	if properties.GroupID != "" {
    88  		return cleanGroupID(properties.GroupID)
    89  	}
    90  
    91  	// sometimes the publisher puts the group ID in the artifact ID field unintentionally
    92  	if looksLikeGroupID(properties.ArtifactID) {
    93  		// there is a strong indication that the artifact ID is really a group ID
    94  		return cleanGroupID(properties.ArtifactID)
    95  	}
    96  
    97  	return groupID
    98  }
    99  
   100  func groupIDFromPomProject(project *pkg.PomProject) (groupID string) {
   101  	if project == nil {
   102  		return groupID
   103  	}
   104  
   105  	// check the project details
   106  	if project.GroupID != "" {
   107  		return cleanGroupID(project.GroupID)
   108  	}
   109  
   110  	// sometimes the publisher puts the group ID in the artifact ID field unintentionally
   111  	if looksLikeGroupID(project.ArtifactID) {
   112  		// there is a strong indication that the artifact ID is really a group ID
   113  		return cleanGroupID(project.ArtifactID)
   114  	}
   115  
   116  	// let's check the parent details
   117  	// if the current project does not have a group ID, but the parent does, we'll use the parent's group ID
   118  	if project.Parent != nil {
   119  		if project.Parent.GroupID != "" {
   120  			return cleanGroupID(project.Parent.GroupID)
   121  		}
   122  
   123  		// sometimes the publisher puts the group ID in the artifact ID field unintentionally
   124  		if looksLikeGroupID(project.Parent.ArtifactID) {
   125  			// there is a strong indication that the artifact ID is really a group ID
   126  			return cleanGroupID(project.Parent.ArtifactID)
   127  		}
   128  	}
   129  
   130  	return groupID
   131  }
   132  func looksLikeGroupID(value string) bool {
   133  	return strings.Contains(value, ".")
   134  }
   135  
   136  func cleanGroupID(groupID string) string {
   137  	return strings.TrimSpace(removeOSCIDirectives(groupID))
   138  }
   139  
   140  func removeOSCIDirectives(groupID string) string {
   141  	// for example:
   142  	// 		org.bar;uses:=“org.foo”		-> 	org.bar
   143  	// more about OSGI directives see https://spring.io/blog/2008/10/20/understanding-the-osgi-uses-directive/
   144  	return strings.Split(groupID, ";")[0]
   145  }