github.com/kastenhq/syft@v0.0.0-20230821225854-0710af25cdbe/syft/formats/common/cyclonedxhelpers/external_references.go (about) 1 package cyclonedxhelpers 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/CycloneDX/cyclonedx-go" 8 9 "github.com/kastenhq/syft/internal/file" 10 syftFile "github.com/kastenhq/syft/syft/file" 11 "github.com/kastenhq/syft/syft/pkg" 12 ) 13 14 //nolint:gocognit 15 func encodeExternalReferences(p pkg.Package) *[]cyclonedx.ExternalReference { 16 var refs []cyclonedx.ExternalReference 17 if hasMetadata(p) { 18 switch metadata := p.Metadata.(type) { 19 case pkg.ApkMetadata: 20 if metadata.URL != "" { 21 refs = append(refs, cyclonedx.ExternalReference{ 22 URL: metadata.URL, 23 Type: cyclonedx.ERTypeDistribution, 24 }) 25 } 26 case pkg.CargoPackageMetadata: 27 if metadata.Source != "" { 28 refs = append(refs, cyclonedx.ExternalReference{ 29 URL: metadata.Source, 30 Type: cyclonedx.ERTypeDistribution, 31 }) 32 } 33 case pkg.NpmPackageJSONMetadata: 34 if metadata.URL != "" { 35 refs = append(refs, cyclonedx.ExternalReference{ 36 URL: metadata.URL, 37 Type: cyclonedx.ERTypeDistribution, 38 }) 39 } 40 if metadata.Homepage != "" { 41 refs = append(refs, cyclonedx.ExternalReference{ 42 URL: metadata.Homepage, 43 Type: cyclonedx.ERTypeWebsite, 44 }) 45 } 46 case pkg.GemMetadata: 47 if metadata.Homepage != "" { 48 refs = append(refs, cyclonedx.ExternalReference{ 49 URL: metadata.Homepage, 50 Type: cyclonedx.ERTypeWebsite, 51 }) 52 } 53 case pkg.JavaMetadata: 54 if len(metadata.ArchiveDigests) > 0 { 55 for _, digest := range metadata.ArchiveDigests { 56 refs = append(refs, cyclonedx.ExternalReference{ 57 URL: "", 58 Type: cyclonedx.ERTypeBuildMeta, 59 Hashes: &[]cyclonedx.Hash{{ 60 Algorithm: toCycloneDXAlgorithm(digest.Algorithm), 61 Value: digest.Value, 62 }}, 63 }) 64 } 65 } 66 case pkg.PythonPackageMetadata: 67 if metadata.DirectURLOrigin != nil && metadata.DirectURLOrigin.URL != "" { 68 ref := cyclonedx.ExternalReference{ 69 URL: metadata.DirectURLOrigin.URL, 70 Type: cyclonedx.ERTypeVCS, 71 } 72 if metadata.DirectURLOrigin.CommitID != "" { 73 ref.Comment = fmt.Sprintf("commit: %s", metadata.DirectURLOrigin.CommitID) 74 } 75 refs = append(refs, ref) 76 } 77 } 78 } 79 if len(refs) > 0 { 80 return &refs 81 } 82 return nil 83 } 84 85 // supported algorithm in cycloneDX as of 1.4 86 // "MD5", "SHA-1", "SHA-256", "SHA-384", "SHA-512", 87 // "SHA3-256", "SHA3-384", "SHA3-512", "BLAKE2b-256", "BLAKE2b-384", "BLAKE2b-512", "BLAKE3" 88 // syft supported digests: cmd/syft/cli/eventloop/tasks.go 89 // MD5, SHA1, SHA256 90 func toCycloneDXAlgorithm(algorithm string) cyclonedx.HashAlgorithm { 91 validMap := map[string]cyclonedx.HashAlgorithm{ 92 "sha1": cyclonedx.HashAlgorithm("SHA-1"), 93 "md5": cyclonedx.HashAlgorithm("MD5"), 94 "sha256": cyclonedx.HashAlgorithm("SHA-256"), 95 } 96 97 return validMap[algorithm] 98 } 99 100 func decodeExternalReferences(c *cyclonedx.Component, metadata interface{}) { 101 if c.ExternalReferences == nil { 102 return 103 } 104 switch meta := metadata.(type) { 105 case *pkg.ApkMetadata: 106 meta.URL = refURL(c, cyclonedx.ERTypeDistribution) 107 case *pkg.CargoPackageMetadata: 108 meta.Source = refURL(c, cyclonedx.ERTypeDistribution) 109 case *pkg.NpmPackageJSONMetadata: 110 meta.URL = refURL(c, cyclonedx.ERTypeDistribution) 111 meta.Homepage = refURL(c, cyclonedx.ERTypeWebsite) 112 case *pkg.GemMetadata: 113 meta.Homepage = refURL(c, cyclonedx.ERTypeWebsite) 114 case *pkg.JavaMetadata: 115 var digests []syftFile.Digest 116 if ref := findExternalRef(c, cyclonedx.ERTypeBuildMeta); ref != nil { 117 if ref.Hashes != nil { 118 for _, hash := range *ref.Hashes { 119 digests = append(digests, syftFile.Digest{ 120 Algorithm: file.CleanDigestAlgorithmName(string(hash.Algorithm)), 121 Value: hash.Value, 122 }) 123 } 124 } 125 } 126 127 meta.ArchiveDigests = digests 128 case *pkg.PythonPackageMetadata: 129 if meta.DirectURLOrigin == nil { 130 meta.DirectURLOrigin = &pkg.PythonDirectURLOriginInfo{} 131 } 132 meta.DirectURLOrigin.URL = refURL(c, cyclonedx.ERTypeVCS) 133 meta.DirectURLOrigin.CommitID = strings.TrimPrefix(refComment(c, cyclonedx.ERTypeVCS), "commit: ") 134 } 135 } 136 137 func findExternalRef(c *cyclonedx.Component, typ cyclonedx.ExternalReferenceType) *cyclonedx.ExternalReference { 138 if c.ExternalReferences != nil { 139 for _, r := range *c.ExternalReferences { 140 if r.Type == typ { 141 return &r 142 } 143 } 144 } 145 return nil 146 } 147 148 func refURL(c *cyclonedx.Component, typ cyclonedx.ExternalReferenceType) string { 149 if r := findExternalRef(c, typ); r != nil { 150 return r.URL 151 } 152 return "" 153 } 154 155 func refComment(c *cyclonedx.Component, typ cyclonedx.ExternalReferenceType) string { 156 if r := findExternalRef(c, typ); r != nil { 157 return r.Comment 158 } 159 return "" 160 }