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