clear devel version for go packages (#3873)

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Alex Goodman 2025-05-09 13:36:52 -04:00 committed by GitHub
parent 0b78186a97
commit a7816dc9e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 79 additions and 56 deletions

View File

@ -53,7 +53,7 @@ func Test_PackageCataloger_Binary(t *testing.T) {
// see the dockerfile for details // see the dockerfile for details
fixture: "image-not-a-module", fixture: "image-not-a-module",
expectedPkgs: []string{ expectedPkgs: []string{
"command-line-arguments @ (devel) (/run-me)", // this is the difference! "command-line-arguments @ (/run-me)", // this is the difference!
"github.com/andybalholm/brotli @ v1.1.1 (/run-me)", "github.com/andybalholm/brotli @ v1.1.1 (/run-me)",
"github.com/dsnet/compress @ v0.0.2-0.20210315054119-f66993602bf5 (/run-me)", "github.com/dsnet/compress @ v0.0.2-0.20210315054119-f66993602bf5 (/run-me)",
"github.com/golang/snappy @ v0.0.4 (/run-me)", "github.com/golang/snappy @ v0.0.4 (/run-me)",
@ -67,17 +67,17 @@ func Test_PackageCataloger_Binary(t *testing.T) {
"stdlib @ go1.23.2 (/run-me)", "stdlib @ go1.23.2 (/run-me)",
}, },
expectedRels: []string{ expectedRels: []string{
"github.com/anchore/archiver/v3 @ v3.5.3-0.20241210171143-5b1d8d1c7c51 (/run-me) [dependency-of] command-line-arguments @ (devel) (/run-me)", "github.com/anchore/archiver/v3 @ v3.5.3-0.20241210171143-5b1d8d1c7c51 (/run-me) [dependency-of] command-line-arguments @ (/run-me)",
"github.com/andybalholm/brotli @ v1.1.1 (/run-me) [dependency-of] command-line-arguments @ (devel) (/run-me)", "github.com/andybalholm/brotli @ v1.1.1 (/run-me) [dependency-of] command-line-arguments @ (/run-me)",
"github.com/dsnet/compress @ v0.0.2-0.20210315054119-f66993602bf5 (/run-me) [dependency-of] command-line-arguments @ (devel) (/run-me)", "github.com/dsnet/compress @ v0.0.2-0.20210315054119-f66993602bf5 (/run-me) [dependency-of] command-line-arguments @ (/run-me)",
"github.com/golang/snappy @ v0.0.4 (/run-me) [dependency-of] command-line-arguments @ (devel) (/run-me)", "github.com/golang/snappy @ v0.0.4 (/run-me) [dependency-of] command-line-arguments @ (/run-me)",
"github.com/klauspost/compress @ v1.17.11 (/run-me) [dependency-of] command-line-arguments @ (devel) (/run-me)", "github.com/klauspost/compress @ v1.17.11 (/run-me) [dependency-of] command-line-arguments @ (/run-me)",
"github.com/klauspost/pgzip @ v1.2.6 (/run-me) [dependency-of] command-line-arguments @ (devel) (/run-me)", "github.com/klauspost/pgzip @ v1.2.6 (/run-me) [dependency-of] command-line-arguments @ (/run-me)",
"github.com/nwaples/rardecode @ v1.1.3 (/run-me) [dependency-of] command-line-arguments @ (devel) (/run-me)", "github.com/nwaples/rardecode @ v1.1.3 (/run-me) [dependency-of] command-line-arguments @ (/run-me)",
"github.com/pierrec/lz4/v4 @ v4.1.21 (/run-me) [dependency-of] command-line-arguments @ (devel) (/run-me)", "github.com/pierrec/lz4/v4 @ v4.1.21 (/run-me) [dependency-of] command-line-arguments @ (/run-me)",
"github.com/ulikunitz/xz @ v0.5.12 (/run-me) [dependency-of] command-line-arguments @ (devel) (/run-me)", "github.com/ulikunitz/xz @ v0.5.12 (/run-me) [dependency-of] command-line-arguments @ (/run-me)",
"github.com/xi2/xz @ v0.0.0-20171230120015-48954b6210f8 (/run-me) [dependency-of] command-line-arguments @ (devel) (/run-me)", "github.com/xi2/xz @ v0.0.0-20171230120015-48954b6210f8 (/run-me) [dependency-of] command-line-arguments @ (/run-me)",
"stdlib @ go1.23.2 (/run-me) [dependency-of] command-line-arguments @ (devel) (/run-me)", "stdlib @ go1.23.2 (/run-me) [dependency-of] command-line-arguments @ (/run-me)",
}, },
}, },
} }

View File

