github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/gosbom/pkg/cataloger/golang/licenses_test.go (about)

     1  package golang
     2  
     3  import (
     4  	"archive/zip"
     5  	"bytes"
     6  	"fmt"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"os"
    10  	"path"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/nextlinux/gosbom/gosbom/file"
    15  	"github.com/nextlinux/gosbom/gosbom/internal/fileresolver"
    16  	"github.com/nextlinux/gosbom/gosbom/license"
    17  	"github.com/nextlinux/gosbom/gosbom/pkg"
    18  	"github.com/nextlinux/gosbom/internal"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  func Test_LocalLicenseSearch(t *testing.T) {
    23  	loc1 := file.NewLocation("github.com/someorg/somename@v0.3.2/LICENSE")
    24  	loc2 := file.NewLocation("github.com/!cap!o!r!g/!cap!project@v4.111.5/LICENSE.txt")
    25  
    26  	tests := []struct {
    27  		name     string
    28  		version  string
    29  		expected pkg.License
    30  	}{
    31  		{
    32  			name:    "github.com/someorg/somename",
    33  			version: "v0.3.2",
    34  			expected: pkg.License{
    35  				Value:          "Apache-2.0",
    36  				SPDXExpression: "Apache-2.0",
    37  				Type:           license.Concluded,
    38  				Locations:      file.NewLocationSet(loc1),
    39  				URLs:           internal.NewStringSet(),
    40  			},
    41  		},
    42  		{
    43  			name:    "github.com/CapORG/CapProject",
    44  			version: "v4.111.5",
    45  			expected: pkg.License{
    46  				Value:          "MIT",
    47  				SPDXExpression: "MIT",
    48  				Type:           license.Concluded,
    49  				Locations:      file.NewLocationSet(loc2),
    50  				URLs:           internal.NewStringSet(),
    51  			},
    52  		},
    53  	}
    54  
    55  	wd, err := os.Getwd()
    56  	require.NoError(t, err)
    57  
    58  	for _, test := range tests {
    59  		t.Run(test.name, func(t *testing.T) {
    60  			l := newGoLicenses(
    61  				GoCatalogerOpts{
    62  					searchLocalModCacheLicenses: true,
    63  					localModCacheDir:            path.Join(wd, "test-fixtures", "licenses", "pkg", "mod"),
    64  				},
    65  			)
    66  			licenses, err := l.getLicenses(fileresolver.Empty{}, test.name, test.version)
    67  			require.NoError(t, err)
    68  
    69  			require.Len(t, licenses, 1)
    70  
    71  			require.Equal(t, test.expected, licenses[0])
    72  		})
    73  	}
    74  }
    75  
    76  func Test_RemoteProxyLicenseSearch(t *testing.T) {
    77  	loc1 := file.NewLocation("github.com/someorg/somename@v0.3.2/LICENSE")
    78  	loc2 := file.NewLocation("github.com/!cap!o!r!g/!cap!project@v4.111.5/LICENSE.txt")
    79  
    80  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    81  		buf := &bytes.Buffer{}
    82  		uri := strings.TrimPrefix(strings.TrimSuffix(r.RequestURI, ".zip"), "/")
    83  
    84  		parts := strings.Split(uri, "/@v/")
    85  		modPath := parts[0]
    86  		modVersion := parts[1]
    87  
    88  		wd, err := os.Getwd()
    89  		require.NoError(t, err)
    90  		testDir := path.Join(wd, "test-fixtures", "licenses", "pkg", "mod", processCaps(modPath)+"@"+modVersion)
    91  
    92  		archive := zip.NewWriter(buf)
    93  
    94  		entries, err := os.ReadDir(testDir)
    95  		require.NoError(t, err)
    96  		for _, f := range entries {
    97  			// the zip files downloaded contain a path to the repo that somewhat matches where it ends up on disk,
    98  			// so prefix entries with something similar
    99  			writer, err := archive.Create(path.Join("github.com/something/some@version", f.Name()))
   100  			require.NoError(t, err)
   101  			contents, err := os.ReadFile(path.Join(testDir, f.Name()))
   102  			require.NoError(t, err)
   103  			_, err = writer.Write(contents)
   104  			require.NoError(t, err)
   105  		}
   106  
   107  		err = archive.Close()
   108  		require.NoError(t, err)
   109  
   110  		w.Header().Add("Content-Length", fmt.Sprintf("%d", buf.Len()))
   111  
   112  		_, err = w.Write(buf.Bytes())
   113  		require.NoError(t, err)
   114  	}))
   115  	defer server.Close()
   116  
   117  	tests := []struct {
   118  		name     string
   119  		version  string
   120  		expected pkg.License
   121  	}{
   122  		{
   123  			name:    "github.com/someorg/somename",
   124  			version: "v0.3.2",
   125  			expected: pkg.License{
   126  				Value:          "Apache-2.0",
   127  				SPDXExpression: "Apache-2.0",
   128  				Type:           license.Concluded,
   129  				Locations:      file.NewLocationSet(loc1),
   130  				URLs:           internal.NewStringSet(),
   131  			},
   132  		},
   133  		{
   134  			name:    "github.com/CapORG/CapProject",
   135  			version: "v4.111.5",
   136  			expected: pkg.License{
   137  				Value:          "MIT",
   138  				SPDXExpression: "MIT",
   139  				Type:           license.Concluded,
   140  				Locations:      file.NewLocationSet(loc2),
   141  				URLs:           internal.NewStringSet(),
   142  			},
   143  		},
   144  	}
   145  
   146  	modDir := path.Join(t.TempDir())
   147  
   148  	for _, test := range tests {
   149  		t.Run(test.name, func(t *testing.T) {
   150  			l := newGoLicenses(GoCatalogerOpts{
   151  				searchRemoteLicenses: true,
   152  				proxies:              []string{server.URL},
   153  				localModCacheDir:     modDir,
   154  			})
   155  
   156  			licenses, err := l.getLicenses(fileresolver.Empty{}, test.name, test.version)
   157  			require.NoError(t, err)
   158  
   159  			require.Len(t, licenses, 1)
   160  
   161  			require.Equal(t, test.expected, licenses[0])
   162  		})
   163  	}
   164  }
   165  
   166  func Test_processCaps(t *testing.T) {
   167  	tests := []struct {
   168  		name     string
   169  		expected string
   170  	}{
   171  		{
   172  			name:     "CycloneDX",
   173  			expected: "!cyclone!d!x",
   174  		},
   175  		{
   176  			name:     "Azure",
   177  			expected: "!azure",
   178  		},
   179  		{
   180  			name:     "xkcd",
   181  			expected: "xkcd",
   182  		},
   183  	}
   184  
   185  	for _, test := range tests {
   186  		t.Run(test.name, func(t *testing.T) {
   187  			got := processCaps(test.name)
   188  
   189  			require.Equal(t, test.expected, got)
   190  		})
   191  	}
   192  }
   193  
   194  func Test_remotesForModule(t *testing.T) {
   195  	allProxies := []string{"https://somewhere.org", "direct"}
   196  	directProxy := []string{"direct"}
   197  
   198  	tests := []struct {
   199  		module   string
   200  		noProxy  string
   201  		expected []string
   202  	}{
   203  		{
   204  			module:   "github.com/nextlinux/gosbom",
   205  			expected: allProxies,
   206  		},
   207  		{
   208  			module:   "github.com/anchore/sbom-action",
   209  			noProxy:  "*/anchore/*",
   210  			expected: directProxy,
   211  		},
   212  		{
   213  			module:   "github.com/anchore/sbom-action",
   214  			noProxy:  "*/user/mod,*/anchore/sbom-action",
   215  			expected: directProxy,
   216  		},
   217  	}
   218  
   219  	for _, test := range tests {
   220  		t.Run(test.module, func(t *testing.T) {
   221  			got := remotesForModule(allProxies, strings.Split(test.noProxy, ","), test.module)
   222  			require.Equal(t, test.expected, got)
   223  		})
   224  	}
   225  }
   226  
   227  func Test_findVersionPath(t *testing.T) {
   228  	f := os.DirFS("test-fixtures/zip-fs")
   229  	vp := findVersionPath(f, ".")
   230  	require.Equal(t, "github.com/someorg/somepkg@version", vp)
   231  }