github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/golang/parse_go_mod_test.go (about) 1 package golang 2 3 import ( 4 "path/filepath" 5 "testing" 6 7 "github.com/google/go-cmp/cmp" 8 "github.com/stretchr/testify/require" 9 10 "github.com/anchore/syft/syft/artifact" 11 "github.com/anchore/syft/syft/file" 12 "github.com/anchore/syft/syft/internal/fileresolver" 13 "github.com/anchore/syft/syft/pkg" 14 "github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest" 15 ) 16 17 func TestParseGoMod(t *testing.T) { 18 tests := []struct { 19 fixture string 20 expected []pkg.Package 21 }{ 22 { 23 fixture: "test-fixtures/go-mod-fixtures/one-package/go.mod", 24 expected: []pkg.Package{ 25 { 26 Name: "github.com/bmatcuk/doublestar", 27 Version: "v1.3.1", 28 PURL: "pkg:golang/github.com/bmatcuk/doublestar@v1.3.1", 29 Locations: file.NewLocationSet(file.NewLocation("test-fixtures/go-mod-fixtures/one-package/go.mod")), 30 Language: pkg.Go, 31 Type: pkg.GoModulePkg, 32 Metadata: pkg.GolangModuleEntry{}, 33 }, 34 }, 35 }, 36 { 37 fixture: "test-fixtures/go-mod-fixtures/relative-replace/go.mod", 38 expected: []pkg.Package{ 39 { 40 Name: "github.com/aws/aws-sdk-go-v2", 41 Version: "", 42 PURL: "pkg:golang/github.com/aws/aws-sdk-go-v2", 43 Language: pkg.Go, 44 Type: pkg.GoModulePkg, 45 Locations: file.NewLocationSet(file.NewLocation("test-fixtures/go-mod-fixtures/relative-replace/go.mod")), 46 Metadata: pkg.GolangModuleEntry{}, 47 }, 48 }, 49 }, 50 { 51 52 fixture: "test-fixtures/go-mod-fixtures/many-packages/go.mod", 53 expected: []pkg.Package{ 54 { 55 Name: "github.com/anchore/archiver/v3", 56 Version: "v3.5.2", 57 PURL: "pkg:golang/github.com/anchore/archiver@v3.5.2#v3", 58 Locations: file.NewLocationSet(file.NewLocation("test-fixtures/go-mod-fixtures/many-packages/go.mod")), 59 Language: pkg.Go, 60 Type: pkg.GoModulePkg, 61 Metadata: pkg.GolangModuleEntry{}, 62 }, 63 { 64 Name: "github.com/anchore/go-testutils", 65 Version: "v0.0.0-20200624184116-66aa578126db", 66 PURL: "pkg:golang/github.com/anchore/go-testutils@v0.0.0-20200624184116-66aa578126db", 67 Locations: file.NewLocationSet(file.NewLocation("test-fixtures/go-mod-fixtures/many-packages/go.mod")), 68 Language: pkg.Go, 69 Type: pkg.GoModulePkg, 70 Metadata: pkg.GolangModuleEntry{}, 71 }, 72 { 73 Name: "github.com/anchore/go-version", 74 Version: "v1.2.2-0.20200701162849-18adb9c92b9b", 75 PURL: "pkg:golang/github.com/anchore/go-version@v1.2.2-0.20200701162849-18adb9c92b9b", 76 Locations: file.NewLocationSet(file.NewLocation("test-fixtures/go-mod-fixtures/many-packages/go.mod")), 77 Language: pkg.Go, 78 Type: pkg.GoModulePkg, 79 Metadata: pkg.GolangModuleEntry{}, 80 }, 81 { 82 Name: "github.com/anchore/stereoscope", 83 Version: "v0.0.0-20200706164556-7cf39d7f4639", 84 PURL: "pkg:golang/github.com/anchore/stereoscope@v0.0.0-20200706164556-7cf39d7f4639", 85 Locations: file.NewLocationSet(file.NewLocation("test-fixtures/go-mod-fixtures/many-packages/go.mod")), 86 Language: pkg.Go, 87 Type: pkg.GoModulePkg, 88 Metadata: pkg.GolangModuleEntry{}, 89 }, 90 { 91 Name: "github.com/bmatcuk/doublestar", 92 Version: "v8.8.8", 93 PURL: "pkg:golang/github.com/bmatcuk/doublestar@v8.8.8", 94 Locations: file.NewLocationSet(file.NewLocation("test-fixtures/go-mod-fixtures/many-packages/go.mod")), 95 Language: pkg.Go, 96 Type: pkg.GoModulePkg, 97 Metadata: pkg.GolangModuleEntry{}, 98 }, 99 { 100 Name: "github.com/go-test/deep", 101 Version: "v1.0.6", 102 PURL: "pkg:golang/github.com/go-test/deep@v1.0.6", 103 Locations: file.NewLocationSet(file.NewLocation("test-fixtures/go-mod-fixtures/many-packages/go.mod")), 104 Language: pkg.Go, 105 Type: pkg.GoModulePkg, 106 Metadata: pkg.GolangModuleEntry{}, 107 }, 108 }, 109 }, 110 } 111 112 for _, test := range tests { 113 t.Run(test.fixture, func(t *testing.T) { 114 c := newGoModCataloger(DefaultCatalogerConfig()) 115 pkgtest.NewCatalogTester(). 116 FromFile(t, test.fixture). 117 Expects(test.expected, nil). 118 WithResolver(fileresolver.Empty{}). 119 TestParser(t, c.parseGoModFile) 120 }) 121 } 122 } 123 124 func Test_GoSumHashes(t *testing.T) { 125 tests := []struct { 126 fixture string 127 expected []pkg.Package 128 }{ 129 { 130 fixture: "test-fixtures/go-sum-hashes", 131 expected: []pkg.Package{ 132 { 133 Name: "github.com/CycloneDX/cyclonedx-go", 134 Version: "v0.6.0", 135 PURL: "pkg:golang/github.com/CycloneDX/cyclonedx-go@v0.6.0", 136 Locations: file.NewLocationSet(file.NewLocation("go.mod")), 137 FoundBy: "go-module-file-cataloger", 138 Language: pkg.Go, 139 Type: pkg.GoModulePkg, 140 Metadata: pkg.GolangModuleEntry{}, 141 }, 142 { 143 Name: "github.com/acarl005/stripansi", 144 Version: "v0.0.0-20180116102854-5a71ef0e047d", 145 PURL: "pkg:golang/github.com/acarl005/stripansi@v0.0.0-20180116102854-5a71ef0e047d", 146 Locations: file.NewLocationSet(file.NewLocation("go.mod")), 147 FoundBy: "go-module-file-cataloger", 148 Language: pkg.Go, 149 Type: pkg.GoModulePkg, 150 Metadata: pkg.GolangModuleEntry{ 151 H1Digest: "h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=", 152 }, 153 }, 154 { 155 Name: "github.com/mgutz/ansi", 156 Version: "v0.0.0-20200706080929-d51e80ef957d", 157 PURL: "pkg:golang/github.com/mgutz/ansi@v0.0.0-20200706080929-d51e80ef957d", 158 Locations: file.NewLocationSet(file.NewLocation("go.mod")), 159 FoundBy: "go-module-file-cataloger", 160 Language: pkg.Go, 161 Type: pkg.GoModulePkg, 162 Metadata: pkg.GolangModuleEntry{ 163 H1Digest: "h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=", 164 }, 165 }, 166 }, 167 }, 168 } 169 170 for _, test := range tests { 171 t.Run(test.fixture, func(t *testing.T) { 172 pkgtest.NewCatalogTester(). 173 FromDirectory(t, test.fixture). 174 Expects(test.expected, nil). 175 TestCataloger(t, NewGoModuleFileCataloger(CatalogerConfig{})) 176 }) 177 } 178 } 179 180 func Test_corruptGoMod(t *testing.T) { 181 c := NewGoModuleFileCataloger(DefaultCatalogerConfig().WithSearchRemoteLicenses(false)) 182 pkgtest.NewCatalogTester(). 183 FromDirectory(t, "test-fixtures/corrupt"). 184 WithError(). 185 TestCataloger(t, c) 186 } 187 188 func Test_parseGoSource_packageResolution(t *testing.T) { 189 tests := []struct { 190 name string 191 fixturePath string 192 config CatalogerConfig 193 expectedPkgs []string 194 expectedRels []string 195 expectedLicenses map[string][]string 196 }{ 197 { 198 name: "go-source with direct, transitive, and deps of transitive", 199 fixturePath: filepath.Join("test-fixtures", "go-source"), 200 expectedPkgs: []string{ 201 "anchore.io/not/real @ (go.mod)", 202 "github.com/davecgh/go-spew @ v1.1.1 (go.mod)", 203 "github.com/go-viper/mapstructure/v2 @ v2.2.1 (go.mod)", 204 "github.com/google/uuid @ v1.6.0 (go.mod)", 205 "github.com/pmezard/go-difflib @ v1.0.0 (go.mod)", 206 "github.com/sagikazarmark/locafero @ v0.7.0 (go.mod)", 207 "github.com/sirupsen/logrus @ v1.9.3 (go.mod)", 208 "github.com/sourcegraph/conc @ v0.3.0 (go.mod)", 209 "github.com/spf13/afero @ v1.12.0 (go.mod)", 210 "github.com/spf13/cast @ v1.7.1 (go.mod)", 211 "github.com/spf13/pflag @ v1.0.6 (go.mod)", 212 "github.com/spf13/viper @ v1.20.1 (go.mod)", 213 "github.com/stretchr/testify @ v1.10.0 (go.mod)", 214 "github.com/subosito/gotenv @ v1.6.0 (go.mod)", 215 "go.uber.org/multierr @ v1.10.0 (go.mod)", 216 "go.uber.org/zap @ v1.27.0 (go.mod)", 217 "golang.org/x/sys @ v0.33.0 (go.mod)", 218 "golang.org/x/text @ v0.21.0 (go.mod)", 219 "gopkg.in/yaml.v3 @ v3.0.1 (go.mod)", 220 "github.com/fsnotify/fsnotify @ v1.8.0 (go.mod)", 221 "github.com/pelletier/go-toml/v2 @ v2.2.3 (go.mod)", 222 "github.com/frankban/quicktest @ v1.14.6 (go.mod)", 223 "github.com/google/go-cmp @ v0.6.0 (go.mod)", 224 "github.com/kr/pretty @ v0.3.1 (go.mod)", 225 "github.com/kr/text @ v0.2.0 (go.mod)", 226 "github.com/rogpeppe/go-internal @ v1.9.0 (go.mod)", 227 "go.uber.org/goleak @ v1.3.0 (go.mod)", 228 "gopkg.in/check.v1 @ v1.0.0-20190902080502-41f04d3bba15 (go.mod)", 229 }, 230 expectedRels: []string{ 231 "github.com/davecgh/go-spew @ v1.1.1 (go.mod) [dependency-of] github.com/stretchr/testify @ v1.10.0 (go.mod)", 232 "github.com/frankban/quicktest @ v1.14.6 (go.mod) [dependency-of] github.com/spf13/cast @ v1.7.1 (go.mod)", 233 "github.com/fsnotify/fsnotify @ v1.8.0 (go.mod) [dependency-of] github.com/spf13/viper @ v1.20.1 (go.mod)", 234 "github.com/go-viper/mapstructure/v2 @ v2.2.1 (go.mod) [dependency-of] github.com/spf13/viper @ v1.20.1 (go.mod)", 235 "github.com/google/go-cmp @ v0.6.0 (go.mod) [dependency-of] github.com/frankban/quicktest @ v1.14.6 (go.mod)", 236 "github.com/google/uuid @ v1.6.0 (go.mod) [dependency-of] anchore.io/not/real @ (go.mod)", 237 "github.com/kr/pretty @ v0.3.1 (go.mod) [dependency-of] github.com/frankban/quicktest @ v1.14.6 (go.mod)", 238 "github.com/kr/pretty @ v0.3.1 (go.mod) [dependency-of] gopkg.in/check.v1 @ v1.0.0-20190902080502-41f04d3bba15 (go.mod)", 239 "github.com/kr/text @ v0.2.0 (go.mod) [dependency-of] github.com/kr/pretty @ v0.3.1 (go.mod)", 240 "github.com/pelletier/go-toml/v2 @ v2.2.3 (go.mod) [dependency-of] github.com/spf13/viper @ v1.20.1 (go.mod)", 241 "github.com/pmezard/go-difflib @ v1.0.0 (go.mod) [dependency-of] github.com/stretchr/testify @ v1.10.0 (go.mod)", 242 "github.com/rogpeppe/go-internal @ v1.9.0 (go.mod) [dependency-of] github.com/kr/pretty @ v0.3.1 (go.mod)", 243 "github.com/sagikazarmark/locafero @ v0.7.0 (go.mod) [dependency-of] github.com/spf13/viper @ v1.20.1 (go.mod)", 244 "github.com/sirupsen/logrus @ v1.9.3 (go.mod) [dependency-of] anchore.io/not/real @ (go.mod)", 245 "github.com/sourcegraph/conc @ v0.3.0 (go.mod) [dependency-of] github.com/sagikazarmark/locafero @ v0.7.0 (go.mod)", 246 "github.com/spf13/afero @ v1.12.0 (go.mod) [dependency-of] github.com/sagikazarmark/locafero @ v0.7.0 (go.mod)", 247 "github.com/spf13/afero @ v1.12.0 (go.mod) [dependency-of] github.com/spf13/viper @ v1.20.1 (go.mod)", 248 "github.com/spf13/cast @ v1.7.1 (go.mod) [dependency-of] github.com/spf13/viper @ v1.20.1 (go.mod)", 249 "github.com/spf13/pflag @ v1.0.6 (go.mod) [dependency-of] github.com/spf13/viper @ v1.20.1 (go.mod)", 250 "github.com/spf13/viper @ v1.20.1 (go.mod) [dependency-of] anchore.io/not/real @ (go.mod)", 251 "github.com/stretchr/testify @ v1.10.0 (go.mod) [dependency-of] anchore.io/not/real @ (go.mod)", 252 "github.com/stretchr/testify @ v1.10.0 (go.mod) [dependency-of] github.com/pelletier/go-toml/v2 @ v2.2.3 (go.mod)", 253 "github.com/stretchr/testify @ v1.10.0 (go.mod) [dependency-of] github.com/sagikazarmark/locafero @ v0.7.0 (go.mod)", 254 "github.com/stretchr/testify @ v1.10.0 (go.mod) [dependency-of] github.com/sirupsen/logrus @ v1.9.3 (go.mod)", 255 "github.com/stretchr/testify @ v1.10.0 (go.mod) [dependency-of] github.com/sourcegraph/conc @ v0.3.0 (go.mod)", 256 "github.com/stretchr/testify @ v1.10.0 (go.mod) [dependency-of] github.com/spf13/viper @ v1.20.1 (go.mod)", 257 "github.com/stretchr/testify @ v1.10.0 (go.mod) [dependency-of] github.com/subosito/gotenv @ v1.6.0 (go.mod)", 258 "github.com/stretchr/testify @ v1.10.0 (go.mod) [dependency-of] go.uber.org/multierr @ v1.10.0 (go.mod)", 259 "github.com/stretchr/testify @ v1.10.0 (go.mod) [dependency-of] go.uber.org/zap @ v1.27.0 (go.mod)", 260 "github.com/subosito/gotenv @ v1.6.0 (go.mod) [dependency-of] github.com/spf13/viper @ v1.20.1 (go.mod)", 261 "go.uber.org/goleak @ v1.3.0 (go.mod) [dependency-of] go.uber.org/zap @ v1.27.0 (go.mod)", 262 "go.uber.org/multierr @ v1.10.0 (go.mod) [dependency-of] go.uber.org/zap @ v1.27.0 (go.mod)", 263 "go.uber.org/zap @ v1.27.0 (go.mod) [dependency-of] anchore.io/not/real @ (go.mod)", 264 "golang.org/x/sys @ v0.33.0 (go.mod) [dependency-of] github.com/fsnotify/fsnotify @ v1.8.0 (go.mod)", 265 "golang.org/x/sys @ v0.33.0 (go.mod) [dependency-of] github.com/sirupsen/logrus @ v1.9.3 (go.mod)", 266 "golang.org/x/text @ v0.21.0 (go.mod) [dependency-of] github.com/spf13/afero @ v1.12.0 (go.mod)", 267 "golang.org/x/text @ v0.21.0 (go.mod) [dependency-of] github.com/subosito/gotenv @ v1.6.0 (go.mod)", 268 "gopkg.in/check.v1 @ v1.0.0-20190902080502-41f04d3bba15 (go.mod) [dependency-of] gopkg.in/yaml.v3 @ v3.0.1 (go.mod)", 269 "gopkg.in/yaml.v3 @ v3.0.1 (go.mod) [dependency-of] github.com/spf13/viper @ v1.20.1 (go.mod)", 270 "gopkg.in/yaml.v3 @ v3.0.1 (go.mod) [dependency-of] github.com/stretchr/testify @ v1.10.0 (go.mod)", 271 "gopkg.in/yaml.v3 @ v3.0.1 (go.mod) [dependency-of] go.uber.org/zap @ v1.27.0 (go.mod)", 272 }, 273 expectedLicenses: map[string][]string{ 274 "github.com/fsnotify/fsnotify": {"BSD-3-Clause"}, 275 "github.com/go-viper/mapstructure/v2": {"MIT"}, 276 "github.com/google/uuid": {"BSD-3-Clause"}, 277 "github.com/pelletier/go-toml/v2": {"MIT"}, 278 "github.com/sagikazarmark/locafero": {"MIT"}, 279 "github.com/sirupsen/logrus": {"MIT"}, 280 "github.com/sourcegraph/conc": {"MIT"}, 281 "github.com/spf13/afero": {"Apache-2.0"}, 282 "github.com/spf13/cast": {"MIT"}, 283 "github.com/spf13/pflag": {"BSD-3-Clause"}, 284 "github.com/spf13/viper": {"MIT"}, 285 "github.com/subosito/gotenv": {"MIT"}, 286 "go.uber.org/multierr": {"MIT"}, 287 "go.uber.org/zap": {"MIT"}, 288 "golang.org/x/sys": {"BSD-3-Clause"}, 289 "golang.org/x/text": {"BSD-3-Clause"}, 290 "gopkg.in/yaml.v3": {"Apache-2.0", "MIT"}, 291 "github.com/davecgh/go-spew": {"ISC"}, 292 "github.com/pmezard/go-difflib": {"BSD-3-Clause"}, 293 "github.com/stretchr/testify": {"MIT"}, 294 "github.com/frankban/quicktest": {"MIT"}, 295 "github.com/google/go-cmp": {"BSD-3-Clause"}, 296 "github.com/kr/text": {"MIT"}, 297 "github.com/kr/pretty": {"MIT"}, 298 "github.com/rogpeppe/go-internal": {"BSD-3-Clause"}, 299 "go.uber.org/goleak": {"MIT"}, 300 "gopkg.in/check.v1": {"BSD-2-Clause"}, 301 }, 302 }, 303 } 304 305 for _, tt := range tests { 306 t.Run(tt.name, func(t *testing.T) { 307 pkgtest.NewCatalogTester(). 308 FromDirectory(t, tt.fixturePath). 309 ExpectsPackageStrings(tt.expectedPkgs). 310 ExpectsRelationshipStrings(tt.expectedRels). 311 ExpectsAssertion(func(t *testing.T, pkgs []pkg.Package, relationships []artifact.Relationship) { 312 for _, p := range pkgs { 313 if metadata, ok := p.Metadata.(pkg.GolangSourceEntry); ok { 314 // Validate that GolangSourceEntry metadata is present but don't assert on specific field values 315 // since these might vary across development machines 316 require.IsType(t, pkg.GolangSourceEntry{}, metadata, "expected GolangSourceEntry metadata for package %s", p.Name) 317 // Verify that the metadata struct is populated (non-zero values indicate go source method was used) 318 require.NotEmpty(t, metadata, "GolangSourceEntry metadata should not be empty for package %s", p.Name) 319 } 320 } 321 }). 322 ExpectsAssertion(func(t *testing.T, pkgs []pkg.Package, relationships []artifact.Relationship) { 323 actualLicenses := make(map[string][]string) 324 for _, p := range pkgs { 325 for _, l := range p.Licenses.ToSlice() { 326 if actualLicenses[p.Name] == nil { 327 actualLicenses[p.Name] = make([]string, 0) 328 } 329 actualLicenses[p.Name] = append(actualLicenses[p.Name], l.Value) 330 } 331 } 332 if diff := cmp.Diff(tt.expectedLicenses, actualLicenses); diff != "" { 333 t.Errorf("mismatch in licenses (-want +got):\n%s", diff) 334 } 335 }). 336 TestCataloger(t, NewGoModuleFileCataloger(CatalogerConfig{})) 337 }) 338 } 339 }