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