@ -9,28 +9,28 @@ import (
"github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/pkg"
) )
func (c *goBinaryCataloger) newGoBinaryPackage(dep *debug.Module, mainModule, goVersion, architecture string, buildSettings pkg.KeyValues, cryptoSettings, experiments []string, licenses []pkg.License, locations ...file.Location) pkg.Package { func (c *goBinaryCataloger) newGoBinaryPackage(dep *debug.Module, m pkg.GolangBinaryBuildinfoEntry, licenses []pkg.License, locations ...file.Location) pkg.Package {
if dep.Replace != nil { if dep.Replace != nil {
dep = dep.Replace dep = dep.Replace
} }
version := dep.Version
if version == devel {
// this is a special case for the "devel" version, which is used when the module is built from source
// and there is no vcs tag info available. In this case, we remove the placeholder to indicate
// we don't know the version.
version = ""
}
p := pkg.Package{ p := pkg.Package{
Name: dep.Path, Name: dep.Path,
Version: dep.Version, Version: version,
Licenses: pkg.NewLicenseSet(licenses...), Licenses: pkg.NewLicenseSet(licenses...),
PURL: packageURL(dep.Path, dep.Version), PURL: packageURL(dep.Path, version),
Language: pkg.Go, Language: pkg.Go,
Type: pkg.GoModulePkg, Type: pkg.GoModulePkg,
Locations: file.NewLocationSet(locations...), Locations: file.NewLocationSet(locations...),
Metadata: pkg.GolangBinaryBuildinfoEntry{ Metadata: m,
GoCompiledVersion: goVersion,
H1Digest: dep.Sum,
Architecture: architecture,
BuildSettings: buildSettings,
MainModule: mainModule,
GoCryptoSettings: cryptoSettings,
GoExperiments: experiments,
},
} }
p.SetID() p.SetID()
@ -38,6 +38,22 @@ func (c *goBinaryCataloger) newGoBinaryPackage(dep *debug.Module, mainModule, go
return p return p
} }
func newBinaryMetadata(dep *debug.Module, mainModule, goVersion, architecture string, buildSettings pkg.KeyValues, cryptoSettings, experiments []string) pkg.GolangBinaryBuildinfoEntry {
if dep.Replace != nil {
dep = dep.Replace
}
return pkg.GolangBinaryBuildinfoEntry{
GoCompiledVersion: goVersion,
H1Digest: dep.Sum,
Architecture: architecture,
BuildSettings: buildSettings,
MainModule: mainModule,
GoCryptoSettings: cryptoSettings,
GoExperiments: experiments,
}
}
func packageURL(moduleName, moduleVersion string) string { func packageURL(moduleName, moduleVersion string) string {
// source: https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst#golang // source: https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst#golang
// note: "The version is often empty when a commit is not specified and should be the commit in most cases when available." // note: "The version is often empty when a commit is not specified and should be the commit in most cases when available."

View File

@ -124,7 +124,8 @@ func (c *goBinaryCataloger) buildGoPkgInfo(ctx context.Context, licenseScanner l
lics := c.licenseResolver.getLicenses(ctx, licenseScanner, resolver, dep.Path, dep.Version) lics := c.licenseResolver.getLicenses(ctx, licenseScanner, resolver, dep.Path, dep.Version)
gover, experiments := getExperimentsFromVersion(mod.GoVersion) gover, experiments := getExperimentsFromVersion(mod.GoVersion)
p := c.newGoBinaryPackage(
m := newBinaryMetadata(
dep, dep,
mod.Main.Path, mod.Main.Path,
gover, gover,
@ -132,6 +133,11 @@ func (c *goBinaryCataloger) buildGoPkgInfo(ctx context.Context, licenseScanner l
nil, nil,
mod.cryptoSettings, mod.cryptoSettings,
experiments, experiments,
)
p := c.newGoBinaryPackage(
dep,
m,
lics, lics,
location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
) )
@ -163,7 +169,8 @@ func (c *goBinaryCataloger) makeGoMainPackage(ctx context.Context, licenseScanne
gbs := getBuildSettings(mod.Settings) gbs := getBuildSettings(mod.Settings)
lics := c.licenseResolver.getLicenses(ctx, licenseScanner, resolver, mod.Main.Path, mod.Main.Version) lics := c.licenseResolver.getLicenses(ctx, licenseScanner, resolver, mod.Main.Path, mod.Main.Version)
gover, experiments := getExperimentsFromVersion(mod.GoVersion) gover, experiments := getExperimentsFromVersion(mod.GoVersion)
main := c.newGoBinaryPackage(
m := newBinaryMetadata(
&mod.Main, &mod.Main,
mod.Main.Path, mod.Main.Path,
gover, gover,
@ -171,33 +178,27 @@ func (c *goBinaryCataloger) makeGoMainPackage(ctx context.Context, licenseScanne
gbs, gbs,
mod.cryptoSettings, mod.cryptoSettings,
experiments, experiments,
)
if mod.Main.Version == devel {
version := c.findMainModuleVersion(&m, gbs, reader)
if version != "" {
// make sure version is prefixed with v as some build systems parsed
// during `findMainModuleVersion` can include incomplete semver
// vx.x.x is correct
version = ensurePrefix(version, "v")
}
mod.Main.Version = version
}
main := c.newGoBinaryPackage(
&mod.Main,
m,
lics, lics,
location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
) )
if main.Version != devel {
// found a full package with a non-development version... return it as is...
return main
}
// we have a package, but the version is "devel"... let's try and find a better answer
var metadata *pkg.GolangBinaryBuildinfoEntry
if v, ok := main.Metadata.(pkg.GolangBinaryBuildinfoEntry); ok {
metadata = &v
}
version := c.findMainModuleVersion(metadata, gbs, reader)
if version != "" {
// make sure version is prefixed with v as some build systems parsed
// during `findMainModuleVersion` can include incomplete semver
// vx.x.x is correct
version = ensurePrefix(version, "v")
main.Version = version
main.PURL = packageURL(main.Name, main.Version)
main.SetID()
}
return main return main
} }

View File

@ -152,8 +152,8 @@ func TestBuildGoPkgInfo(t *testing.T) {
Name: "github.com/anchore/syft", Name: "github.com/anchore/syft",
Language: pkg.Go, Language: pkg.Go,
Type: pkg.GoModulePkg, Type: pkg.GoModulePkg,
Version: "(devel)", Version: "", // this was (devel) but we cleared it explicitly
PURL: "pkg:golang/github.com/anchore/syft@%28devel%29", PURL: "pkg:golang/github.com/anchore/syft",
Locations: file.NewLocationSet( Locations: file.NewLocationSet(
file.NewLocationFromCoordinates( file.NewLocationFromCoordinates(
file.Coordinates{ file.Coordinates{
@ -178,6 +178,7 @@ func TestBuildGoPkgInfo(t *testing.T) {
name string name string
mod *extendedBuildInfo mod *extendedBuildInfo
expected []pkg.Package expected []pkg.Package
cfg *CatalogerConfig
binaryContent string binaryContent string
}{ }{
{ {
@ -282,8 +283,8 @@ func TestBuildGoPkgInfo(t *testing.T) {
expected: []pkg.Package{ expected: []pkg.Package{
{ {
Name: "github.com/a/b/c", Name: "github.com/a/b/c",
Version: "(devel)", Version: "", // this was (devel) but we cleared it explicitly
PURL: "pkg:golang/github.com/a/b@%28devel%29#c", PURL: "pkg:golang/github.com/a/b#c",
Language: pkg.Go, Language: pkg.Go,
Type: pkg.GoModulePkg, Type: pkg.GoModulePkg,
Locations: file.NewLocationSet( Locations: file.NewLocationSet(
@ -934,8 +935,8 @@ func TestBuildGoPkgInfo(t *testing.T) {
Name: "github.com/anchore/syft", Name: "github.com/anchore/syft",
Language: pkg.Go, Language: pkg.Go,
Type: pkg.GoModulePkg, Type: pkg.GoModulePkg,
Version: "(devel)", Version: "", // this was (devel) but we cleared it explicitly
PURL: "pkg:golang/github.com/anchore/syft@%28devel%29", PURL: "pkg:golang/github.com/anchore/syft",
Locations: file.NewLocationSet( Locations: file.NewLocationSet(
file.NewLocationFromCoordinates( file.NewLocationFromCoordinates(
file.Coordinates{ file.Coordinates{
@ -1057,7 +1058,12 @@ func TestBuildGoPkgInfo(t *testing.T) {
}, },
) )
c := newGoBinaryCataloger(DefaultCatalogerConfig()) if test.cfg == nil {
c := DefaultCatalogerConfig()
test.cfg = &c
}
c := newGoBinaryCataloger(*test.cfg)
reader, err := unionreader.GetUnionReader(io.NopCloser(strings.NewReader(test.binaryContent))) reader, err := unionreader.GetUnionReader(io.NopCloser(strings.NewReader(test.binaryContent)))
require.NoError(t, err) require.NoError(t, err)
mainPkg, pkgs := c.buildGoPkgInfo(context.Background(), licenseScanner, fileresolver.Empty{}, location, test.mod, test.mod.arch, reader) mainPkg, pkgs := c.buildGoPkgInfo(context.Background(), licenseScanner, fileresolver.Empty{}, location, test.mod, test.mod.arch, reader)