github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/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/pkg" 19 "github.com/lineaje-labs/syft/syft/internal/fileresolver" 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 Metadata: pkg.GolangBinaryBuildinfoEntry{ 148 GoCompiledVersion: goCompiledVersion, 149 Architecture: archDetails, 150 BuildSettings: defaultBuildSettings, 151 MainModule: "github.com/anchore/syft", 152 }, 153 } 154 155 tests := []struct { 156 name string 157 mod *extendedBuildInfo 158 expected []pkg.Package 159 }{ 160 { 161 name: "package without name", 162 mod: &extendedBuildInfo{ 163 BuildInfo: &debug.BuildInfo{ 164 Deps: []*debug.Module{ 165 { 166 Path: "github.com/adrg/xdg", 167 }, 168 { 169 Path: "", 170 Version: "v0.2.1", 171 }, 172 }, 173 }, 174 cryptoSettings: nil, 175 arch: "", 176 }, 177 expected: []pkg.Package{ 178 { 179 Name: "github.com/adrg/xdg", 180 PURL: "pkg:golang/github.com/adrg/xdg", 181 Language: pkg.Go, 182 Type: pkg.GoModulePkg, 183 Locations: file.NewLocationSet( 184 file.NewLocationFromCoordinates( 185 file.Coordinates{ 186 RealPath: "/a-path", 187 FileSystemID: "layer-id", 188 }, 189 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 190 ), 191 Metadata: pkg.GolangBinaryBuildinfoEntry{}, 192 }, 193 }, 194 }, 195 { 196 name: "buildGoPkgInfo parses a blank mod and returns no packages", 197 mod: &extendedBuildInfo{&debug.BuildInfo{}, nil, ""}, 198 expected: []pkg.Package(nil), 199 }, 200 { 201 name: "parse a mod without main module", 202 mod: &extendedBuildInfo{ 203 BuildInfo: &debug.BuildInfo{ 204 GoVersion: goCompiledVersion, 205 Settings: []debug.BuildSetting{ 206 {Key: "GOARCH", Value: archDetails}, 207 {Key: "GOOS", Value: "darwin"}, 208 {Key: "GOAMD64", Value: "v1"}, 209 }, 210 Deps: []*debug.Module{ 211 { 212 Path: "github.com/adrg/xdg", 213 Version: "v0.2.1", 214 Sum: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=", 215 }, 216 }, 217 }, 218 cryptoSettings: nil, 219 arch: archDetails, 220 }, 221 expected: []pkg.Package{ 222 { 223 Name: "github.com/adrg/xdg", 224 Version: "v0.2.1", 225 PURL: "pkg:golang/github.com/adrg/xdg@v0.2.1", 226 Language: pkg.Go, 227 Type: pkg.GoModulePkg, 228 Locations: file.NewLocationSet( 229 file.NewLocationFromCoordinates( 230 file.Coordinates{ 231 RealPath: "/a-path", 232 FileSystemID: "layer-id", 233 }, 234 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 235 ), 236 Metadata: pkg.GolangBinaryBuildinfoEntry{ 237 GoCompiledVersion: goCompiledVersion, 238 Architecture: archDetails, 239 H1Digest: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=", 240 }, 241 }, 242 }, 243 }, 244 { 245 name: "parse a mod with path but no main module", 246 mod: &extendedBuildInfo{ 247 BuildInfo: &debug.BuildInfo{ 248 GoVersion: goCompiledVersion, 249 Settings: []debug.BuildSetting{ 250 {Key: "GOARCH", Value: archDetails}, 251 {Key: "GOOS", Value: "darwin"}, 252 {Key: "GOAMD64", Value: "v1"}, 253 }, 254 Path: "github.com/a/b/c", 255 }, 256 cryptoSettings: []string{"boringcrypto + fips"}, 257 arch: archDetails, 258 }, 259 expected: []pkg.Package{ 260 { 261 Name: "github.com/a/b/c", 262 Version: "(devel)", 263 PURL: "pkg:golang/github.com/a/b/c@(devel)", 264 Language: pkg.Go, 265 Type: pkg.GoModulePkg, 266 Locations: file.NewLocationSet( 267 file.NewLocationFromCoordinates( 268 file.Coordinates{ 269 RealPath: "/a-path", 270 FileSystemID: "layer-id", 271 }, 272 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 273 ), 274 Metadata: pkg.GolangBinaryBuildinfoEntry{ 275 GoCompiledVersion: goCompiledVersion, 276 Architecture: archDetails, 277 H1Digest: "", 278 BuildSettings: map[string]string{ 279 "GOAMD64": "v1", 280 "GOARCH": "amd64", 281 "GOOS": "darwin", 282 }, 283 MainModule: "github.com/a/b/c", 284 GoCryptoSettings: []string{"boringcrypto + fips"}, 285 }, 286 }, 287 }, 288 }, 289 { 290 name: "parse a mod without packages", 291 mod: &extendedBuildInfo{ 292 BuildInfo: &debug.BuildInfo{ 293 GoVersion: goCompiledVersion, 294 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 295 Settings: []debug.BuildSetting{ 296 {Key: "GOARCH", Value: archDetails}, 297 {Key: "GOOS", Value: "darwin"}, 298 {Key: "GOAMD64", Value: "v1"}, 299 }, 300 }, 301 cryptoSettings: nil, 302 arch: archDetails, 303 }, 304 expected: []pkg.Package{unmodifiedMain}, 305 }, 306 { 307 name: "parse main mod and replace devel pseudo version and ldflags exists (but contains no version)", 308 mod: &extendedBuildInfo{ 309 BuildInfo: &debug.BuildInfo{ 310 GoVersion: goCompiledVersion, 311 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 312 Settings: []debug.BuildSetting{ 313 {Key: "GOARCH", Value: archDetails}, 314 {Key: "GOOS", Value: "darwin"}, 315 {Key: "GOAMD64", Value: "v1"}, 316 {Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"}, 317 {Key: "vcs.time", Value: "2022-10-14T19:54:57Z"}, 318 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X blah=foobar`}, 319 }, 320 }, 321 cryptoSettings: nil, 322 arch: archDetails, 323 }, 324 expected: []pkg.Package{ 325 { 326 Name: "github.com/anchore/syft", 327 Language: pkg.Go, 328 Type: pkg.GoModulePkg, 329 Version: "v0.0.0-20221014195457-41bc6bb41035", 330 PURL: "pkg:golang/github.com/anchore/syft@v0.0.0-20221014195457-41bc6bb41035", 331 Locations: file.NewLocationSet( 332 file.NewLocationFromCoordinates( 333 file.Coordinates{ 334 RealPath: "/a-path", 335 FileSystemID: "layer-id", 336 }, 337 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 338 ), 339 Metadata: pkg.GolangBinaryBuildinfoEntry{ 340 GoCompiledVersion: goCompiledVersion, 341 Architecture: archDetails, 342 BuildSettings: map[string]string{ 343 "GOARCH": archDetails, 344 "GOOS": "darwin", 345 "GOAMD64": "v1", 346 "vcs.revision": "41bc6bb410352845f22766e27dd48ba93aa825a4", 347 "vcs.time": "2022-10-14T19:54:57Z", 348 "-ldflags": `build -ldflags="-w -s -extldflags '-static' -X blah=foobar`, 349 }, 350 MainModule: "github.com/anchore/syft", 351 }, 352 }, 353 }, 354 }, 355 { 356 name: "parse main mod and replace devel version with one from ldflags with vcs. build settings", 357 mod: &extendedBuildInfo{ 358 BuildInfo: &debug.BuildInfo{ 359 GoVersion: goCompiledVersion, 360 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 361 Settings: []debug.BuildSetting{ 362 {Key: "GOARCH", Value: archDetails}, 363 {Key: "GOOS", Value: "darwin"}, 364 {Key: "GOAMD64", Value: "v1"}, 365 {Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"}, 366 {Key: "vcs.time", Value: "2022-10-14T19:54:57Z"}, 367 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`}, 368 }, 369 }, 370 cryptoSettings: nil, 371 arch: archDetails, 372 }, 373 expected: []pkg.Package{ 374 { 375 Name: "github.com/anchore/syft", 376 Language: pkg.Go, 377 Type: pkg.GoModulePkg, 378 Version: "v0.79.0", 379 PURL: "pkg:golang/github.com/anchore/syft@v0.79.0", 380 Locations: file.NewLocationSet( 381 file.NewLocationFromCoordinates( 382 file.Coordinates{ 383 RealPath: "/a-path", 384 FileSystemID: "layer-id", 385 }, 386 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 387 ), 388 Metadata: pkg.GolangBinaryBuildinfoEntry{ 389 GoCompiledVersion: goCompiledVersion, 390 Architecture: archDetails, 391 BuildSettings: map[string]string{ 392 "GOARCH": archDetails, 393 "GOOS": "darwin", 394 "GOAMD64": "v1", 395 "vcs.revision": "41bc6bb410352845f22766e27dd48ba93aa825a4", 396 "vcs.time": "2022-10-14T19:54:57Z", 397 "-ldflags": `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`, 398 }, 399 MainModule: "github.com/anchore/syft", 400 }, 401 }, 402 }, 403 }, 404 { 405 name: "parse main mod and replace devel version with one from ldflags without any vcs. build settings", 406 mod: &extendedBuildInfo{ 407 BuildInfo: &debug.BuildInfo{ 408 GoVersion: goCompiledVersion, 409 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 410 Settings: []debug.BuildSetting{ 411 {Key: "GOARCH", Value: archDetails}, 412 {Key: "GOOS", Value: "darwin"}, 413 {Key: "GOAMD64", Value: "v1"}, 414 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`}, 415 }, 416 }, 417 cryptoSettings: nil, 418 arch: archDetails, 419 }, 420 expected: []pkg.Package{ 421 { 422 Name: "github.com/anchore/syft", 423 Language: pkg.Go, 424 Type: pkg.GoModulePkg, 425 Version: "v0.79.0", 426 PURL: "pkg:golang/github.com/anchore/syft@v0.79.0", 427 Locations: file.NewLocationSet( 428 file.NewLocationFromCoordinates( 429 file.Coordinates{ 430 RealPath: "/a-path", 431 FileSystemID: "layer-id", 432 }, 433 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 434 ), 435 Metadata: pkg.GolangBinaryBuildinfoEntry{ 436 GoCompiledVersion: goCompiledVersion, 437 Architecture: archDetails, 438 BuildSettings: map[string]string{ 439 "GOARCH": archDetails, 440 "GOOS": "darwin", 441 "GOAMD64": "v1", 442 "-ldflags": `build -ldflags="-w -s -extldflags '-static' -X github.com/anchore/syft/internal/version.version=0.79.0`, 443 }, 444 MainModule: "github.com/anchore/syft", 445 }, 446 }, 447 }, 448 }, 449 { 450 name: "parse main mod and replace devel version with one from ldflags main.version without any vcs. build settings", 451 mod: &extendedBuildInfo{ 452 BuildInfo: &debug.BuildInfo{ 453 GoVersion: goCompiledVersion, 454 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 455 Settings: []debug.BuildSetting{ 456 {Key: "GOARCH", Value: archDetails}, 457 {Key: "GOOS", Value: "darwin"}, 458 {Key: "GOAMD64", Value: "v1"}, 459 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X main.version=0.79.0`}, 460 }, 461 }, 462 cryptoSettings: nil, 463 arch: archDetails, 464 }, 465 expected: []pkg.Package{ 466 { 467 Name: "github.com/anchore/syft", 468 Language: pkg.Go, 469 Type: pkg.GoModulePkg, 470 Version: "v0.79.0", 471 PURL: "pkg:golang/github.com/anchore/syft@v0.79.0", 472 Locations: file.NewLocationSet( 473 file.NewLocationFromCoordinates( 474 file.Coordinates{ 475 RealPath: "/a-path", 476 FileSystemID: "layer-id", 477 }, 478 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 479 ), 480 Metadata: pkg.GolangBinaryBuildinfoEntry{ 481 GoCompiledVersion: goCompiledVersion, 482 Architecture: archDetails, 483 BuildSettings: map[string]string{ 484 "GOARCH": archDetails, 485 "GOOS": "darwin", 486 "GOAMD64": "v1", 487 "-ldflags": `build -ldflags="-w -s -extldflags '-static' -X main.version=0.79.0`, 488 }, 489 MainModule: "github.com/anchore/syft", 490 }, 491 }, 492 }, 493 }, 494 { 495 name: "parse main mod and replace devel version with one from ldflags main.Version without any vcs. build settings", 496 mod: &extendedBuildInfo{ 497 BuildInfo: &debug.BuildInfo{ 498 GoVersion: goCompiledVersion, 499 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 500 Settings: []debug.BuildSetting{ 501 {Key: "GOARCH", Value: archDetails}, 502 {Key: "GOOS", Value: "darwin"}, 503 {Key: "GOAMD64", Value: "v1"}, 504 {Key: "-ldflags", Value: `build -ldflags="-w -s -extldflags '-static' -X main.Version=0.79.0`}, 505 }, 506 }, 507 cryptoSettings: nil, 508 arch: archDetails, 509 }, 510 expected: []pkg.Package{ 511 { 512 Name: "github.com/anchore/syft", 513 Language: pkg.Go, 514 Type: pkg.GoModulePkg, 515 Version: "v0.79.0", 516 PURL: "pkg:golang/github.com/anchore/syft@v0.79.0", 517 Locations: file.NewLocationSet( 518 file.NewLocationFromCoordinates( 519 file.Coordinates{ 520 RealPath: "/a-path", 521 FileSystemID: "layer-id", 522 }, 523 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 524 ), 525 Metadata: pkg.GolangBinaryBuildinfoEntry{ 526 GoCompiledVersion: goCompiledVersion, 527 Architecture: archDetails, 528 BuildSettings: map[string]string{ 529 "GOARCH": archDetails, 530 "GOOS": "darwin", 531 "GOAMD64": "v1", 532 "-ldflags": `build -ldflags="-w -s -extldflags '-static' -X main.Version=0.79.0`, 533 }, 534 MainModule: "github.com/anchore/syft", 535 }, 536 }, 537 }, 538 }, 539 { 540 name: "parse main mod and replace devel version with a pseudo version", 541 mod: &extendedBuildInfo{ 542 BuildInfo: &debug.BuildInfo{ 543 GoVersion: goCompiledVersion, 544 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 545 Settings: []debug.BuildSetting{ 546 {Key: "GOARCH", Value: archDetails}, 547 {Key: "GOOS", Value: "darwin"}, 548 {Key: "GOAMD64", Value: "v1"}, 549 {Key: "vcs.revision", Value: "41bc6bb410352845f22766e27dd48ba93aa825a4"}, 550 {Key: "vcs.time", Value: "2022-10-14T19:54:57Z"}, 551 }, 552 }, 553 cryptoSettings: nil, 554 arch: archDetails, 555 }, 556 expected: []pkg.Package{ 557 { 558 Name: "github.com/anchore/syft", 559 Language: pkg.Go, 560 Type: pkg.GoModulePkg, 561 Version: "v0.0.0-20221014195457-41bc6bb41035", 562 PURL: "pkg:golang/github.com/anchore/syft@v0.0.0-20221014195457-41bc6bb41035", 563 Locations: file.NewLocationSet( 564 file.NewLocationFromCoordinates( 565 file.Coordinates{ 566 RealPath: "/a-path", 567 FileSystemID: "layer-id", 568 }, 569 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 570 ), 571 Metadata: pkg.GolangBinaryBuildinfoEntry{ 572 GoCompiledVersion: goCompiledVersion, 573 Architecture: archDetails, 574 BuildSettings: map[string]string{ 575 "GOARCH": archDetails, 576 "GOOS": "darwin", 577 "GOAMD64": "v1", 578 "vcs.revision": "41bc6bb410352845f22766e27dd48ba93aa825a4", 579 "vcs.time": "2022-10-14T19:54:57Z", 580 }, 581 MainModule: "github.com/anchore/syft", 582 }, 583 }, 584 }, 585 }, 586 { 587 name: "parse a populated mod string and returns packages but no source info", 588 mod: &extendedBuildInfo{ 589 BuildInfo: &debug.BuildInfo{ 590 GoVersion: goCompiledVersion, 591 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 592 Settings: []debug.BuildSetting{ 593 {Key: "GOARCH", Value: archDetails}, 594 {Key: "GOOS", Value: "darwin"}, 595 {Key: "GOAMD64", Value: "v1"}, 596 }, 597 Deps: []*debug.Module{ 598 { 599 Path: "github.com/adrg/xdg", 600 Version: "v0.2.1", 601 Sum: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=", 602 }, 603 { 604 Path: "github.com/anchore/client-go", 605 Version: "v0.0.0-20210222170800-9c70f9b80bcf", 606 Sum: "h1:DYssiUV1pBmKqzKsm4mqXx8artqC0Q8HgZsVI3lMsAg=", 607 }, 608 }, 609 }, 610 cryptoSettings: nil, 611 arch: archDetails, 612 }, 613 expected: []pkg.Package{ 614 { 615 Name: "github.com/adrg/xdg", 616 Version: "v0.2.1", 617 PURL: "pkg:golang/github.com/adrg/xdg@v0.2.1", 618 Language: pkg.Go, 619 Type: pkg.GoModulePkg, 620 Locations: file.NewLocationSet( 621 file.NewLocationFromCoordinates( 622 file.Coordinates{ 623 RealPath: "/a-path", 624 FileSystemID: "layer-id", 625 }, 626 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 627 ), 628 Metadata: pkg.GolangBinaryBuildinfoEntry{ 629 GoCompiledVersion: goCompiledVersion, 630 Architecture: archDetails, 631 H1Digest: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=", 632 MainModule: "github.com/anchore/syft", 633 }, 634 }, 635 { 636 Name: "github.com/anchore/client-go", 637 Version: "v0.0.0-20210222170800-9c70f9b80bcf", 638 PURL: "pkg:golang/github.com/anchore/client-go@v0.0.0-20210222170800-9c70f9b80bcf", 639 Language: pkg.Go, 640 Type: pkg.GoModulePkg, 641 Locations: file.NewLocationSet( 642 file.NewLocationFromCoordinates( 643 file.Coordinates{ 644 RealPath: "/a-path", 645 FileSystemID: "layer-id", 646 }, 647 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 648 ), 649 Metadata: pkg.GolangBinaryBuildinfoEntry{ 650 GoCompiledVersion: goCompiledVersion, 651 Architecture: archDetails, 652 H1Digest: "h1:DYssiUV1pBmKqzKsm4mqXx8artqC0Q8HgZsVI3lMsAg=", 653 MainModule: "github.com/anchore/syft", 654 }, 655 }, 656 unmodifiedMain, 657 }, 658 }, 659 { 660 name: "parse a populated mod string and returns packages when a replace directive exists", 661 mod: &extendedBuildInfo{ 662 BuildInfo: &debug.BuildInfo{ 663 GoVersion: goCompiledVersion, 664 Main: debug.Module{Path: "github.com/anchore/syft", Version: "(devel)"}, 665 Settings: []debug.BuildSetting{ 666 {Key: "GOARCH", Value: archDetails}, 667 {Key: "GOOS", Value: "darwin"}, 668 {Key: "GOAMD64", Value: "v1"}, 669 }, 670 Deps: []*debug.Module{ 671 { 672 Path: "golang.org/x/sys", 673 Version: "v0.0.0-20211006194710-c8a6f5223071", 674 Sum: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=", 675 }, 676 { 677 Path: "golang.org/x/term", 678 Version: "v0.0.0-20210927222741-03fcf44c2211", 679 Sum: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=", 680 Replace: &debug.Module{ 681 Path: "golang.org/x/term", 682 Version: "v0.0.0-20210916214954-140adaaadfaf", 683 Sum: "h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=", 684 }, 685 }, 686 }, 687 }, 688 cryptoSettings: nil, 689 arch: archDetails, 690 }, 691 expected: []pkg.Package{ 692 { 693 Name: "golang.org/x/sys", 694 Version: "v0.0.0-20211006194710-c8a6f5223071", 695 PURL: "pkg:golang/golang.org/x/sys@v0.0.0-20211006194710-c8a6f5223071", 696 Language: pkg.Go, 697 Type: pkg.GoModulePkg, 698 Locations: file.NewLocationSet( 699 file.NewLocationFromCoordinates( 700 file.Coordinates{ 701 RealPath: "/a-path", 702 FileSystemID: "layer-id", 703 }, 704 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 705 ), 706 Metadata: pkg.GolangBinaryBuildinfoEntry{ 707 GoCompiledVersion: goCompiledVersion, 708 Architecture: archDetails, 709 H1Digest: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=", 710 MainModule: "github.com/anchore/syft", 711 }}, 712 { 713 Name: "golang.org/x/term", 714 Version: "v0.0.0-20210916214954-140adaaadfaf", 715 PURL: "pkg:golang/golang.org/x/term@v0.0.0-20210916214954-140adaaadfaf", 716 Language: pkg.Go, 717 Type: pkg.GoModulePkg, 718 Locations: file.NewLocationSet( 719 file.NewLocationFromCoordinates( 720 file.Coordinates{ 721 RealPath: "/a-path", 722 FileSystemID: "layer-id", 723 }, 724 ).WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 725 ), 726 Metadata: pkg.GolangBinaryBuildinfoEntry{ 727 GoCompiledVersion: goCompiledVersion, 728 Architecture: archDetails, 729 H1Digest: "h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=", 730 MainModule: "github.com/anchore/syft", 731 }, 732 }, 733 unmodifiedMain, 734 }, 735 }, 736 } 737 738 for _, test := range tests { 739 t.Run(test.name, func(t *testing.T) { 740 for i := range test.expected { 741 p := &test.expected[i] 742 p.SetID() 743 } 744 location := file.NewLocationFromCoordinates( 745 file.Coordinates{ 746 RealPath: "/a-path", 747 FileSystemID: "layer-id", 748 }, 749 ) 750 751 c := goBinaryCataloger{} 752 pkgs := c.buildGoPkgInfo(fileresolver.Empty{}, location, test.mod, test.mod.arch) 753 assert.Equal(t, test.expected, pkgs) 754 }) 755 } 756 } 757 758 func Test_extractVersionFromLDFlags(t *testing.T) { 759 tests := []struct { 760 name string 761 ldflags string 762 wantMajorVersion string 763 wantFullVersion string 764 }{ 765 { 766 name: "empty ldflags", 767 ldflags: "", 768 }, 769 { 770 name: "syft ldflags", 771 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 "`, 772 wantMajorVersion: "0", 773 wantFullVersion: "v0.79.0", 774 }, 775 { 776 name: "kubectl ldflags", 777 ldflags: ` build -asmflags=all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes 778 build -compiler=gc 779 build -gcflags="all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes " 780 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"`, 781 wantMajorVersion: "1", 782 wantFullVersion: "v1.25.9", 783 }, 784 { 785 name: "nerdctl ldflags", 786 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"`, 787 wantMajorVersion: "1", 788 wantFullVersion: "v1.3.1", 789 }, 790 { 791 name: "limactl ldflags", 792 ldflags: ` build -ldflags="-s -w -X github.com/lima-vm/lima/pkg/version.Version=v0.15.1"`, 793 wantMajorVersion: "0", 794 wantFullVersion: "v0.15.1", 795 }, 796 { 797 name: "terraform ldflags", 798 ldflags: ` build -ldflags="-w -s -X 'github.com/hashicorp/terraform/version.Version=1.4.6' -X 'github.com/hashicorp/terraform/version.Prerelease='"`, 799 wantMajorVersion: "1", 800 wantFullVersion: "v1.4.6", 801 }, 802 { 803 name: "kube-apiserver ldflags", 804 ldflags: ` build -asmflags=all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes 805 build -buildmode=exe 806 build -compiler=gc 807 build -gcflags="all=-trimpath=/workspace/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes " 808 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"`, 809 wantMajorVersion: "1", 810 wantFullVersion: "v1.27.1", 811 }, 812 { 813 name: "prometheus ldflags", 814 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'" 815 build -tags=netgo,builtinassets,stringlabels`, 816 wantMajorVersion: "2", 817 wantFullVersion: "v2.44.0", 818 }, 819 { 820 name: "influxdb ldflags", 821 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'" 822 build -tags=assets,sqlite_foreign_keys,sqlite_json,static_build,noasm`, 823 wantMajorVersion: "2", 824 wantFullVersion: "v2.7.1", 825 }, 826 { 827 name: "gitea ldflags", 828 ldflags: ` build -ldflags=" -X \"main.MakeVersion=GNU Make 4.1\" -X \"main.Version=1.19.3\" -X \"main.Tags=bindata sqlite sqlite_unlock_notify\" "`, 829 wantMajorVersion: "1", 830 wantFullVersion: "v1.19.3", 831 }, 832 { 833 name: "docker sbom cli ldflags", 834 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 "`, 835 wantMajorVersion: "0", 836 wantFullVersion: "v0.6.1-SNAPSHOT-02cf1c8", 837 }, 838 { 839 name: "docker scout ldflags", 840 ldflags: ` build -ldflags="-w -s -extldflags '-static' -X github.com/docker/scout-cli-plugin/internal.version=0.10.0 "`, 841 wantMajorVersion: "0", 842 wantFullVersion: "v0.10.0", 843 }, 844 { 845 name: "influx telegraf ldflags", 846 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"`, 847 wantMajorVersion: "1", 848 wantFullVersion: "v1.26.2", 849 }, 850 { 851 name: "argocd ldflags", 852 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\""`, 853 wantMajorVersion: "2", 854 wantFullVersion: "v2.7.2", 855 }, 856 { 857 name: "kustomize ldflags", 858 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 "`, 859 wantMajorVersion: "4", 860 wantFullVersion: "v4.5.7", 861 }, 862 // //////////////////////////////////////////////////////////////// 863 // negative cases 864 { 865 name: "hugo ldflags", 866 ldflags: ` build -ldflags="-s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio"`, 867 }, 868 { 869 name: "ghostunnel ldflags", 870 ldflags: ` build -ldflags="-X main.version=77d9aaa"`, 871 }, 872 { 873 name: "opa ldflags", 874 ldflags: `build -ldflags=" -X github.com/open-policy-agent/opa/version.Hostname=9549178459bc"`, 875 }, 876 // ///////////////////////////////////////////////////////////////// 877 // trickier cases 878 { 879 name: "macvlan plugin for cri-o ldflags", 880 ldflags: ` build -ldflags="-extldflags -static -X github.com/containernetworking/plugins/pkg/utils/buildversion.BuildVersion=v1.2.0"`, 881 wantMajorVersion: "1", 882 wantFullVersion: "v1.2.0", 883 }, 884 { 885 name: "coder ldflags", 886 ldflags: ` build -ldflags="-s -w -X 'github.com/coder/coder/buildinfo.tag=0.23.4'"`, 887 wantMajorVersion: "0", 888 wantFullVersion: "v0.23.4", 889 }, 890 // ///////////////////////////////////////////////////////////////// 891 // don't know how to handle these... yet 892 // { 893 // // package name: pkgName: "github.com/krakendio/krakend-ce/v2", 894 // name: "krakenD ldflags", 895 // 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) "`, 896 // wantMajorVersion: "2.3.2", 897 // wantFullVersion: "v2.3.2", 898 // }, 899 // { 900 // // package name: pkgName: "github.com/krakendio/krakend-ce/v2", 901 // name: "krakenD ldflags -- answer embedded in the middle", 902 // 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) "`, 903 // wantMajorVersion: "2.3.2", 904 // wantFullVersion: "v2.3.2", 905 // }, 906 } 907 for _, tt := range tests { 908 t.Run(tt.name, func(t *testing.T) { 909 gotMajorVersion, gotFullVersion := extractVersionFromLDFlags(tt.ldflags) 910 assert.Equal(t, tt.wantMajorVersion, gotMajorVersion, "unexpected major version") 911 assert.Equal(t, tt.wantFullVersion, gotFullVersion, "unexpected full version") 912 }) 913 } 914 }