github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/pkg/cataloger/golang/parse_go_binary_test.go (about) 1 package golang 2 3 import ( 4 "bufio" 5 "bytes" 6 "errors" 7 "io" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "runtime/debug" 12 "strconv" 13 "strings" 14 "syscall" 15 "testing" 16 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 20 "github.com/anchore/syft/syft/file" 21 "github.com/anchore/syft/syft/internal/fileresolver" 22 "github.com/anchore/syft/syft/internal/unionreader" 23 "github.com/anchore/syft/syft/pkg" 24 "github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest" 25 ) 26 27 // make will run the default make target for the given test fixture path 28 func runMakeTarget(t *testing.T, fixtureName string) { 29 cwd, err := os.Getwd() 30 require.NoError(t, err) 31 fixtureDir := filepath.Join(cwd, "test-fixtures/", fixtureName) 32 33 t.Logf("Generating Fixture in %q", fixtureDir) 34 35 cmd := exec.Command("make") 36 cmd.Dir = fixtureDir 37 38 stderr, err := cmd.StderrPipe() 39 require.NoError(t, err) 40 41 stdout, err := cmd.StdoutPipe() 42 require.NoError(t, err) 43 44 err = cmd.Start() 45 require.NoError(t, err) 46 47 show := func(label string, reader io.ReadCloser) { 48 scanner := bufio.NewScanner(reader) 49 scanner.Split(bufio.ScanLines) 50 for scanner.Scan() { 51 t.Logf("%s: %s", label, scanner.Text()) 52 } 53 } 54 go show("out", stdout) 55 go show("err", stderr) 56 57 if err := cmd.Wait(); err != nil { 58 if exiterr, ok := err.(*exec.ExitError); ok { 59 // The program has exited with an exit code != 0 60 61 // This works on both Unix and Windows. Although package 62 // syscall is generally platform dependent, WaitStatus is 63 // defined for both Unix and Windows and in both cases has 64 // an ExitStatus() method with the same signature. 65 if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { 66 if status.ExitStatus() != 0 { 67 t.Fatalf("failed to generate fixture: rc=%d", status.ExitStatus()) 68 } 69 } 70 } else { 71 t.Fatalf("unable to get generate fixture result: %+v", err) 72 } 73 } 74 } 75 76 func Test_getGOARCHFromBin(t *testing.T) { 77 runMakeTarget(t, "archs") 78 79 tests := []struct { 80 name string 81 filepath string 82 expected string 83 }{ 84 { 85 name: "pe", 86 filepath: "test-fixtures/archs/binaries/hello-win-amd64", 87 // see: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types 88 expected: strconv.Itoa(0x8664), 89 }, 90 { 91 name: "elf-ppc64", 92 filepath: "test-fixtures/archs/binaries/hello-linux-ppc64le", 93 expected: "ppc64", 94 }, 95 { 96 name: "mach-o-arm64", 97 filepath: "test-fixtures/archs/binaries/hello-mach-o-arm64", 98 expected: "arm64", 99 }, 100 { 101 name: "linux-arm", 102 filepath: "test-fixtures/archs/binaries/hello-linux-arm", 103 expected: "arm", 104 }, 105 { 106 name: "xcoff-32bit", 107 filepath: "internal/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec", 108 expected: strconv.Itoa(0x1DF), 109 }, 110 { 111 name: "xcoff-64bit", 112 filepath: "internal/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec", 113 expected: strconv.Itoa(0x1F7), 114 }, 115 } 116 117 for _, tt := range tests { 118 f, err := os.Open(tt.filepath) 119 require.NoError(t, err) 120 arch, err := getGOARCHFromBin(f) 121 require.NoError(t, err, "test name: %s", tt.name) 122 assert.Equal(t, tt.expected, arch) 123 } 124 125 } 126 127 func TestBuildGoPkgInfo(t *testing.T) { 128 const ( 129 goCompiledVersion = "1.18" 130 archDetails = "amd64" 131 ) 132 133 defaultBuildSettings := []pkg.KeyValue{ 134 { 135 Key: "GOARCH", 136 Value: "amd64", 137 }, 138 { 139 Key: "GOOS", 140 Value: "darwin", 141 }, 142 { 143 Key: "GOAMD64", 144 Value: "v1", 145 }, 146 } 147 148 unmodifiedMain := pkg.Package{ 149 Name: "github.com/anchore/syft", 150 Language: pkg.Go, 151 Type: pkg.GoModulePkg, 152 Version: "(devel)", 153 PURL: "pkg:golang/github.com/anchore/syft@(devel)", 154 Locations: file.NewLocationSet( 155 file.NewLocationFromCoordinates( 156 file.Coordinates{ 157 RealPath: "/a-path", 158 FileSystemID: "layer-id", 159 }, 160 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 161 ), 162 Metadata: pkg.GolangBinaryBuildinfoEntry{ 163 GoCompiledVersion: goCompiledVersion, 164 Architecture: archDetails, 165 BuildSettings: defaultBuildSettings, 166 MainModule: "github.com/anchore/syft", 167 }, 168 } 169 170 tests := []struct { 171 name string 172 mod *extendedBuildInfo 173 expected []pkg.Package 174 binaryContent string 175 }{ 176 { 177 name: "package without name", 178 mod: &extendedBuildInfo{ 179 BuildInfo: &debug.BuildInfo{ 180 Deps: []*debug.Module{ 181 { 182 Path: "github.com/adrg/xdg", 183 }, 184 { 185 Path: "", 186 Version: "v0.2.1", 187 }, 188 }, 189 }, 190 cryptoSettings: nil, 191 arch: "", 192 }, 193 expected: []pkg.Package{ 194 { 195 Name: "github.com/adrg/xdg", 196 PURL: "pkg:golang/github.com/adrg/xdg", 197 Language: pkg.Go, 198 Type: pkg.GoModulePkg, 199 Locations: file.NewLocationSet( 200 file.NewLocationFromCoordinates( 201 file.Coordinates{ 202 RealPath: "/a-path", 203 FileSystemID: "layer-id", 204 }, 205 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 206 ), 207 Metadata: pkg.GolangBinaryBuildinfoEntry{}, 208 }, 209 }, 210 }, 211 { 212 name: "buildGoPkgInfo parses a blank mod and returns no packages", 213 mod: &extendedBuildInfo{&debug.BuildInfo{}, nil, ""}, 214 expected: []pkg.Package(nil), 215 }, 216 { 217 name: "parse a mod without main module", 218 mod: &extendedBuildInfo{ 219 BuildInfo: &debug.BuildInfo{ 220 GoVersion: goCompiledVersion, 221 Settings: []debug.BuildSetting{ 222 {Key: "GOARCH", Value: archDetails}, 223 {Key: "GOOS", Value: "darwin"}, 224 {Key: "GOAMD64", Value: "v1"}, 225 }, 226 Deps: []*debug.Module{ 227 { 228 Path: "github.com/adrg/xdg", 229 Version: "v0.2.1", 230 Sum: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=", 231 }, 232 }, 233 }, 234 cryptoSettings: nil, 235 arch: archDetails, 236 }, 237 expected: []pkg.Package{ 238 { 239 Name: "github.com/adrg/xdg", 240 Version: "v0.2.1", 241 PURL: "pkg:golang/github.com/adrg/xdg@v0.2.1", 242 Language: pkg.Go, 243 Type: pkg.GoModulePkg, 244 Locations: file.NewLocationSet( 245 file.NewLocationFromCoordinates( 246 file.Coordinates{ 247 RealPath: "/a-path", 248 FileSystemID: "layer-id", 249 }, 250 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 251 ), 252 Metadata: pkg.GolangBinaryBuildinfoEntry{ 253 GoCompiledVersion: goCompiledVersion, 254 Architecture: archDetails, 255 H1Digest: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=", 256 }, 257 }, 258 }, 259 }, 260 { 261 name: "parse a mod with path but no main module", 262 mod: &extendedBuildInfo{ 263 BuildInfo: &debug.BuildInfo{ 264 GoVersion: goCompiledVersion, 265 Settings: []debug.BuildSetting{ 266 {Key: "GOARCH", Value: archDetails}, 267 {Key: "GOOS", Value: "darwin"}, 268 {Key: "GOAMD64", Value: "v1"}, 269 }, 270 Path: "github.com/a/b/c", 271 }, 272 cryptoSettings: []string{"boringcrypto + fips"}, 273 arch: archDetails, 274 }, 275 expected: []pkg.Package{ 276 { 277 Name: "github.com/a/b/c", 278 Version: "(devel)", 279 PURL: "pkg:golang/github.com/a/b@(devel)#c", 280 Language: pkg.Go, 281 Type: pkg.GoModulePkg, 282 Locations: file.NewLocationSet( 283 file.NewLocationFromCoordinates( 284 file.Coordinates{ 285 RealPath: "/a-path", 286 FileSystemID: "layer-id", 287 }, 288 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 289 ), 290 Metadata: pkg.GolangBinaryBuildinfoEntry{ 291 GoCompiledVersion: goCompiledVersion, 292 Architecture: archDetails, 293 H1Digest: "", 294 BuildSettings: []pkg.KeyValue{ 295 { 296 Key: "GOARCH", 297 Value: archDetails, 298 }, 299 { 300 Key: "GOOS", 301 Value: "darwin", 302 }, 303 { 304 Key: "GOAMD64", 305 Value: "v1", 306 }, 307 }, 308 MainModule: "github.com/a/b/c", 309 GoCryptoSettings: []string{"boringcrypto + fips"}, 310 }, 311 }, 312 }, 313 }, 314 { 315 name: "parse a mod without packages", 316 mod: &extendedBuildInfo{ 317 BuildInfo: &debug.BuildInfo{ 318 GoVersion: goCompiledVersion, 319 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 320 Settings: []debug.BuildSetting{ 321 {Key: "GOARCH", Value: archDetails}, 322 {Key: "GOOS", Value: "darwin"}, 323 {Key: "GOAMD64", Value: "v1"}, 324 }, 325 }, 326 cryptoSettings: nil, 327 arch: archDetails, 328 }, 329 expected: []pkg.Package{unmodifiedMain}, 330 }, 331 { 332 name: "parse main mod and replace devel pseudo version and ldflags exists (but contains no version)", 333 mod: &extendedBuildInfo{ 334 BuildInfo: &debug.BuildInfo{ 335 GoVersion: goCompiledVersion, 336 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 337 Settings: []debug.BuildSetting{ 338 {Key: "GOARCH", Value: archDetails}, 339 {Key: "GOOS", Value: "darwin"}, 340 {Key: "GOAMD64", Value: "v1"}, 341 {Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"}, 342 {Key: "vcs.time", Value: "2022-10-14T19:54:57Z"}, 343 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X blah=foobar`}, 344 }, 345 }, 346 cryptoSettings: nil, 347 arch: archDetails, 348 }, 349 expected: []pkg.Package{ 350 { 351 Name: "github.com/anchore/syft", 352 Language: pkg.Go, 353 Type: pkg.GoModulePkg, 354 Version: "v0.0.0-20221014195457-41bc6bb41035", 355 PURL: "pkg:golang/github.com/anchore/syft@v0.0.0-20221014195457-41bc6bb41035", 356 Locations: file.NewLocationSet( 357 file.NewLocationFromCoordinates( 358 file.Coordinates{ 359 RealPath: "/a-path", 360 FileSystemID: "layer-id", 361 }, 362 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 363 ), 364 Metadata: pkg.GolangBinaryBuildinfoEntry{ 365 GoCompiledVersion: goCompiledVersion, 366 Architecture: archDetails, 367 BuildSettings: []pkg.KeyValue{ 368 { 369 Key: "GOARCH", 370 Value: archDetails, 371 }, 372 { 373 Key: "GOOS", 374 Value: "darwin", 375 }, 376 { 377 Key: "GOAMD64", 378 Value: "v1", 379 }, 380 { 381 Key: "vcs.revision", 382 Value: "41bc6bb410352845f22766e27dd48ba93aa825a4", 383 }, 384 { 385 Key: "vcs.time", 386 Value: "2022-10-14T19:54:57Z", 387 }, 388 { 389 Key: "-ldflags", 390 Value: `build -ldflags="-w -s -extldflags '-static' -X blah=foobar`, 391 }, 392 }, 393 MainModule: "github.com/anchore/syft", 394 }, 395 }, 396 }, 397 }, 398 { 399 name: "parse main mod and replace devel version with one from ldflags with vcs. build settings", 400 mod: &extendedBuildInfo{ 401 BuildInfo: &debug.BuildInfo{ 402 GoVersion: goCompiledVersion, 403 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 404 Settings: []debug.BuildSetting{ 405 {Key: "GOARCH", Value: archDetails}, 406 {Key: "GOOS", Value: "darwin"}, 407 {Key: "GOAMD64", Value: "v1"}, 408 {Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"}, 409 {Key: "vcs.time", Value: "2022-10-14T19:54:57Z"}, 410 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`}, 411 }, 412 }, 413 cryptoSettings: nil, 414 arch: archDetails, 415 }, 416 expected: []pkg.Package{ 417 { 418 Name: "github.com/anchore/syft", 419 Language: pkg.Go, 420 Type: pkg.GoModulePkg, 421 Version: "v0.79.0", 422 PURL: "pkg:golang/github.com/anchore/syft@v0.79.0", 423 Locations: file.NewLocationSet( 424 file.NewLocationFromCoordinates( 425 file.Coordinates{ 426 RealPath: "/a-path", 427 FileSystemID: "layer-id", 428 }, 429 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 430 ), 431 Metadata: pkg.GolangBinaryBuildinfoEntry{ 432 GoCompiledVersion: goCompiledVersion, 433 Architecture: archDetails, 434 BuildSettings: []pkg.KeyValue{ 435 { 436 Key: "GOARCH", 437 Value: archDetails, 438 }, 439 { 440 Key: "GOOS", 441 Value: "darwin", 442 }, 443 { 444 Key: "GOAMD64", 445 Value: "v1", 446 }, 447 { 448 Key: "vcs.revision", 449 Value: "41bc6bb410352845f22766e27dd48ba93aa825a4", 450 }, 451 { 452 Key: "vcs.time", 453 Value: "2022-10-14T19:54:57Z", 454 }, 455 { 456 Key: "-ldflags", 457 Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`, 458 }, 459 }, 460 MainModule: "github.com/anchore/syft", 461 }, 462 }, 463 }, 464 }, 465 { 466 name: "parse main mod and replace devel version with one from ldflags without any vcs. build settings", 467 mod: &extendedBuildInfo{ 468 BuildInfo: &debug.BuildInfo{ 469 GoVersion: goCompiledVersion, 470 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 471 Settings: []debug.BuildSetting{ 472 {Key: "GOARCH", Value: archDetails}, 473 {Key: "GOOS", Value: "darwin"}, 474 {Key: "GOAMD64", Value: "v1"}, 475 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`}, 476 }, 477 }, 478 cryptoSettings: nil, 479 arch: archDetails, 480 }, 481 expected: []pkg.Package{ 482 { 483 Name: "github.com/anchore/syft", 484 Language: pkg.Go, 485 Type: pkg.GoModulePkg, 486 Version: "v0.79.0", 487 PURL: "pkg:golang/github.com/anchore/syft@v0.79.0", 488 Locations: file.NewLocationSet( 489 file.NewLocationFromCoordinates( 490 file.Coordinates{ 491 RealPath: "/a-path", 492 FileSystemID: "layer-id", 493 }, 494 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 495 ), 496 Metadata: pkg.GolangBinaryBuildinfoEntry{ 497 GoCompiledVersion: goCompiledVersion, 498 Architecture: archDetails, 499 BuildSettings: []pkg.KeyValue{ 500 { 501 Key: "GOARCH", 502 Value: archDetails, 503 }, 504 { 505 Key: "GOOS", 506 Value: "darwin", 507 }, 508 { 509 Key: "GOAMD64", 510 Value: "v1", 511 }, 512 { 513 Key: "-ldflags", 514 Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`, 515 }, 516 }, 517 MainModule: "github.com/anchore/syft", 518 }, 519 }, 520 }, 521 }, 522 { 523 name: "parse main mod and replace devel version with one from ldflags main.version without any vcs. build settings", 524 mod: &extendedBuildInfo{ 525 BuildInfo: &debug.BuildInfo{ 526 GoVersion: goCompiledVersion, 527 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 528 Settings: []debug.BuildSetting{ 529 {Key: "GOARCH", Value: archDetails}, 530 {Key: "GOOS", Value: "darwin"}, 531 {Key: "GOAMD64", Value: "v1"}, 532 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X main.version=0.79.0`}, 533 }, 534 }, 535 cryptoSettings: nil, 536 arch: archDetails, 537 }, 538 expected: []pkg.Package{ 539 { 540 Name: "github.com/anchore/syft", 541 Language: pkg.Go, 542 Type: pkg.GoModulePkg, 543 Version: "v0.79.0", 544 PURL: "pkg:golang/github.com/anchore/syft@v0.79.0", 545 Locations: file.NewLocationSet( 546 file.NewLocationFromCoordinates( 547 file.Coordinates{ 548 RealPath: "/a-path", 549 FileSystemID: "layer-id", 550 }, 551 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 552 ), 553 Metadata: pkg.GolangBinaryBuildinfoEntry{ 554 GoCompiledVersion: goCompiledVersion, 555 Architecture: archDetails, 556 BuildSettings: []pkg.KeyValue{ 557 { 558 Key: "GOARCH", 559 Value: archDetails, 560 }, 561 { 562 Key: "GOOS", 563 Value: "darwin", 564 }, 565 { 566 Key: "GOAMD64", 567 Value: "v1", 568 }, 569 { 570 Key: "-ldflags", 571 Value: `build -ldflags="-w -s -extldflags '-static' -X main.version=0.79.0`, 572 }, 573 }, 574 MainModule: "github.com/anchore/syft", 575 }, 576 }, 577 }, 578 }, 579 { 580 name: "parse main mod and replace devel version with one from ldflags main.Version without any vcs. build settings", 581 mod: &extendedBuildInfo{ 582 BuildInfo: &debug.BuildInfo{ 583 GoVersion: goCompiledVersion, 584 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 585 Settings: []debug.BuildSetting{ 586 {Key: "GOARCH", Value: archDetails}, 587 {Key: "GOOS", Value: "darwin"}, 588 {Key: "GOAMD64", Value: "v1"}, 589 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X main.Version=0.79.0`}, 590 }, 591 }, 592 cryptoSettings: nil, 593 arch: archDetails, 594 }, 595 expected: []pkg.Package{ 596 { 597 Name: "github.com/anchore/syft", 598 Language: pkg.Go, 599 Type: pkg.GoModulePkg, 600 Version: "v0.79.0", 601 PURL: "pkg:golang/github.com/anchore/syft@v0.79.0", 602 Locations: file.NewLocationSet( 603 file.NewLocationFromCoordinates( 604 file.Coordinates{ 605 RealPath: "/a-path", 606 FileSystemID: "layer-id", 607 }, 608 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 609 ), 610 Metadata: pkg.GolangBinaryBuildinfoEntry{ 611 GoCompiledVersion: goCompiledVersion, 612 Architecture: archDetails, 613 BuildSettings: []pkg.KeyValue{ 614 { 615 Key: "GOARCH", 616 Value: archDetails, 617 }, 618 { 619 Key: "GOOS", 620 Value: "darwin", 621 }, 622 { 623 Key: "GOAMD64", 624 Value: "v1", 625 }, 626 { 627 Key: "-ldflags", 628 Value: `build -ldflags="-w -s -extldflags '-static' -X main.Version=0.79.0`, 629 }, 630 }, 631 MainModule: "github.com/anchore/syft", 632 }, 633 }, 634 }, 635 }, 636 { 637 name: "parse main mod and replace devel version with a pseudo version", 638 mod: &extendedBuildInfo{ 639 BuildInfo: &debug.BuildInfo{ 640 GoVersion: goCompiledVersion, 641 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 642 Settings: []debug.BuildSetting{ 643 {Key: "GOARCH", Value: archDetails}, 644 {Key: "GOOS", Value: "darwin"}, 645 {Key: "GOAMD64", Value: "v1"}, 646 {Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"}, 647 {Key: "vcs.time", Value: "2022-10-14T19:54:57Z"}, 648 }, 649 }, 650 cryptoSettings: nil, 651 arch: archDetails, 652 }, 653 expected: []pkg.Package{ 654 { 655 Name: "github.com/anchore/syft", 656 Language: pkg.Go, 657 Type: pkg.GoModulePkg, 658 Version: "v0.0.0-20221014195457-41bc6bb41035", 659 PURL: "pkg:golang/github.com/anchore/syft@v0.0.0-20221014195457-41bc6bb41035", 660 Locations: file.NewLocationSet( 661 file.NewLocationFromCoordinates( 662 file.Coordinates{ 663 RealPath: "/a-path", 664 FileSystemID: "layer-id", 665 }, 666 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 667 ), 668 Metadata: pkg.GolangBinaryBuildinfoEntry{ 669 GoCompiledVersion: goCompiledVersion, 670 Architecture: archDetails, 671 BuildSettings: []pkg.KeyValue{ 672 { 673 Key: "GOARCH", 674 Value: archDetails, 675 }, 676 { 677 Key: "GOOS", 678 Value: "darwin", 679 }, 680 { 681 Key: "GOAMD64", 682 Value: "v1", 683 }, 684 { 685 Key: "vcs.revision", 686 Value: "41bc6bb410352845f22766e27dd48ba93aa825a4", 687 }, 688 { 689 Key: "vcs.time", 690 Value: "2022-10-14T19:54:57Z", 691 }, 692 }, 693 MainModule: "github.com/anchore/syft", 694 }, 695 }, 696 }, 697 }, 698 { 699 name: "parse a populated mod string and returns packages but no source info", 700 mod: &extendedBuildInfo{ 701 BuildInfo: &debug.BuildInfo{ 702 GoVersion: goCompiledVersion, 703 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 704 Settings: []debug.BuildSetting{ 705 {Key: "GOARCH", Value: archDetails}, 706 {Key: "GOOS", Value: "darwin"}, 707 {Key: "GOAMD64", Value: "v1"}, 708 }, 709 Deps: []*debug.Module{ 710 { 711 Path: "github.com/adrg/xdg", 712 Version: "v0.2.1", 713 Sum: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=", 714 }, 715 { 716 Path: "github.com/anchore/client-go", 717 Version: "v0.0.0-20210222170800-9c70f9b80bcf", 718 Sum: "h1:DYssiUV1pBmKqzKsm4mqXx8artqC0Q8HgZsVI3lMsAg=", 719 }, 720 }, 721 }, 722 cryptoSettings: nil, 723 arch: archDetails, 724 }, 725 expected: []pkg.Package{ 726 { 727 Name: "github.com/adrg/xdg", 728 Version: "v0.2.1", 729 PURL: "pkg:golang/github.com/adrg/xdg@v0.2.1", 730 Language: pkg.Go, 731 Type: pkg.GoModulePkg, 732 Locations: file.NewLocationSet( 733 file.NewLocationFromCoordinates( 734 file.Coordinates{ 735 RealPath: "/a-path", 736 FileSystemID: "layer-id", 737 }, 738 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 739 ), 740 Metadata: pkg.GolangBinaryBuildinfoEntry{ 741 GoCompiledVersion: goCompiledVersion, 742 Architecture: archDetails, 743 H1Digest: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=", 744 MainModule: "github.com/anchore/syft", 745 }, 746 }, 747 { 748 Name: "github.com/anchore/client-go", 749 Version: "v0.0.0-20210222170800-9c70f9b80bcf", 750 PURL: "pkg:golang/github.com/anchore/client-go@v0.0.0-20210222170800-9c70f9b80bcf", 751 Language: pkg.Go, 752 Type: pkg.GoModulePkg, 753 Locations: file.NewLocationSet( 754 file.NewLocationFromCoordinates( 755 file.Coordinates{ 756 RealPath: "/a-path", 757 FileSystemID: "layer-id", 758 }, 759 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 760 ), 761 Metadata: pkg.GolangBinaryBuildinfoEntry{ 762 GoCompiledVersion: goCompiledVersion, 763 Architecture: archDetails, 764 H1Digest: "h1:DYssiUV1pBmKqzKsm4mqXx8artqC0Q8HgZsVI3lMsAg=", 765 MainModule: "github.com/anchore/syft", 766 }, 767 }, 768 unmodifiedMain, 769 }, 770 }, 771 { 772 name: "parse a populated mod string and returns packages when a replace directive exists", 773 mod: &extendedBuildInfo{ 774 BuildInfo: &debug.BuildInfo{ 775 GoVersion: goCompiledVersion, 776 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 777 Settings: []debug.BuildSetting{ 778 {Key: "GOARCH", Value: archDetails}, 779 {Key: "GOOS", Value: "darwin"}, 780 {Key: "GOAMD64", Value: "v1"}, 781 }, 782 Deps: []*debug.Module{ 783 { 784 Path: "golang.org/x/sys", 785 Version: "v0.0.0-20211006194710-c8a6f5223071", 786 Sum: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=", 787 }, 788 { 789 Path: "golang.org/x/term", 790 Version: "v0.0.0-20210927222741-03fcf44c2211", 791 Sum: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=", 792 Replace: &debug.Module{ 793 Path: "golang.org/x/term", 794 Version: "v0.0.0-20210916214954-140adaaadfaf", 795 Sum: "h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=", 796 }, 797 }, 798 }, 799 }, 800 cryptoSettings: nil, 801 arch: archDetails, 802 }, 803 expected: []pkg.Package{ 804 { 805 Name: "golang.org/x/sys", 806 Version: "v0.0.0-20211006194710-c8a6f5223071", 807 PURL: "pkg:golang/golang.org/x/sys@v0.0.0-20211006194710-c8a6f5223071", 808 Language: pkg.Go, 809 Type: pkg.GoModulePkg, 810 Locations: file.NewLocationSet( 811 file.NewLocationFromCoordinates( 812 file.Coordinates{ 813 RealPath: "/a-path", 814 FileSystemID: "layer-id", 815 }, 816 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 817 ), 818 Metadata: pkg.GolangBinaryBuildinfoEntry{ 819 GoCompiledVersion: goCompiledVersion, 820 Architecture: archDetails, 821 H1Digest: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=", 822 MainModule: "github.com/anchore/syft", 823 }}, 824 { 825 Name: "golang.org/x/term", 826 Version: "v0.0.0-20210916214954-140adaaadfaf", 827 PURL: "pkg:golang/golang.org/x/term@v0.0.0-20210916214954-140adaaadfaf", 828 Language: pkg.Go, 829 Type: pkg.GoModulePkg, 830 Locations: file.NewLocationSet( 831 file.NewLocationFromCoordinates( 832 file.Coordinates{ 833 RealPath: "/a-path", 834 FileSystemID: "layer-id", 835 }, 836 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 837 ), 838 Metadata: pkg.GolangBinaryBuildinfoEntry{ 839 GoCompiledVersion: goCompiledVersion, 840 Architecture: archDetails, 841 H1Digest: "h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=", 842 MainModule: "github.com/anchore/syft", 843 }, 844 }, 845 unmodifiedMain, 846 }, 847 }, 848 { 849 name: "parse main mod and replace devel with pattern from binary contents", 850 mod: &extendedBuildInfo{ 851 BuildInfo: &debug.BuildInfo{ 852 GoVersion: goCompiledVersion, 853 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 854 Settings: []debug.BuildSetting{ 855 {Key: "GOARCH", Value: archDetails}, 856 {Key: "GOOS", Value: "darwin"}, 857 {Key: "GOAMD64", Value: "v1"}, 858 {Key: "vcs.time", Value: "2022-10-14T19:54:57Z"}, // important! missing revision 859 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X blah=foobar`}, 860 }, 861 }, 862 cryptoSettings: nil, 863 arch: archDetails, 864 }, 865 binaryContent: "\x00v1.0.0-somethingelse+incompatible\x00", 866 expected: []pkg.Package{ 867 { 868 Name: "github.com/anchore/syft", 869 Language: pkg.Go, 870 Type: pkg.GoModulePkg, 871 Version: "v1.0.0-somethingelse+incompatible", 872 PURL: "pkg:golang/github.com/anchore/syft@v1.0.0-somethingelse%2Bincompatible", 873 Locations: file.NewLocationSet( 874 file.NewLocationFromCoordinates( 875 file.Coordinates{ 876 RealPath: "/a-path", 877 FileSystemID: "layer-id", 878 }, 879 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 880 ), 881 Metadata: pkg.GolangBinaryBuildinfoEntry{ 882 GoCompiledVersion: goCompiledVersion, 883 Architecture: archDetails, 884 BuildSettings: []pkg.KeyValue{ 885 { 886 Key: "GOARCH", 887 Value: archDetails, 888 }, 889 { 890 Key: "GOOS", 891 Value: "darwin", 892 }, 893 { 894 Key: "GOAMD64", 895 Value: "v1", 896 }, 897 { 898 Key: "vcs.time", 899 Value: "2022-10-14T19:54:57Z", 900 }, 901 { 902 Key: "-ldflags", 903 Value: `build -ldflags="-w -s -extldflags '-static' -X blah=foobar`, 904 }, 905 }, 906 MainModule: "github.com/anchore/syft", 907 }, 908 }, 909 }, 910 }, 911 } 912 913 for _, test := range tests { 914 t.Run(test.name, func(t *testing.T) { 915 for i := range test.expected { 916 p := &test.expected[i] 917 p.SetID() 918 } 919 location := file.NewLocationFromCoordinates( 920 file.Coordinates{ 921 RealPath: "/a-path", 922 FileSystemID: "layer-id", 923 }, 924 ) 925 926 c := newGoBinaryCataloger(DefaultCatalogerConfig()) 927 reader, err := unionreader.GetUnionReader(io.NopCloser(strings.NewReader(test.binaryContent))) 928 require.NoError(t, err) 929 pkgs := c.buildGoPkgInfo(fileresolver.Empty{}, location, test.mod, test.mod.arch, reader) 930 require.Len(t, pkgs, len(test.expected)) 931 for i, p := range pkgs { 932 pkgtest.AssertPackagesEqual(t, test.expected[i], p) 933 } 934 }) 935 } 936 } 937 938 func Test_extractVersionFromLDFlags(t *testing.T) { 939 tests := []struct { 940 name string 941 ldflags string 942 wantMajorVersion string 943 wantFullVersion string 944 }{ 945 { 946 name: "empty ldflags", 947 ldflags: "", 948 }, 949 { 950 name: "syft ldflags", 951 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 "`, 952 wantMajorVersion: "0", 953 wantFullVersion: "v0.79.0", 954 }, 955 { 956 name: "kubectl ldflags", 957 ldflags: ` build -asmflags=all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes 958 build -compiler=gc 959 build -gcflags="all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes " 960 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"`, 961 wantMajorVersion: "1", 962 wantFullVersion: "v1.25.9", 963 }, 964 { 965 name: "nerdctl ldflags", 966 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"`, 967 wantMajorVersion: "1", 968 wantFullVersion: "v1.3.1", 969 }, 970 { 971 name: "limactl ldflags", 972 ldflags: ` build -ldflags="-s -w -X github.com/lima-vm/lima/pkg/version.Version=v0.15.1"`, 973 wantMajorVersion: "0", 974 wantFullVersion: "v0.15.1", 975 }, 976 { 977 name: "terraform ldflags", 978 ldflags: ` build -ldflags="-w -s -X 'github.com/hashicorp/terraform/version.Version=1.4.6' -X 'github.com/hashicorp/terraform/version.Prerelease='"`, 979 wantMajorVersion: "1", 980 wantFullVersion: "v1.4.6", 981 }, 982 { 983 name: "kube-apiserver ldflags", 984 ldflags: ` build -asmflags=all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes 985 build -buildmode=exe 986 build -compiler=gc 987 build -gcflags="all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes " 988 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"`, 989 wantMajorVersion: "1", 990 wantFullVersion: "v1.27.1", 991 }, 992 { 993 name: "prometheus ldflags", 994 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'" 995 build -tags=netgo,builtinassets,stringlabels`, 996 wantMajorVersion: "2", 997 wantFullVersion: "v2.44.0", 998 }, 999 { 1000 name: "influxdb ldflags", 1001 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'" 1002 build -tags=assets,sqlite_foreign_keys,sqlite_json,static_build,noasm`, 1003 wantMajorVersion: "2", 1004 wantFullVersion: "v2.7.1", 1005 }, 1006 { 1007 name: "gitea ldflags", 1008 ldflags: ` build -ldflags=" -X \"main.MakeVersion=GNU Make 4.1\" -X \"main.Version=1.19.3\" -X \"main.Tags=bindata sqlite sqlite_unlock_notify\" "`, 1009 wantMajorVersion: "1", 1010 wantFullVersion: "v1.19.3", 1011 }, 1012 { 1013 name: "docker sbom cli ldflags", 1014 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 "`, 1015 wantMajorVersion: "0", 1016 wantFullVersion: "v0.6.1-SNAPSHOT-02cf1c8", 1017 }, 1018 { 1019 name: "docker scout ldflags", 1020 ldflags: ` build -ldflags="-w -s -extldflags '-static' -X github.com/docker/scout-cli-plugin/internal.version=0.10.0 "`, 1021 wantMajorVersion: "0", 1022 wantFullVersion: "v0.10.0", 1023 }, 1024 { 1025 name: "influx telegraf ldflags", 1026 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"`, 1027 wantMajorVersion: "1", 1028 wantFullVersion: "v1.26.2", 1029 }, 1030 { 1031 name: "argocd ldflags", 1032 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\""`, 1033 wantMajorVersion: "2", 1034 wantFullVersion: "v2.7.2", 1035 }, 1036 { 1037 name: "kustomize ldflags", 1038 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 "`, 1039 wantMajorVersion: "4", 1040 wantFullVersion: "v4.5.7", 1041 }, 1042 ////////////////////////////////////////////////////////////////// 1043 // negative cases 1044 { 1045 name: "hugo ldflags", 1046 ldflags: ` build -ldflags="-s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio"`, 1047 }, 1048 { 1049 name: "ghostunnel ldflags", 1050 ldflags: ` build -ldflags="-X main.version=77d9aaa"`, 1051 }, 1052 { 1053 name: "opa ldflags", 1054 ldflags: `build -ldflags=" -X github.com/open-policy-agent/opa/version.Hostname=9549178459bc"`, 1055 }, 1056 /////////////////////////////////////////////////////////////////// 1057 // trickier cases 1058 { 1059 name: "macvlan plugin for cri-o ldflags", 1060 ldflags: ` build -ldflags="-extldflags -static -X github.com/containernetworking/plugins/pkg/utils/buildversion.BuildVersion=v1.2.0"`, 1061 wantMajorVersion: "1", 1062 wantFullVersion: "v1.2.0", 1063 }, 1064 { 1065 name: "coder ldflags", 1066 ldflags: ` build -ldflags="-s -w -X 'github.com/coder/coder/buildinfo.tag=0.23.4'"`, 1067 wantMajorVersion: "0", 1068 wantFullVersion: "v0.23.4", 1069 }, 1070 /////////////////////////////////////////////////////////////////// 1071 // don't know how to handle these... yet 1072 //{ 1073 // // package name: pkgName: "github.com/krakendio/krakend-ce/v2", 1074 // name: "krakenD ldflags", 1075 // 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) "`, 1076 // wantMajorVersion: "2.3.2", 1077 // wantFullVersion: "v2.3.2", 1078 //}, 1079 //{ 1080 // // package name: pkgName: "github.com/krakendio/krakend-ce/v2", 1081 // name: "krakenD ldflags -- answer embedded in the middle", 1082 // 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) "`, 1083 // wantMajorVersion: "2.3.2", 1084 // wantFullVersion: "v2.3.2", 1085 //}, 1086 } 1087 for _, tt := range tests { 1088 t.Run(tt.name, func(t *testing.T) { 1089 gotMajorVersion, gotFullVersion := extractVersionFromLDFlags(tt.ldflags) 1090 assert.Equal(t, tt.wantMajorVersion, gotMajorVersion, "unexpected major version") 1091 assert.Equal(t, tt.wantFullVersion, gotFullVersion, "unexpected full version") 1092 }) 1093 } 1094 } 1095 1096 func Test_extractVersionFromContents(t *testing.T) { 1097 tests := []struct { 1098 name string 1099 contents io.Reader 1100 want string 1101 }{ 1102 { 1103 name: "empty string on error", 1104 contents: &alwaysErrorReader{}, 1105 want: "", 1106 }, 1107 { 1108 name: "empty string on empty reader", 1109 contents: bytes.NewReader([]byte{}), 1110 want: "", 1111 }, 1112 { 1113 name: "null-byte delimited semver", 1114 contents: strings.NewReader("\x001.2.3\x00"), 1115 want: "1.2.3", 1116 }, 1117 { 1118 name: "null-byte delimited semver with v prefix", 1119 contents: strings.NewReader("\x00v1.2.3\x00"), 1120 want: "v1.2.3", 1121 }, 1122 { 1123 // 01a0bfc8: 0e74 5a3b 0000 a04c 7631 2e39 2e35 0000 .tZ;...Lv1.9.5.. from nginx-ingress-controller 1124 // at /nginx-ingress-controller in registry.k8s.io/ingress-nginx/controller:v1.9.5 1125 // digest: sha256:b3aba22b1da80e7acfc52b115cae1d4c687172cbf2b742d5b502419c25ff340e 1126 // TODO: eventually use something for managing snippets, similar to what's used with binary classifier tests 1127 name: "null byte, then random byte, then L then semver", 1128 contents: strings.NewReader("\x0e\x74\x5a\x3b\x00\x00\xa0\x4cv1.9.5\x00\x00"), 1129 want: "v1.9.5", 1130 }, 1131 } 1132 for _, tt := range tests { 1133 t.Run(tt.name, func(t *testing.T) { 1134 got := extractVersionFromContents(tt.contents) 1135 assert.Equal(t, tt.want, got) 1136 }) 1137 } 1138 } 1139 1140 type alwaysErrorReader struct{} 1141 1142 func (alwaysErrorReader) Read(_ []byte) (int, error) { 1143 return 0, errors.New("read from always error reader") 1144 }