github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/golang/parse_go_binary_test.go (about) 1 package golang 2 3 import ( 4 "bufio" 5 "io" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "runtime/debug" 10 "strconv" 11 "syscall" 12 "testing" 13 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 17 "github.com/anchore/syft/syft/file" 18 "github.com/anchore/syft/syft/internal/fileresolver" 19 "github.com/anchore/syft/syft/pkg" 20 ) 21 22 // make will run the default make target for the given test fixture path 23 func runMakeTarget(t *testing.T, fixtureName string) { 24 cwd, err := os.Getwd() 25 require.NoError(t, err) 26 fixtureDir := filepath.Join(cwd, "test-fixtures/", fixtureName) 27 28 t.Logf("Generating Fixture in %q", fixtureDir) 29 30 cmd := exec.Command("make") 31 cmd.Dir = fixtureDir 32 33 stderr, err := cmd.StderrPipe() 34 require.NoError(t, err) 35 36 stdout, err := cmd.StdoutPipe() 37 require.NoError(t, err) 38 39 err = cmd.Start() 40 require.NoError(t, err) 41 42 show := func(label string, reader io.ReadCloser) { 43 scanner := bufio.NewScanner(reader) 44 scanner.Split(bufio.ScanLines) 45 for scanner.Scan() { 46 t.Logf("%s: %s", label, scanner.Text()) 47 } 48 } 49 go show("out", stdout) 50 go show("err", stderr) 51 52 if err := cmd.Wait(); err != nil { 53 if exiterr, ok := err.(*exec.ExitError); ok { 54 // The program has exited with an exit code != 0 55 56 // This works on both Unix and Windows. Although package 57 // syscall is generally platform dependent, WaitStatus is 58 // defined for both Unix and Windows and in both cases has 59 // an ExitStatus() method with the same signature. 60 if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { 61 if status.ExitStatus() != 0 { 62 t.Fatalf("failed to generate fixture: rc=%d", status.ExitStatus()) 63 } 64 } 65 } else { 66 t.Fatalf("unable to get generate fixture result: %+v", err) 67 } 68 } 69 } 70 71 func Test_getGOARCHFromBin(t *testing.T) { 72 runMakeTarget(t, "archs") 73 74 tests := []struct { 75 name string 76 filepath string 77 expected string 78 }{ 79 { 80 name: "pe", 81 filepath: "test-fixtures/archs/binaries/hello-win-amd64", 82 // see: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types 83 expected: strconv.Itoa(0x8664), 84 }, 85 { 86 name: "elf-ppc64", 87 filepath: "test-fixtures/archs/binaries/hello-linux-ppc64le", 88 expected: "ppc64", 89 }, 90 { 91 name: "mach-o-arm64", 92 filepath: "test-fixtures/archs/binaries/hello-mach-o-arm64", 93 expected: "arm64", 94 }, 95 { 96 name: "linux-arm", 97 filepath: "test-fixtures/archs/binaries/hello-linux-arm", 98 expected: "arm", 99 }, 100 { 101 name: "xcoff-32bit", 102 filepath: "internal/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec", 103 expected: strconv.Itoa(0x1DF), 104 }, 105 { 106 name: "xcoff-64bit", 107 filepath: "internal/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec", 108 expected: strconv.Itoa(0x1F7), 109 }, 110 } 111 112 for _, tt := range tests { 113 f, err := os.Open(tt.filepath) 114 require.NoError(t, err) 115 arch, err := getGOARCHFromBin(f) 116 require.NoError(t, err, "test name: %s", tt.name) 117 assert.Equal(t, tt.expected, arch) 118 } 119 120 } 121 122 func TestBuildGoPkgInfo(t *testing.T) { 123 const ( 124 goCompiledVersion = "1.18" 125 archDetails = "amd64" 126 ) 127 defaultBuildSettings := map[string]string{ 128 "GOARCH": "amd64", 129 "GOOS": "darwin", 130 "GOAMD64": "v1", 131 } 132 133 unmodifiedMain := pkg.Package{ 134 Name: "github.com/anchore/syft", 135 Language: pkg.Go, 136 Type: pkg.GoModulePkg, 137 Version: "(devel)", 138 PURL: "pkg:golang/github.com/anchore/syft@(devel)", 139 Locations: file.NewLocationSet( 140 file.NewLocationFromCoordinates( 141 file.Coordinates{ 142 RealPath: "/a-path", 143 FileSystemID: "layer-id", 144 }, 145 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 146 ), 147 MetadataType: pkg.GolangBinMetadataType, 148 Metadata: pkg.GolangBinMetadata{ 149 GoCompiledVersion: goCompiledVersion, 150 Architecture: archDetails, 151 BuildSettings: defaultBuildSettings, 152 MainModule: "github.com/anchore/syft", 153 }, 154 } 155 156 tests := []struct { 157 name string 158 mod *extendedBuildInfo 159 expected []pkg.Package 160 }{ 161 { 162 name: "package without name", 163 mod: &extendedBuildInfo{ 164 BuildInfo: &debug.BuildInfo{ 165 Deps: []*debug.Module{ 166 { 167 Path: "github.com/adrg/xdg", 168 }, 169 { 170 Path: "", 171 Version: "v0.2.1", 172 }, 173 }, 174 }, 175 cryptoSettings: nil, 176 arch: "", 177 }, 178 expected: []pkg.Package{ 179 { 180 Name: "github.com/adrg/xdg", 181 PURL: "pkg:golang/github.com/adrg/xdg", 182 Language: pkg.Go, 183 Type: pkg.GoModulePkg, 184 Locations: file.NewLocationSet( 185 file.NewLocationFromCoordinates( 186 file.Coordinates{ 187 RealPath: "/a-path", 188 FileSystemID: "layer-id", 189 }, 190 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 191 ), 192 MetadataType: pkg.GolangBinMetadataType, 193 Metadata: pkg.GolangBinMetadata{}, 194 }, 195 }, 196 }, 197 { 198 name: "buildGoPkgInfo parses a blank mod and returns no packages", 199 mod: &extendedBuildInfo{&debug.BuildInfo{}, nil, ""}, 200 expected: []pkg.Package(nil), 201 }, 202 { 203 name: "parse a mod without main module", 204 mod: &extendedBuildInfo{ 205 BuildInfo: &debug.BuildInfo{ 206 GoVersion: goCompiledVersion, 207 Settings: []debug.BuildSetting{ 208 {Key: "GOARCH", Value: archDetails}, 209 {Key: "GOOS", Value: "darwin"}, 210 {Key: "GOAMD64", Value: "v1"}, 211 }, 212 Deps: []*debug.Module{ 213 { 214 Path: "github.com/adrg/xdg", 215 Version: "v0.2.1", 216 Sum: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=", 217 }, 218 }, 219 }, 220 cryptoSettings: nil, 221 arch: archDetails, 222 }, 223 expected: []pkg.Package{ 224 { 225 Name: "github.com/adrg/xdg", 226 Version: "v0.2.1", 227 PURL: "pkg:golang/github.com/adrg/xdg@v0.2.1", 228 Language: pkg.Go, 229 Type: pkg.GoModulePkg, 230 Locations: file.NewLocationSet( 231 file.NewLocationFromCoordinates( 232 file.Coordinates{ 233 RealPath: "/a-path", 234 FileSystemID: "layer-id", 235 }, 236 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 237 ), 238 MetadataType: pkg.GolangBinMetadataType, 239 Metadata: pkg.GolangBinMetadata{ 240 GoCompiledVersion: goCompiledVersion, 241 Architecture: archDetails, 242 H1Digest: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=", 243 }, 244 }, 245 }, 246 }, 247 { 248 name: "parse a mod with path but no main module", 249 mod: &extendedBuildInfo{ 250 BuildInfo: &debug.BuildInfo{ 251 GoVersion: goCompiledVersion, 252 Settings: []debug.BuildSetting{ 253 {Key: "GOARCH", Value: archDetails}, 254 {Key: "GOOS", Value: "darwin"}, 255 {Key: "GOAMD64", Value: "v1"}, 256 }, 257 Path: "github.com/a/b/c", 258 }, 259 cryptoSettings: []string{"boringcrypto + fips"}, 260 arch: archDetails, 261 }, 262 expected: []pkg.Package{ 263 { 264 Name: "github.com/a/b/c", 265 Version: "(devel)", 266 PURL: "pkg:golang/github.com/a/b/c@(devel)", 267 Language: pkg.Go, 268 Type: pkg.GoModulePkg, 269 Locations: file.NewLocationSet( 270 file.NewLocationFromCoordinates( 271 file.Coordinates{ 272 RealPath: "/a-path", 273 FileSystemID: "layer-id", 274 }, 275 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 276 ), 277 MetadataType: pkg.GolangBinMetadataType, 278 Metadata: pkg.GolangBinMetadata{ 279 GoCompiledVersion: goCompiledVersion, 280 Architecture: archDetails, 281 H1Digest: "", 282 BuildSettings: map[string]string{ 283 "GOAMD64": "v1", 284 "GOARCH": "amd64", 285 "GOOS": "darwin", 286 }, 287 MainModule: "github.com/a/b/c", 288 GoCryptoSettings: []string{"boringcrypto + fips"}, 289 }, 290 }, 291 }, 292 }, 293 { 294 name: "parse a mod without packages", 295 mod: &extendedBuildInfo{ 296 BuildInfo: &debug.BuildInfo{ 297 GoVersion: goCompiledVersion, 298 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 299 Settings: []debug.BuildSetting{ 300 {Key: "GOARCH", Value: archDetails}, 301 {Key: "GOOS", Value: "darwin"}, 302 {Key: "GOAMD64", Value: "v1"}, 303 }, 304 }, 305 cryptoSettings: nil, 306 arch: archDetails, 307 }, 308 expected: []pkg.Package{unmodifiedMain}, 309 }, 310 { 311 name: "parse main mod and replace devel pseudo version and ldflags exists (but contains no version)", 312 mod: &extendedBuildInfo{ 313 BuildInfo: &debug.BuildInfo{ 314 GoVersion: goCompiledVersion, 315 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 316 Settings: []debug.BuildSetting{ 317 {Key: "GOARCH", Value: archDetails}, 318 {Key: "GOOS", Value: "darwin"}, 319 {Key: "GOAMD64", Value: "v1"}, 320 {Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"}, 321 {Key: "vcs.time", Value: "2022-10-14T19:54:57Z"}, 322 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X blah=foobar`}, 323 }, 324 }, 325 cryptoSettings: nil, 326 arch: archDetails, 327 }, 328 expected: []pkg.Package{ 329 { 330 Name: "github.com/anchore/syft", 331 Language: pkg.Go, 332 Type: pkg.GoModulePkg, 333 Version: "v0.0.0-20221014195457-41bc6bb41035", 334 PURL: "pkg:golang/github.com/anchore/syft@v0.0.0-20221014195457-41bc6bb41035", 335 Locations: file.NewLocationSet( 336 file.NewLocationFromCoordinates( 337 file.Coordinates{ 338 RealPath: "/a-path", 339 FileSystemID: "layer-id", 340 }, 341 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 342 ), 343 MetadataType: pkg.GolangBinMetadataType, 344 Metadata: pkg.GolangBinMetadata{ 345 GoCompiledVersion: goCompiledVersion, 346 Architecture: archDetails, 347 BuildSettings: map[string]string{ 348 "GOARCH": archDetails, 349 "GOOS": "darwin", 350 "GOAMD64": "v1", 351 "vcs.revision": "41bc6bb410352845f22766e27dd48ba93aa825a4", 352 "vcs.time": "2022-10-14T19:54:57Z", 353 "-ldflags": `build -ldflags="-w -s -extldflags '-static' -X blah=foobar`, 354 }, 355 MainModule: "github.com/anchore/syft", 356 }, 357 }, 358 }, 359 }, 360 { 361 name: "parse main mod and replace devel version with one from ldflags with vcs. build settings", 362 mod: &extendedBuildInfo{ 363 BuildInfo: &debug.BuildInfo{ 364 GoVersion: goCompiledVersion, 365 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 366 Settings: []debug.BuildSetting{ 367 {Key: "GOARCH", Value: archDetails}, 368 {Key: "GOOS", Value: "darwin"}, 369 {Key: "GOAMD64", Value: "v1"}, 370 {Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"}, 371 {Key: "vcs.time", Value: "2022-10-14T19:54:57Z"}, 372 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`}, 373 }, 374 }, 375 cryptoSettings: nil, 376 arch: archDetails, 377 }, 378 expected: []pkg.Package{ 379 { 380 Name: "github.com/anchore/syft", 381 Language: pkg.Go, 382 Type: pkg.GoModulePkg, 383 Version: "v0.79.0", 384 PURL: "pkg:golang/github.com/anchore/syft@v0.79.0", 385 Locations: file.NewLocationSet( 386 file.NewLocationFromCoordinates( 387 file.Coordinates{ 388 RealPath: "/a-path", 389 FileSystemID: "layer-id", 390 }, 391 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 392 ), 393 MetadataType: pkg.GolangBinMetadataType, 394 Metadata: pkg.GolangBinMetadata{ 395 GoCompiledVersion: goCompiledVersion, 396 Architecture: archDetails, 397 BuildSettings: map[string]string{ 398 "GOARCH": archDetails, 399 "GOOS": "darwin", 400 "GOAMD64": "v1", 401 "vcs.revision": "41bc6bb410352845f22766e27dd48ba93aa825a4", 402 "vcs.time": "2022-10-14T19:54:57Z", 403 "-ldflags": `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`, 404 }, 405 MainModule: "github.com/anchore/syft", 406 }, 407 }, 408 }, 409 }, 410 { 411 name: "parse main mod and replace devel version with one from ldflags without any vcs. build settings", 412 mod: &extendedBuildInfo{ 413 BuildInfo: &debug.BuildInfo{ 414 GoVersion: goCompiledVersion, 415 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 416 Settings: []debug.BuildSetting{ 417 {Key: "GOARCH", Value: archDetails}, 418 {Key: "GOOS", Value: "darwin"}, 419 {Key: "GOAMD64", Value: "v1"}, 420 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`}, 421 }, 422 }, 423 cryptoSettings: nil, 424 arch: archDetails, 425 }, 426 expected: []pkg.Package{ 427 { 428 Name: "github.com/anchore/syft", 429 Language: pkg.Go, 430 Type: pkg.GoModulePkg, 431 Version: "v0.79.0", 432 PURL: "pkg:golang/github.com/anchore/syft@v0.79.0", 433 Locations: file.NewLocationSet( 434 file.NewLocationFromCoordinates( 435 file.Coordinates{ 436 RealPath: "/a-path", 437 FileSystemID: "layer-id", 438 }, 439 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 440 ), 441 MetadataType: pkg.GolangBinMetadataType, 442 Metadata: pkg.GolangBinMetadata{ 443 GoCompiledVersion: goCompiledVersion, 444 Architecture: archDetails, 445 BuildSettings: map[string]string{ 446 "GOARCH": archDetails, 447 "GOOS": "darwin", 448 "GOAMD64": "v1", 449 "-ldflags": `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`, 450 }, 451 MainModule: "github.com/anchore/syft", 452 }, 453 }, 454 }, 455 }, 456 { 457 name: "parse main mod and replace devel version with one from ldflags main.version without any vcs. build settings", 458 mod: &extendedBuildInfo{ 459 BuildInfo: &debug.BuildInfo{ 460 GoVersion: goCompiledVersion, 461 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 462 Settings: []debug.BuildSetting{ 463 {Key: "GOARCH", Value: archDetails}, 464 {Key: "GOOS", Value: "darwin"}, 465 {Key: "GOAMD64", Value: "v1"}, 466 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X main.version=0.79.0`}, 467 }, 468 }, 469 cryptoSettings: nil, 470 arch: archDetails, 471 }, 472 expected: []pkg.Package{ 473 { 474 Name: "github.com/anchore/syft", 475 Language: pkg.Go, 476 Type: pkg.GoModulePkg, 477 Version: "v0.79.0", 478 PURL: "pkg:golang/github.com/anchore/syft@v0.79.0", 479 Locations: file.NewLocationSet( 480 file.NewLocationFromCoordinates( 481 file.Coordinates{ 482 RealPath: "/a-path", 483 FileSystemID: "layer-id", 484 }, 485 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 486 ), 487 MetadataType: pkg.GolangBinMetadataType, 488 Metadata: pkg.GolangBinMetadata{ 489 GoCompiledVersion: goCompiledVersion, 490 Architecture: archDetails, 491 BuildSettings: map[string]string{ 492 "GOARCH": archDetails, 493 "GOOS": "darwin", 494 "GOAMD64": "v1", 495 "-ldflags": `build -ldflags="-w -s -extldflags '-static' -X main.version=0.79.0`, 496 }, 497 MainModule: "github.com/anchore/syft", 498 }, 499 }, 500 }, 501 }, 502 { 503 name: "parse main mod and replace devel version with one from ldflags main.Version without any vcs. build settings", 504 mod: &extendedBuildInfo{ 505 BuildInfo: &debug.BuildInfo{ 506 GoVersion: goCompiledVersion, 507 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 508 Settings: []debug.BuildSetting{ 509 {Key: "GOARCH", Value: archDetails}, 510 {Key: "GOOS", Value: "darwin"}, 511 {Key: "GOAMD64", Value: "v1"}, 512 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X main.Version=0.79.0`}, 513 }, 514 }, 515 cryptoSettings: nil, 516 arch: archDetails, 517 }, 518 expected: []pkg.Package{ 519 { 520 Name: "github.com/anchore/syft", 521 Language: pkg.Go, 522 Type: pkg.GoModulePkg, 523 Version: "v0.79.0", 524 PURL: "pkg:golang/github.com/anchore/syft@v0.79.0", 525 Locations: file.NewLocationSet( 526 file.NewLocationFromCoordinates( 527 file.Coordinates{ 528 RealPath: "/a-path", 529 FileSystemID: "layer-id", 530 }, 531 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 532 ), 533 MetadataType: pkg.GolangBinMetadataType, 534 Metadata: pkg.GolangBinMetadata{ 535 GoCompiledVersion: goCompiledVersion, 536 Architecture: archDetails, 537 BuildSettings: map[string]string{ 538 "GOARCH": archDetails, 539 "GOOS": "darwin", 540 "GOAMD64": "v1", 541 "-ldflags": `build -ldflags="-w -s -extldflags '-static' -X main.Version=0.79.0`, 542 }, 543 MainModule: "github.com/anchore/syft", 544 }, 545 }, 546 }, 547 }, 548 { 549 name: "parse main mod and replace devel version with a pseudo version", 550 mod: &extendedBuildInfo{ 551 BuildInfo: &debug.BuildInfo{ 552 GoVersion: goCompiledVersion, 553 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 554 Settings: []debug.BuildSetting{ 555 {Key: "GOARCH", Value: archDetails}, 556 {Key: "GOOS", Value: "darwin"}, 557 {Key: "GOAMD64", Value: "v1"}, 558 {Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"}, 559 {Key: "vcs.time", Value: "2022-10-14T19:54:57Z"}, 560 }, 561 }, 562 cryptoSettings: nil, 563 arch: archDetails, 564 }, 565 expected: []pkg.Package{ 566 { 567 Name: "github.com/anchore/syft", 568 Language: pkg.Go, 569 Type: pkg.GoModulePkg, 570 Version: "v0.0.0-20221014195457-41bc6bb41035", 571 PURL: "pkg:golang/github.com/anchore/syft@v0.0.0-20221014195457-41bc6bb41035", 572 Locations: file.NewLocationSet( 573 file.NewLocationFromCoordinates( 574 file.Coordinates{ 575 RealPath: "/a-path", 576 FileSystemID: "layer-id", 577 }, 578 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 579 ), 580 MetadataType: pkg.GolangBinMetadataType, 581 Metadata: pkg.GolangBinMetadata{ 582 GoCompiledVersion: goCompiledVersion, 583 Architecture: archDetails, 584 BuildSettings: map[string]string{ 585 "GOARCH": archDetails, 586 "GOOS": "darwin", 587 "GOAMD64": "v1", 588 "vcs.revision": "41bc6bb410352845f22766e27dd48ba93aa825a4", 589 "vcs.time": "2022-10-14T19:54:57Z", 590 }, 591 MainModule: "github.com/anchore/syft", 592 }, 593 }, 594 }, 595 }, 596 { 597 name: "parse a populated mod string and returns packages but no source info", 598 mod: &extendedBuildInfo{ 599 BuildInfo: &debug.BuildInfo{ 600 GoVersion: goCompiledVersion, 601 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 602 Settings: []debug.BuildSetting{ 603 {Key: "GOARCH", Value: archDetails}, 604 {Key: "GOOS", Value: "darwin"}, 605 {Key: "GOAMD64", Value: "v1"}, 606 }, 607 Deps: []*debug.Module{ 608 { 609 Path: "github.com/adrg/xdg", 610 Version: "v0.2.1", 611 Sum: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=", 612 }, 613 { 614 Path: "github.com/anchore/client-go", 615 Version: "v0.0.0-20210222170800-9c70f9b80bcf", 616 Sum: "h1:DYssiUV1pBmKqzKsm4mqXx8artqC0Q8HgZsVI3lMsAg=", 617 }, 618 }, 619 }, 620 cryptoSettings: nil, 621 arch: archDetails, 622 }, 623 expected: []pkg.Package{ 624 { 625 Name: "github.com/adrg/xdg", 626 Version: "v0.2.1", 627 PURL: "pkg:golang/github.com/adrg/xdg@v0.2.1", 628 Language: pkg.Go, 629 Type: pkg.GoModulePkg, 630 Locations: file.NewLocationSet( 631 file.NewLocationFromCoordinates( 632 file.Coordinates{ 633 RealPath: "/a-path", 634 FileSystemID: "layer-id", 635 }, 636 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 637 ), 638 MetadataType: pkg.GolangBinMetadataType, 639 Metadata: pkg.GolangBinMetadata{ 640 GoCompiledVersion: goCompiledVersion, 641 Architecture: archDetails, 642 H1Digest: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=", 643 MainModule: "github.com/anchore/syft", 644 }, 645 }, 646 { 647 Name: "github.com/anchore/client-go", 648 Version: "v0.0.0-20210222170800-9c70f9b80bcf", 649 PURL: "pkg:golang/github.com/anchore/client-go@v0.0.0-20210222170800-9c70f9b80bcf", 650 Language: pkg.Go, 651 Type: pkg.GoModulePkg, 652 Locations: file.NewLocationSet( 653 file.NewLocationFromCoordinates( 654 file.Coordinates{ 655 RealPath: "/a-path", 656 FileSystemID: "layer-id", 657 }, 658 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 659 ), 660 MetadataType: pkg.GolangBinMetadataType, 661 Metadata: pkg.GolangBinMetadata{ 662 GoCompiledVersion: goCompiledVersion, 663 Architecture: archDetails, 664 H1Digest: "h1:DYssiUV1pBmKqzKsm4mqXx8artqC0Q8HgZsVI3lMsAg=", 665 MainModule: "github.com/anchore/syft", 666 }, 667 }, 668 unmodifiedMain, 669 }, 670 }, 671 { 672 name: "parse a populated mod string and returns packages when a replace directive exists", 673 mod: &extendedBuildInfo{ 674 BuildInfo: &debug.BuildInfo{ 675 GoVersion: goCompiledVersion, 676 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 677 Settings: []debug.BuildSetting{ 678 {Key: "GOARCH", Value: archDetails}, 679 {Key: "GOOS", Value: "darwin"}, 680 {Key: "GOAMD64", Value: "v1"}, 681 }, 682 Deps: []*debug.Module{ 683 { 684 Path: "golang.org/x/sys", 685 Version: "v0.0.0-20211006194710-c8a6f5223071", 686 Sum: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=", 687 }, 688 { 689 Path: "golang.org/x/term", 690 Version: "v0.0.0-20210927222741-03fcf44c2211", 691 Sum: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=", 692 Replace: &debug.Module{ 693 Path: "golang.org/x/term", 694 Version: "v0.0.0-20210916214954-140adaaadfaf", 695 Sum: "h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=", 696 }, 697 }, 698 }, 699 }, 700 cryptoSettings: nil, 701 arch: archDetails, 702 }, 703 expected: []pkg.Package{ 704 { 705 Name: "golang.org/x/sys", 706 Version: "v0.0.0-20211006194710-c8a6f5223071", 707 PURL: "pkg:golang/golang.org/x/sys@v0.0.0-20211006194710-c8a6f5223071", 708 Language: pkg.Go, 709 Type: pkg.GoModulePkg, 710 Locations: file.NewLocationSet( 711 file.NewLocationFromCoordinates( 712 file.Coordinates{ 713 RealPath: "/a-path", 714 FileSystemID: "layer-id", 715 }, 716 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 717 ), 718 MetadataType: pkg.GolangBinMetadataType, 719 Metadata: pkg.GolangBinMetadata{ 720 GoCompiledVersion: goCompiledVersion, 721 Architecture: archDetails, 722 H1Digest: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=", 723 MainModule: "github.com/anchore/syft", 724 }}, 725 { 726 Name: "golang.org/x/term", 727 Version: "v0.0.0-20210916214954-140adaaadfaf", 728 PURL: "pkg:golang/golang.org/x/term@v0.0.0-20210916214954-140adaaadfaf", 729 Language: pkg.Go, 730 Type: pkg.GoModulePkg, 731 Locations: file.NewLocationSet( 732 file.NewLocationFromCoordinates( 733 file.Coordinates{ 734 RealPath: "/a-path", 735 FileSystemID: "layer-id", 736 }, 737 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 738 ), 739 MetadataType: pkg.GolangBinMetadataType, 740 Metadata: pkg.GolangBinMetadata{ 741 GoCompiledVersion: goCompiledVersion, 742 Architecture: archDetails, 743 H1Digest: "h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=", 744 MainModule: "github.com/anchore/syft", 745 }, 746 }, 747 unmodifiedMain, 748 }, 749 }, 750 } 751 752 for _, test := range tests { 753 t.Run(test.name, func(t *testing.T) { 754 for i := range test.expected { 755 p := &test.expected[i] 756 p.SetID() 757 } 758 location := file.NewLocationFromCoordinates( 759 file.Coordinates{ 760 RealPath: "/a-path", 761 FileSystemID: "layer-id", 762 }, 763 ) 764 765 c := goBinaryCataloger{} 766 pkgs := c.buildGoPkgInfo(fileresolver.Empty{}, location, test.mod, test.mod.arch) 767 assert.Equal(t, test.expected, pkgs) 768 }) 769 } 770 } 771 772 func Test_extractVersionFromLDFlags(t *testing.T) { 773 tests := []struct { 774 name string 775 ldflags string 776 wantMajorVersion string 777 wantFullVersion string 778 }{ 779 { 780 name: "empty ldflags", 781 ldflags: "", 782 }, 783 { 784 name: "syft ldflags", 785 ldflags: ` build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0 -X github.com/anchore/syft/internal/version.gitCommit=b2b332e8b2b66af0905e98b54ebd713a922be1a8 -X github.com/anchore/syft/internal/version.buildDate=2023-04-21T16:20:25Z -X github.com/anchore/syft/internal/version.gitDescription=v0.79.0 "`, 786 wantMajorVersion: "0", 787 wantFullVersion: "v0.79.0", 788 }, 789 { 790 name: "kubectl ldflags", 791 ldflags: ` build -asmflags=all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes 792 build -compiler=gc 793 build -gcflags="all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes " 794 build -ldflags="all=-X 'k8s.io/kubernetes/vendor/k8s.io/client-go/pkg/version.buildDate=2023-04-12T12:16:51Z' -X 'k8s.io/kubernetes/vendor/k8s.io/component-base/version.buildDate=2023-04-12T12:16:51Z' -X 'k8s.io/client-go/pkg/version.buildDate=2023-04-12T12:16:51Z' -X 'k8s.io/component-base/version.buildDate=2023-04-12T12:16:51Z' -X 'k8s.io/kubernetes/vendor/k8s.io/client-go/pkg/version.gitCommit=a1a87a0a2bcd605820920c6b0e618a8ab7d117d4' -X 'k8s.io/kubernetes/vendor/k8s.io/component-base/version.gitCommit=a1a87a0a2bcd605820920c6b0e618a8ab7d117d4' -X 'k8s.io/client-go/pkg/version.gitCommit=a1a87a0a2bcd605820920c6b0e618a8ab7d117d4' -X 'k8s.io/component-base/version.gitCommit=a1a87a0a2bcd605820920c6b0e618a8ab7d117d4' -X 'k8s.io/kubernetes/vendor/k8s.io/client-go/pkg/version.gitTreeState=clean' -X 'k8s.io/kubernetes/vendor/k8s.io/component-base/version.gitTreeState=clean' -X 'k8s.io/client-go/pkg/version.gitTreeState=clean' -X 'k8s.io/component-base/version.gitTreeState=clean' -X 'k8s.io/kubernetes/vendor/k8s.io/client-go/pkg/version.gitVersion=v1.25.9' -X 'k8s.io/kubernetes/vendor/k8s.io/component-base/version.gitVersion=v1.25.9' -X 'k8s.io/client-go/pkg/version.gitVersion=v1.25.9' -X 'k8s.io/component-base/version.gitVersion=v1.25.9' -X 'k8s.io/kubernetes/vendor/k8s.io/client-go/pkg/version.gitMajor=1' -X 'k8s.io/kubernetes/vendor/k8s.io/component-base/version.gitMajor=1' -X 'k8s.io/client-go/pkg/version.gitMajor=1' -X 'k8s.io/component-base/version.gitMajor=1' -X 'k8s.io/kubernetes/vendor/k8s.io/client-go/pkg/version.gitMinor=25' -X 'k8s.io/kubernetes/vendor/k8s.io/component-base/version.gitMinor=25' -X 'k8s.io/client-go/pkg/version.gitMinor=25' -X 'k8s.io/component-base/version.gitMinor=25' -s -w"`, 795 wantMajorVersion: "1", 796 wantFullVersion: "v1.25.9", 797 }, 798 { 799 name: "nerdctl ldflags", 800 ldflags: ` build -ldflags="-s -w -X github.com/containerd/nerdctl/pkg/version.Version=v1.3.1 -X github.com/containerd/nerdctl/pkg/version.Revision=b224b280ff3086516763c7335fc0e0997aca617a"`, 801 wantMajorVersion: "1", 802 wantFullVersion: "v1.3.1", 803 }, 804 { 805 name: "limactl ldflags", 806 ldflags: ` build -ldflags="-s -w -X github.com/lima-vm/lima/pkg/version.Version=v0.15.1"`, 807 wantMajorVersion: "0", 808 wantFullVersion: "v0.15.1", 809 }, 810 { 811 name: "terraform ldflags", 812 ldflags: ` build -ldflags="-w -s -X 'github.com/hashicorp/terraform/version.Version=1.4.6' -X 'github.com/hashicorp/terraform/version.Prerelease='"`, 813 wantMajorVersion: "1", 814 wantFullVersion: "v1.4.6", 815 }, 816 { 817 name: "kube-apiserver ldflags", 818 ldflags: ` build -asmflags=all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes 819 build -buildmode=exe 820 build -compiler=gc 821 build -gcflags="all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes " 822 build -ldflags="all=-X 'k8s.io/kubernetes/vendor/k8s.io/client-go/pkg/version.buildDate=2023-04-14T13:14:42Z' -X 'k8s.io/kubernetes/vendor/k8s.io/component-base/version.buildDate=2023-04-14T13:14:42Z' -X 'k8s.io/client-go/pkg/version.buildDate=2023-04-14T13:14:42Z' -X 'k8s.io/component-base/version.buildDate=2023-04-14T13:14:42Z' -X 'k8s.io/kubernetes/vendor/k8s.io/client-go/pkg/version.gitCommit=4c9411232e10168d7b050c49a1b59f6df9d7ea4b' -X 'k8s.io/kubernetes/vendor/k8s.io/component-base/version.gitCommit=4c9411232e10168d7b050c49a1b59f6df9d7ea4b' -X 'k8s.io/client-go/pkg/version.gitCommit=4c9411232e10168d7b050c49a1b59f6df9d7ea4b' -X 'k8s.io/component-base/version.gitCommit=4c9411232e10168d7b050c49a1b59f6df9d7ea4b' -X 'k8s.io/kubernetes/vendor/k8s.io/client-go/pkg/version.gitTreeState=clean' -X 'k8s.io/kubernetes/vendor/k8s.io/component-base/version.gitTreeState=clean' -X 'k8s.io/client-go/pkg/version.gitTreeState=clean' -X 'k8s.io/component-base/version.gitTreeState=clean' -X 'k8s.io/kubernetes/vendor/k8s.io/client-go/pkg/version.gitVersion=v1.27.1' -X 'k8s.io/kubernetes/vendor/k8s.io/component-base/version.gitVersion=v1.27.1' -X 'k8s.io/client-go/pkg/version.gitVersion=v1.27.1' -X 'k8s.io/component-base/version.gitVersion=v1.27.1' -X 'k8s.io/kubernetes/vendor/k8s.io/client-go/pkg/version.gitMajor=1' -X 'k8s.io/kubernetes/vendor/k8s.io/component-base/version.gitMajor=1' -X 'k8s.io/client-go/pkg/version.gitMajor=1' -X 'k8s.io/component-base/version.gitMajor=1' -X 'k8s.io/kubernetes/vendor/k8s.io/client-go/pkg/version.gitMinor=27' -X 'k8s.io/kubernetes/vendor/k8s.io/component-base/version.gitMinor=27' -X 'k8s.io/client-go/pkg/version.gitMinor=27' -X 'k8s.io/component-base/version.gitMinor=27' -s -w"`, 823 wantMajorVersion: "1", 824 wantFullVersion: "v1.27.1", 825 }, 826 { 827 name: "prometheus ldflags", 828 ldflags: ` build -ldflags="-X github.com/prometheus/common/version.Version=2.44.0 -X github.com/prometheus/common/version.Revision=1ac5131f698ebc60f13fe2727f89b115a41f6558 -X github.com/prometheus/common/version.Branch=HEAD -X github.com/prometheus/common/version.BuildUser=root@739e8181c5db -X github.com/prometheus/common/version.BuildDate=20230514-06:18:11 -extldflags '-static'" 829 build -tags=netgo,builtinassets,stringlabels`, 830 wantMajorVersion: "2", 831 wantFullVersion: "v2.44.0", 832 }, 833 { 834 name: "influxdb ldflags", 835 ldflags: ` build -ldflags="-s -w -X main.version=v2.7.1 -X main.commit=407fa622e9 -X main.date=2023-04-28T13:24:27Z -linkmode=external -extld=/musl/x86_64/bin/musl-gcc -extldflags '-fno-PIC -static-pie -Wl,-z,stack-size=8388608'" 836 build -tags=assets,sqlite_foreign_keys,sqlite_json,static_build,noasm`, 837 wantMajorVersion: "2", 838 wantFullVersion: "v2.7.1", 839 }, 840 { 841 name: "gitea ldflags", 842 ldflags: ` build -ldflags=" -X \"main.MakeVersion=GNU Make 4.1\" -X \"main.Version=1.19.3\" -X \"main.Tags=bindata sqlite sqlite_unlock_notify\" "`, 843 wantMajorVersion: "1", 844 wantFullVersion: "v1.19.3", 845 }, 846 { 847 name: "docker sbom cli ldflags", 848 ldflags: ` build -ldflags="-w -s -extldflags '-static' -X github.com/docker/sbom-cli-plugin/internal/version.version=0.6.1-SNAPSHOT-02cf1c8 -X github.com/docker/sbom-cli-plugin/internal/version.gitCommit=02cf1c888ad6662109ac6e3be618392514a56316 -X github.com/docker/sbom-cli-plugin/internal/version.gitDescription=v0.6.1-dirty "`, 849 wantMajorVersion: "0", 850 wantFullVersion: "v0.6.1-SNAPSHOT-02cf1c8", 851 }, 852 { 853 name: "docker scout ldflags", 854 ldflags: ` build -ldflags="-w -s -extldflags '-static' -X github.com/docker/scout-cli-plugin/internal.version=0.10.0 "`, 855 wantMajorVersion: "0", 856 wantFullVersion: "v0.10.0", 857 }, 858 { 859 name: "influx telegraf ldflags", 860 ldflags: ` build -ldflags="-w -s -X github.com/influxdata/telegraf/internal.Commit=a3a884a1 -X github.com/influxdata/telegraf/internal.Branch=HEAD -X github.com/influxdata/telegraf/internal.Version=1.26.2"`, 861 wantMajorVersion: "1", 862 wantFullVersion: "v1.26.2", 863 }, 864 { 865 name: "argocd ldflags", 866 ldflags: ` build -ldflags="-X github.com/argoproj/argo-cd/v2/common.version=2.7.2 -X github.com/argoproj/argo-cd/v2/common.buildDate=2023-05-12T14:06:49Z -X github.com/argoproj/argo-cd/v2/common.gitCommit=cbee7e6011407ed2d1066c482db74e97e0cc6bdb -X github.com/argoproj/argo-cd/v2/common.gitTreeState=clean -X github.com/argoproj/argo-cd/v2/common.kubectlVersion=v0.24.2 -extldflags=\"-static\""`, 867 wantMajorVersion: "2", 868 wantFullVersion: "v2.7.2", 869 }, 870 { 871 name: "kustomize ldflags", 872 ldflags: ` build -ldflags="-s -X sigs.k8s.io/kustomize/api/provenance.version=kustomize/v4.5.7 -X sigs.k8s.io/kustomize/api/provenance.gitCommit=56d82a8378dfc8dc3b3b1085e5a6e67b82966bd7 -X sigs.k8s.io/kustomize/api/provenance.buildDate=2022-08-02T16:35:54Z "`, 873 wantMajorVersion: "4", 874 wantFullVersion: "v4.5.7", 875 }, 876 ////////////////////////////////////////////////////////////////// 877 // negative cases 878 { 879 name: "hugo ldflags", 880 ldflags: ` build -ldflags="-s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio"`, 881 }, 882 { 883 name: "ghostunnel ldflags", 884 ldflags: ` build -ldflags="-X main.version=77d9aaa"`, 885 }, 886 { 887 name: "opa ldflags", 888 ldflags: `build -ldflags=" -X github.com/open-policy-agent/opa/version.Hostname=9549178459bc"`, 889 }, 890 /////////////////////////////////////////////////////////////////// 891 // trickier cases 892 { 893 name: "macvlan plugin for cri-o ldflags", 894 ldflags: ` build -ldflags="-extldflags -static -X github.com/containernetworking/plugins/pkg/utils/buildversion.BuildVersion=v1.2.0"`, 895 wantMajorVersion: "1", 896 wantFullVersion: "v1.2.0", 897 }, 898 { 899 name: "coder ldflags", 900 ldflags: ` build -ldflags="-s -w -X 'github.com/coder/coder/buildinfo.tag=0.23.4'"`, 901 wantMajorVersion: "0", 902 wantFullVersion: "v0.23.4", 903 }, 904 /////////////////////////////////////////////////////////////////// 905 // don't know how to handle these... yet 906 //{ 907 // // package name: pkgName: "github.com/krakendio/krakend-ce/v2", 908 // name: "krakenD ldflags", 909 // ldflags: ` build -ldflags="-X github.com/luraproject/lura/v2/core.KrakendVersion=2.3.2 -X github.com/luraproject/lura/v2/core.GoVersion=1.20.4 -X github.com/luraproject/lura/v2/core.GlibcVersion=GLIBC-2.31_(debian-11) "`, 910 // wantMajorVersion: "2.3.2", 911 // wantFullVersion: "v2.3.2", 912 //}, 913 //{ 914 // // package name: pkgName: "github.com/krakendio/krakend-ce/v2", 915 // name: "krakenD ldflags -- answer embedded in the middle", 916 // ldflags: ` build -ldflags=" -X github.com/luraproject/lura/v2/core.GoVersion=1.20.4 -X github.com/luraproject/lura/v2/core.KrakendVersion=2.3.2 -X github.com/luraproject/lura/v2/core.GlibcVersion=GLIBC-2.31_(debian-11) "`, 917 // wantMajorVersion: "2.3.2", 918 // wantFullVersion: "v2.3.2", 919 //}, 920 } 921 for _, tt := range tests { 922 t.Run(tt.name, func(t *testing.T) { 923 gotMajorVersion, gotFullVersion := extractVersionFromLDFlags(tt.ldflags) 924 assert.Equal(t, tt.wantMajorVersion, gotMajorVersion, "unexpected major version") 925 assert.Equal(t, tt.wantFullVersion, gotFullVersion, "unexpected full version") 926 }) 927 } 928 }