diff --git a/internal/cache/filesystem.go b/internal/cache/filesystem.go index 8b628cc50..6e7175999 100644 --- a/internal/cache/filesystem.go +++ b/internal/cache/filesystem.go @@ -87,7 +87,7 @@ func subFs(fsys afero.Fs, subDirs ...string) (afero.Fs, error) { if errors.Is(err, afero.ErrFileNotFound) { err = fsys.MkdirAll(dir, dirPermissions) if err != nil { - return nil, fmt.Errorf("unable to create directory at '%s/%s': %v", dir, strings.Join(subDirs, "/"), err) + return nil, fmt.Errorf("unable to create directory at '%s': %v", dir, err) } stat, err = fsys.Stat(dir) if err != nil { diff --git a/internal/cache/filesystem_test.go b/internal/cache/filesystem_test.go index 721cb9f6a..47c693042 100644 --- a/internal/cache/filesystem_test.go +++ b/internal/cache/filesystem_test.go @@ -1,6 +1,7 @@ package cache import ( + "fmt" "io" "net/url" "os" @@ -92,3 +93,14 @@ func Test_makeDiskKey(t *testing.T) { }) } } + +func Test_errors(t *testing.T) { + tmp := t.TempDir() + cache := filepath.Join(tmp, "cache") + // make a non-writable directory + require.NoError(t, os.MkdirAll(cache, 0500|os.ModeDir)) + // attempt to make cache in non-writable directory + dir := filepath.Join(cache, "dir") + _, err := NewFromDir(dir, time.Hour) + require.ErrorContains(t, err, fmt.Sprintf("unable to create directory at '%s':", dir)) +} diff --git a/syft/pkg/cataloger/golang/licenses.go b/syft/pkg/cataloger/golang/licenses.go index 911d386cc..f53246314 100644 --- a/syft/pkg/cataloger/golang/licenses.go +++ b/syft/pkg/cataloger/golang/licenses.go @@ -138,7 +138,15 @@ func (c *goLicenseResolver) getLicensesFromRemote(moduleName, moduleVersion stri func (c *goLicenseResolver) findLicensesInFS(urlPrefix string, fsys fs.FS) ([]goLicense, error) { var out []goLicense - err := fs.WalkDir(fsys, ".", func(filePath string, d fs.DirEntry, _ error) error { + err := fs.WalkDir(fsys, ".", func(filePath string, d fs.DirEntry, err error) error { + if err != nil { + log.Debugf("error reading %s#%s: %v", urlPrefix, filePath, err) + return err + } + if d == nil { + log.Debugf("nil entry for %s#%s", urlPrefix, filePath) + return nil + } if !c.lowerLicenseFileNames.Has(strings.ToLower(d.Name())) { return nil } diff --git a/syft/pkg/cataloger/golang/licenses_test.go b/syft/pkg/cataloger/golang/licenses_test.go index d34d59e5a..0ac644faf 100644 --- a/syft/pkg/cataloger/golang/licenses_test.go +++ b/syft/pkg/cataloger/golang/licenses_test.go @@ -4,6 +4,7 @@ import ( "archive/zip" "bytes" "fmt" + "io/fs" "net/http" "net/http/httptest" "os" @@ -244,3 +245,62 @@ func Test_findVersionPath(t *testing.T) { vp := findVersionPath(f, ".") require.Equal(t, "github.com/someorg/somepkg@version", vp) } + +func Test_walkDirErrors(t *testing.T) { + resolver := newGoLicenseResolver("", CatalogerConfig{}) + _, err := resolver.findLicensesInFS("somewhere", badFS{}) + require.Error(t, err) +} + +type badFS struct{} + +func (b badFS) Open(_ string) (fs.File, error) { + return nil, fmt.Errorf("error") +} + +var _ fs.FS = (*badFS)(nil) + +func Test_noLocalGoModDir(t *testing.T) { + emptyTmp := t.TempDir() + + validTmp := t.TempDir() + require.NoError(t, os.MkdirAll(filepath.Join(validTmp, "mod@ver"), 0700|os.ModeDir)) + + tests := []struct { + name string + dir string + wantErr require.ErrorAssertionFunc + }{ + { + name: "empty", + dir: "", + wantErr: require.Error, + }, + { + name: "invalid dir", + dir: filepath.Join(emptyTmp, "invalid-dir"), + wantErr: require.Error, + }, + { + name: "missing mod dir", + dir: emptyTmp, + wantErr: require.Error, + }, + { + name: "valid mod dir", + dir: validTmp, + wantErr: require.NoError, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + resolver := newGoLicenseResolver("", CatalogerConfig{ + SearchLocalModCacheLicenses: true, + LocalModCacheDir: test.dir, + }) + _, err := resolver.getLicensesFromLocal("mod", "ver") + test.wantErr(t, err) + }) + } +}