github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/gosbom/formats/common/spdxhelpers/license.go (about) 1 package spdxhelpers 2 3 import ( 4 "strings" 5 6 "github.com/nextlinux/gosbom/gosbom/license" 7 "github.com/nextlinux/gosbom/gosbom/pkg" 8 "github.com/nextlinux/gosbom/internal/spdxlicense" 9 ) 10 11 func License(p pkg.Package) (concluded, declared string) { 12 // source: https://spdx.github.io/spdx-spec/3-package-information/#313-concluded-license 13 // The options to populate this field are limited to: 14 // A valid SPDX License Expression as defined in Appendix IV; 15 // NONE, if the SPDX file creator concludes there is no license available for this package; or 16 // NOASSERTION if: 17 // (i) the SPDX file creator has attempted to but cannot reach a reasonable objective determination; 18 // (ii) the SPDX file creator has made no attempt to determine this field; or 19 // (iii) the SPDX file creator has intentionally provided no information (no meaning should be implied by doing so). 20 21 if p.Licenses.Empty() { 22 return NOASSERTION, NOASSERTION 23 } 24 25 // take all licenses and assume an AND expression; 26 // for information about license expressions see: 27 // https://spdx.github.io/spdx-spec/v2.3/SPDX-license-expressions/ 28 pc, pd := parseLicenses(p.Licenses.ToSlice()) 29 30 for i, v := range pc { 31 if strings.HasPrefix(v, spdxlicense.LicenseRefPrefix) { 32 pc[i] = SanitizeElementID(v) 33 } 34 } 35 36 for i, v := range pd { 37 if strings.HasPrefix(v, spdxlicense.LicenseRefPrefix) { 38 pd[i] = SanitizeElementID(v) 39 } 40 } 41 42 return joinLicenses(pc), joinLicenses(pd) 43 } 44 45 func joinLicenses(licenses []string) string { 46 if len(licenses) == 0 { 47 return NOASSERTION 48 } 49 50 var newLicenses []string 51 52 for _, v := range licenses { 53 // check if license does not start or end with parens 54 if !strings.HasPrefix(v, "(") && !strings.HasSuffix(v, ")") { 55 // if license contains AND, OR, or WITH, then wrap in parens 56 if strings.Contains(v, " AND ") || 57 strings.Contains(v, " OR ") || 58 strings.Contains(v, " WITH ") { 59 newLicenses = append(newLicenses, "("+v+")") 60 continue 61 } 62 } 63 newLicenses = append(newLicenses, v) 64 } 65 66 return strings.Join(newLicenses, " AND ") 67 } 68 69 func parseLicenses(raw []pkg.License) (concluded, declared []string) { 70 for _, l := range raw { 71 var candidate string 72 if l.SPDXExpression != "" { 73 candidate = l.SPDXExpression 74 } else { 75 // we did not find a valid SPDX license ID so treat as separate license 76 candidate = spdxlicense.LicenseRefPrefix + l.Value 77 } 78 79 switch l.Type { 80 case license.Concluded: 81 concluded = append(concluded, candidate) 82 case license.Declared: 83 declared = append(declared, candidate) 84 } 85 } 86 return concluded, declared 87 }