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 }