diff --git a/mage.go b/mage.go index 0ab03e40..49182c73 100644 --- a/mage.go +++ b/mage.go @@ -1,3 +1,4 @@ +//go:build ignore // +build ignore /* diff --git a/pkg/spdx/document.go b/pkg/spdx/document.go index e7928c30..e87fa0d4 100644 --- a/pkg/spdx/document.go +++ b/pkg/spdx/document.go @@ -260,7 +260,7 @@ func (d *Document) Render() (doc string, err error) { return "", fmt.Errorf("rendering file "+file.Name+" :%w", err) } docSb255.WriteString(fileDoc) - filesDescribedSb255.WriteString(fmt.Sprintf("Relationship: %s DESCRIBES %s\n\n", d.ID, file.ID)) + fmt.Fprintf(&filesDescribedSb255, "Relationship: %s DESCRIBES %s\n\n", d.ID, file.ID) } doc += docSb255.String() filesDescribed += filesDescribedSb255.String() @@ -275,7 +275,7 @@ func (d *Document) Render() (doc string, err error) { } docSb266.WriteString(pkgDoc) - docSb266.WriteString(fmt.Sprintf("Relationship: %s DESCRIBES %s\n\n", d.ID, pkg.ID)) + fmt.Fprintf(&docSb266, "Relationship: %s DESCRIBES %s\n\n", d.ID, pkg.ID) } doc += docSb266.String() diff --git a/pkg/spdx/gomod_test.go b/pkg/spdx/gomod_test.go index 34083762..043e37d7 100644 --- a/pkg/spdx/gomod_test.go +++ b/pkg/spdx/gomod_test.go @@ -17,6 +17,8 @@ limitations under the License. package spdx import ( + "os" + "path/filepath" "strings" "testing" @@ -49,6 +51,29 @@ func TestToSPDXPackage(t *testing.T) { } } +func TestPackageFromDirectory_UsesGoModModulePath(t *testing.T) { + // Create a temporary directory structure with a go.mod at a nested path + dir := t.TempDir() + // Simulate extraction where files are under a subdir + sub := filepath.Join(dir, "submodule") + require.NoError(t, os.MkdirAll(sub, 0o755)) + // Write go.mod with module directive + gomod := "module example.com/my/module\n" + require.NoError(t, os.WriteFile(filepath.Join(sub, "go.mod"), []byte(gomod), 0o600)) + + // Create a dummy file so PackageFromDirectory has something to scan + require.NoError(t, os.WriteFile(filepath.Join(sub, "main.go"), []byte("package main"), 0o600)) + + // Call PackageFromDirectory on the parent dir; implementation should + // discover go.mod in scanned file tree and use module path. + di := &spdxDefaultImplementation{} + opts := &Options{IgnorePatterns: []string{}} + pkg, err := di.PackageFromDirectory(opts, dir) + require.NoError(t, err) + require.NotNil(t, pkg) + require.Equal(t, "example.com/my/module", pkg.Name) +} + func TestPackageURL(t *testing.T) { for _, tc := range []struct { pkg GoPackage diff --git a/pkg/spdx/implementation.go b/pkg/spdx/implementation.go index 4b0a6538..cd475258 100644 --- a/pkg/spdx/implementation.go +++ b/pkg/spdx/implementation.go @@ -1028,7 +1028,43 @@ func (di *spdxDefaultImplementation) PackageFromDirectory(opts *Options, dirPath pkg = NewPackage() pkg.FilesAnalyzed = true + // Default package name is the directory base name. If this directory + // (or one of its top-level children created during extraction) contains + // a go.mod, prefer the module path defined there so the root package + // reflects the module import path instead of a temp dirname. pkg.Name = filepath.Base(dirPath) + + // Look for a go.mod either at the root dirPath or in the scanned file + // tree (which may contain a nested module after extraction). Prefer an + // explicit go.mod at dirPath if present, otherwise use the first + // occurrence from fileList. + goModDir := "" + if helpers.Exists(filepath.Join(dirPath, GoModFileName)) { + goModDir = dirPath + } else { + for _, p := range fileList { + if filepath.Base(p) == GoModFileName { + // p is a relative path; derive the directory containing go.mod + goModDir = filepath.Join(dirPath, filepath.Dir(p)) + break + } + } + } + + if goModDir != "" { + // Try to read the module path from go.mod without doing full module + // processing. NewGoModuleFromPath provides a GoModule with the + // GoModDefaultImpl which implements OpenModule for parsing only. + if gm, err := NewGoModuleFromPath(goModDir); err == nil { + if gomod, err := gm.impl.OpenModule(gm.Options()); err == nil { + if gomod != nil && gomod.Module != nil && gomod.Module.Mod.Path != "" { + pkg.Name = gomod.Module.Mod.Path + } + } else { + logrus.Debugf("unable to parse go.mod for %s: %v", goModDir, err) + } + } + } if pkg.Name == "" { pkg.Name = uuid.NewString() }