github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/pkg/java.go (about) 1 package pkg 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "sort" 7 "strings" 8 9 "github.com/anchore/syft/internal" 10 "github.com/anchore/syft/syft/file" 11 ) 12 13 var jenkinsPluginPomPropertiesGroupIDs = []string{ 14 "io.jenkins.plugins", 15 "org.jenkins.plugins", 16 "org.jenkins-ci.plugins", 17 "io.jenkins-ci.plugins", 18 "com.cloudbees.jenkins.plugins", 19 } 20 21 // JavaArchive encapsulates all Java ecosystem metadata for a package as well as an (optional) parent relationship. 22 type JavaArchive struct { 23 VirtualPath string `json:"virtualPath" cyclonedx:"virtualPath"` // we need to include the virtual path in cyclonedx documents to prevent deduplication of jars within jars 24 Manifest *JavaManifest `mapstructure:"Manifest" json:"manifest,omitempty"` 25 PomProperties *JavaPomProperties `mapstructure:"PomProperties" json:"pomProperties,omitempty" cyclonedx:"-"` 26 PomProject *JavaPomProject `mapstructure:"PomProject" json:"pomProject,omitempty"` 27 ArchiveDigests []file.Digest `hash:"ignore" json:"digest,omitempty"` 28 Parent *Package `hash:"ignore" json:"-"` // note: the parent cannot be included in the minimal definition of uniqueness since this field is not reproducible in an encode-decode cycle (is lossy). 29 } 30 31 // JavaPomProperties represents the fields of interest extracted from a Java archive's pom.properties file. 32 type JavaPomProperties struct { 33 Path string `mapstructure:"path" json:"path"` 34 Name string `mapstructure:"name" json:"name"` 35 GroupID string `mapstructure:"groupId" json:"groupId" cyclonedx:"groupID"` 36 ArtifactID string `mapstructure:"artifactId" json:"artifactId" cyclonedx:"artifactID"` 37 Version string `mapstructure:"version" json:"version"` 38 Scope string `mapstructure:"scope" json:"scope,omitempty"` 39 Extra map[string]string `mapstructure:",remain" json:"extraFields,omitempty"` 40 } 41 42 // JavaPomProject represents fields of interest extracted from a Java archive's pom.xml file. See https://maven.apache.org/ref/3.6.3/maven-model/maven.html for more details. 43 type JavaPomProject struct { 44 Path string `json:"path"` 45 Parent *JavaPomParent `json:"parent,omitempty"` 46 GroupID string `json:"groupId"` 47 ArtifactID string `json:"artifactId"` 48 Version string `json:"version"` 49 Name string `json:"name"` 50 Description string `json:"description,omitempty"` 51 URL string `json:"url,omitempty"` 52 } 53 54 // JavaPomParent contains the fields within the <parent> tag in a pom.xml file 55 type JavaPomParent struct { 56 GroupID string `json:"groupId"` 57 ArtifactID string `json:"artifactId"` 58 Version string `json:"version"` 59 } 60 61 // PkgTypeIndicated returns the package Type indicated by the data contained in the JavaPomProperties. 62 func (p JavaPomProperties) PkgTypeIndicated() Type { 63 if internal.HasAnyOfPrefixes(p.GroupID, jenkinsPluginPomPropertiesGroupIDs...) || strings.Contains(p.GroupID, ".jenkins.plugin") { 64 return JenkinsPluginPkg 65 } 66 67 return JavaPkg 68 } 69 70 // JavaManifest represents the fields of interest extracted from a Java archive's META-INF/MANIFEST.MF file. 71 type JavaManifest struct { 72 Main KeyValues `json:"main,omitempty"` 73 Sections []KeyValues `json:"sections,omitempty"` 74 } 75 76 type unmarshalJavaManifest JavaManifest 77 78 type legacyJavaManifest struct { 79 Main map[string]string `json:"main"` 80 NamedSections map[string]map[string]string `json:"namedSections"` 81 } 82 83 func (m *JavaManifest) UnmarshalJSON(b []byte) error { 84 var either map[string]any 85 err := json.Unmarshal(b, &either) 86 if err != nil { 87 return fmt.Errorf("could not unmarshal java manifest: %w", err) 88 } 89 if _, ok := either["namedSections"]; ok { 90 var lm legacyJavaManifest 91 if err = json.Unmarshal(b, &lm); err != nil { 92 return fmt.Errorf("could not unmarshal java manifest: %w", err) 93 } 94 *m = lm.toNewManifest() 95 return nil 96 } 97 var jm unmarshalJavaManifest 98 err = json.Unmarshal(b, &jm) 99 if err != nil { 100 return fmt.Errorf("could not unmarshal java manifest: %w", err) 101 } 102 *m = JavaManifest(jm) 103 return nil 104 } 105 106 func (lm legacyJavaManifest) toNewManifest() JavaManifest { 107 var result JavaManifest 108 result.Main = keyValuesFromMap(lm.Main) 109 var sectionNames []string 110 for k := range lm.NamedSections { 111 sectionNames = append(sectionNames, k) 112 } 113 sort.Strings(sectionNames) 114 var sections []KeyValues 115 for _, name := range sectionNames { 116 section := KeyValues{ 117 KeyValue{ 118 Key: "Name", 119 Value: name, 120 }, 121 } 122 section = append(section, keyValuesFromMap(lm.NamedSections[name])...) 123 sections = append(sections, section) 124 } 125 result.Sections = sections 126 return result 127 } 128 129 func (m JavaManifest) Section(name string) KeyValues { 130 for _, section := range m.Sections { 131 if sectionName, ok := section.Get("Name"); ok && sectionName == name { 132 return section 133 } 134 } 135 return nil 136 }