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