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