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  }