github.com/goreleaser/goreleaser@v1.25.1/internal/pipe/sbom/sbom_test.go (about) 1 package sbom 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "sort" 8 "strings" 9 "testing" 10 11 "github.com/goreleaser/goreleaser/internal/artifact" 12 "github.com/goreleaser/goreleaser/internal/skips" 13 "github.com/goreleaser/goreleaser/internal/testctx" 14 "github.com/goreleaser/goreleaser/internal/testlib" 15 "github.com/goreleaser/goreleaser/internal/tmpl" 16 "github.com/goreleaser/goreleaser/pkg/config" 17 "github.com/goreleaser/goreleaser/pkg/context" 18 "github.com/stretchr/testify/assert" 19 "github.com/stretchr/testify/require" 20 ) 21 22 func TestDescription(t *testing.T) { 23 require.NotEmpty(t, Pipe{}.String()) 24 } 25 26 func TestSBOMCatalogDefault(t *testing.T) { 27 defaultArgs := []string{"$artifact", "--output", "spdx-json=$document"} 28 defaultSboms := []string{ 29 "{{ .ArtifactName }}.sbom", 30 } 31 defaultCmd := "syft" 32 tests := []struct { 33 configs []config.SBOM 34 artifact string 35 cmd string 36 sboms []string 37 args []string 38 env []string 39 err bool 40 }{ 41 { 42 configs: []config.SBOM{ 43 { 44 // empty 45 }, 46 }, 47 artifact: "archive", 48 cmd: defaultCmd, 49 sboms: defaultSboms, 50 args: defaultArgs, 51 env: []string{ 52 "SYFT_FILE_METADATA_CATALOGER_ENABLED=true", 53 }, 54 }, 55 { 56 configs: []config.SBOM{ 57 { 58 Artifacts: "package", 59 }, 60 }, 61 artifact: "package", 62 cmd: defaultCmd, 63 sboms: defaultSboms, 64 args: defaultArgs, 65 }, 66 { 67 configs: []config.SBOM{ 68 { 69 Artifacts: "archive", 70 }, 71 }, 72 artifact: "archive", 73 cmd: defaultCmd, 74 sboms: defaultSboms, 75 args: defaultArgs, 76 env: []string{ 77 "SYFT_FILE_METADATA_CATALOGER_ENABLED=true", 78 }, 79 }, 80 { 81 configs: []config.SBOM{ 82 { 83 Artifacts: "archive", 84 Env: []string{ 85 "something=something-else", 86 }, 87 }, 88 }, 89 artifact: "archive", 90 cmd: defaultCmd, 91 sboms: defaultSboms, 92 args: defaultArgs, 93 env: []string{ 94 "something=something-else", 95 }, 96 }, 97 { 98 configs: []config.SBOM{ 99 { 100 Artifacts: "any", 101 }, 102 }, 103 artifact: "any", 104 cmd: defaultCmd, 105 sboms: []string{}, 106 args: defaultArgs, 107 }, 108 { 109 configs: []config.SBOM{ 110 { 111 Artifacts: "binary", 112 }, 113 }, 114 artifact: "binary", 115 cmd: defaultCmd, 116 sboms: []string{"{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}.sbom"}, 117 args: defaultArgs, 118 }, 119 { 120 configs: []config.SBOM{ 121 { 122 Artifacts: "source", 123 }, 124 }, 125 artifact: "source", 126 cmd: defaultCmd, 127 sboms: defaultSboms, 128 args: defaultArgs, 129 env: []string{ 130 "SYFT_FILE_METADATA_CATALOGER_ENABLED=true", 131 }, 132 }, 133 { 134 // multiple documents are not allowed when artifacts != "any" 135 configs: []config.SBOM{ 136 { 137 Artifacts: "binary", 138 Documents: []string{ 139 "doc1", 140 "doc2", 141 }, 142 }, 143 }, 144 err: true, 145 }, 146 } 147 148 for _, test := range tests { 149 t.Run(fmt.Sprintf("artifact=%q", test.configs[0].Artifacts), func(t *testing.T) { 150 testlib.CheckPath(t, "syft") 151 ctx := testctx.NewWithCfg(config.Project{ 152 SBOMs: test.configs, 153 }) 154 err := Pipe{}.Default(ctx) 155 if test.err { 156 require.Error(t, err) 157 return 158 } 159 require.NoError(t, err) 160 require.Equal(t, ctx.Config.SBOMs[0].Cmd, test.cmd) 161 require.Equal(t, ctx.Config.SBOMs[0].Documents, test.sboms) 162 require.Equal(t, ctx.Config.SBOMs[0].Args, test.args) 163 require.Equal(t, ctx.Config.SBOMs[0].Env, test.env) 164 require.Equal(t, ctx.Config.SBOMs[0].Artifacts, test.artifact) 165 }) 166 } 167 } 168 169 func TestSBOMCatalogInvalidArtifacts(t *testing.T) { 170 ctx := testctx.NewWithCfg(config.Project{ 171 SBOMs: []config.SBOM{{Artifacts: "foo"}}, 172 }) 173 err := Pipe{}.Run(ctx) 174 require.EqualError(t, err, "invalid list of artifacts to catalog: foo") 175 } 176 177 func TestSeveralSBOMsWithTheSameID(t *testing.T) { 178 ctx := testctx.NewWithCfg(config.Project{ 179 SBOMs: []config.SBOM{ 180 { 181 ID: "a", 182 }, 183 { 184 ID: "a", 185 }, 186 }, 187 }) 188 require.EqualError(t, Pipe{}.Default(ctx), "found 2 sboms with the ID 'a', please fix your config") 189 } 190 191 func TestSkipCataloging(t *testing.T) { 192 t.Run("skip", func(t *testing.T) { 193 require.True(t, Pipe{}.Skip(testctx.New())) 194 }) 195 196 t.Run("skip SBOM cataloging", func(t *testing.T) { 197 ctx := testctx.NewWithCfg(config.Project{ 198 SBOMs: []config.SBOM{ 199 { 200 Artifacts: "all", 201 }, 202 }, 203 }, testctx.Skip(skips.SBOM)) 204 require.True(t, Pipe{}.Skip(ctx)) 205 }) 206 207 t.Run("dont skip", func(t *testing.T) { 208 ctx := testctx.NewWithCfg(config.Project{ 209 SBOMs: []config.SBOM{ 210 { 211 Artifacts: "all", 212 }, 213 }, 214 }) 215 require.False(t, Pipe{}.Skip(ctx)) 216 }) 217 } 218 219 func TestSBOMCatalogArtifacts(t *testing.T) { 220 tests := []struct { 221 desc string 222 ctx *context.Context 223 sbomPaths []string 224 sbomNames []string 225 expectedErrAs any 226 expectedErrMsg string 227 }{ 228 { 229 desc: "catalog errors", 230 expectedErrMsg: "cataloging artifacts: exit failed", 231 ctx: testctx.NewWithCfg(config.Project{ 232 SBOMs: []config.SBOM{ 233 { 234 Artifacts: "binary", 235 Cmd: "exit", 236 Args: []string{"1"}, 237 }, 238 }, 239 }), 240 }, 241 { 242 desc: "invalid args template", 243 expectedErrAs: &tmpl.Error{}, 244 ctx: testctx.NewWithCfg(config.Project{ 245 SBOMs: []config.SBOM{ 246 { 247 Artifacts: "binary", 248 Cmd: "exit", 249 Args: []string{"${FOO}-{{ .foo }{{}}{"}, 250 }, 251 }, 252 Env: []string{ 253 "FOO=BAR", 254 }, 255 }), 256 }, 257 { 258 desc: "catalog source archives", 259 ctx: testctx.NewWithCfg(config.Project{ 260 SBOMs: []config.SBOM{ 261 {Artifacts: "source"}, 262 }, 263 }), 264 sbomPaths: []string{"artifact5.tar.gz.sbom"}, 265 sbomNames: []string{"artifact5.tar.gz.sbom"}, 266 }, 267 { 268 desc: "catalog archives", 269 ctx: testctx.NewWithCfg(config.Project{ 270 SBOMs: []config.SBOM{ 271 {Artifacts: "archive"}, 272 }, 273 }), 274 sbomPaths: []string{"artifact1.sbom", "artifact2.sbom"}, 275 sbomNames: []string{"artifact1.sbom", "artifact2.sbom"}, 276 }, 277 { 278 desc: "catalog linux packages", 279 ctx: testctx.NewWithCfg(config.Project{ 280 SBOMs: []config.SBOM{ 281 {Artifacts: "package"}, 282 }, 283 }), 284 sbomPaths: []string{"package1.deb.sbom"}, 285 sbomNames: []string{"package1.deb.sbom"}, 286 }, 287 { 288 desc: "catalog binaries", 289 ctx: testctx.NewWithCfg(config.Project{ 290 SBOMs: []config.SBOM{ 291 {Artifacts: "binary"}, 292 }, 293 }), 294 sbomPaths: []string{ 295 "artifact3-name_1.2.2_linux_amd64.sbom", 296 "artifact4-name_1.2.2_linux_amd64.sbom", 297 }, 298 sbomNames: []string{ 299 "artifact3-name_1.2.2_linux_amd64.sbom", 300 "artifact4-name_1.2.2_linux_amd64.sbom", 301 }, 302 }, 303 { 304 desc: "manual cataloging", 305 ctx: testctx.NewWithCfg(config.Project{ 306 SBOMs: []config.SBOM{ 307 { 308 Artifacts: "any", 309 Args: []string{ 310 "--output", 311 "spdx-json=$document0", 312 "artifact5.tar.gz", 313 }, 314 Documents: []string{ 315 "final.sbom", 316 }, 317 }, 318 }, 319 }), 320 sbomPaths: []string{"final.sbom"}, 321 sbomNames: []string{"final.sbom"}, 322 }, 323 { 324 desc: "multiple SBOM configs", 325 ctx: testctx.NewWithCfg(config.Project{ 326 Env: []string{ 327 "SBOM_SUFFIX=s2-ish", 328 }, 329 SBOMs: []config.SBOM{ 330 { 331 ID: "s1", 332 Artifacts: "binary", 333 }, 334 { 335 ID: "s2", 336 Artifacts: "archive", 337 Documents: []string{"{{ .ArtifactName }}.{{ .Env.SBOM_SUFFIX }}.sbom"}, 338 }, 339 }, 340 }), 341 sbomPaths: []string{ 342 "artifact1.s2-ish.sbom", 343 "artifact2.s2-ish.sbom", 344 "artifact3-name_1.2.2_linux_amd64.sbom", 345 "artifact4-name_1.2.2_linux_amd64.sbom", 346 }, 347 sbomNames: []string{ 348 "artifact1.s2-ish.sbom", 349 "artifact2.s2-ish.sbom", 350 "artifact3-name_1.2.2_linux_amd64.sbom", 351 "artifact4-name_1.2.2_linux_amd64.sbom", 352 }, 353 }, 354 { 355 desc: "catalog artifacts with filtered by ID", 356 ctx: testctx.NewWithCfg(config.Project{ 357 SBOMs: []config.SBOM{ 358 { 359 Artifacts: "binary", 360 IDs: []string{"foo"}, 361 }, 362 }, 363 }), 364 sbomPaths: []string{ 365 "artifact3-name_1.2.2_linux_amd64.sbom", 366 }, 367 sbomNames: []string{ 368 "artifact3-name_1.2.2_linux_amd64.sbom", 369 }, 370 }, 371 { 372 desc: "catalog binary artifacts with env in arguments", 373 ctx: testctx.NewWithCfg(config.Project{ 374 SBOMs: []config.SBOM{ 375 { 376 Artifacts: "binary", 377 Args: []string{ 378 "--output", 379 "spdx-json=$document", 380 "$artifact", 381 }, 382 Documents: []string{ 383 "{{ .ArtifactName }}.{{ .Env.TEST_USER }}.sbom", 384 }, 385 }, 386 }, 387 Env: []string{ 388 "TEST_USER=test-user-name", 389 }, 390 }), 391 sbomPaths: []string{ 392 "artifact3-name.test-user-name.sbom", 393 "artifact4.test-user-name.sbom", 394 }, 395 sbomNames: []string{ 396 "artifact3-name.test-user-name.sbom", 397 "artifact4.test-user-name.sbom", 398 }, 399 }, 400 { 401 desc: "cataloging 'any' artifacts fails", 402 ctx: testctx.NewWithCfg(config.Project{ 403 SBOMs: []config.SBOM{ 404 { 405 Artifacts: "any", 406 Cmd: "false", 407 }, 408 }, 409 }), 410 expectedErrMsg: "cataloging artifacts: false failed: exit status 1: ", 411 }, 412 { 413 desc: "catalog wrong command", 414 ctx: testctx.NewWithCfg(config.Project{ 415 SBOMs: []config.SBOM{ 416 {Args: []string{"$artifact", "--file", "$sbom", "--output", "spdx-json"}}, 417 }, 418 }), 419 expectedErrMsg: "cataloging artifacts: command did not write any files, check your configuration", 420 }, 421 { 422 desc: "no matches", 423 ctx: testctx.NewWithCfg(config.Project{ 424 SBOMs: []config.SBOM{ 425 {IDs: []string{"nopenopenope"}}, 426 }, 427 }), 428 }, 429 } 430 431 for _, test := range tests { 432 t.Run(test.desc, func(t *testing.T) { 433 testSBOMCataloging( 434 t, 435 test.ctx, 436 test.sbomPaths, 437 test.sbomNames, 438 test.expectedErrAs, 439 test.expectedErrMsg, 440 ) 441 }) 442 } 443 } 444 445 func testSBOMCataloging( 446 tb testing.TB, 447 ctx *context.Context, 448 sbomPaths, sbomNames []string, 449 expectedErrAs any, 450 expectedErrMsg string, 451 ) { 452 tb.Helper() 453 testlib.CheckPath(tb, "syft") 454 tmpdir := tb.TempDir() 455 456 ctx.Config.Dist = tmpdir 457 ctx.Version = "1.2.2" 458 459 // create some fake artifacts 460 artifacts := []string{"artifact1", "artifact2", "artifact3", "package1.deb"} 461 require.NoError(tb, os.Mkdir(filepath.Join(tmpdir, "linux_amd64"), os.ModePerm)) 462 for _, f := range artifacts { 463 file := filepath.Join(tmpdir, f) 464 require.NoError(tb, os.WriteFile(file, []byte("foo"), 0o644)) 465 } 466 require.NoError(tb, os.WriteFile(filepath.Join(tmpdir, "linux_amd64", "artifact4"), []byte("foo"), 0o644)) 467 artifacts = append(artifacts, "linux_amd64/artifact4") 468 require.NoError(tb, os.WriteFile(filepath.Join(tmpdir, "artifact5.tar.gz"), []byte("foo"), 0o644)) 469 artifacts = append(artifacts, "artifact5.tar.gz") 470 ctx.Artifacts.Add(&artifact.Artifact{ 471 Name: "artifact1", 472 Path: filepath.Join(tmpdir, "artifact1"), 473 Type: artifact.UploadableArchive, 474 Extra: map[string]interface{}{ 475 artifact.ExtraID: "foo", 476 }, 477 }) 478 ctx.Artifacts.Add(&artifact.Artifact{ 479 Name: "artifact2", 480 Path: filepath.Join(tmpdir, "artifact2"), 481 Type: artifact.UploadableArchive, 482 Extra: map[string]interface{}{ 483 artifact.ExtraID: "foo3", 484 }, 485 }) 486 ctx.Artifacts.Add(&artifact.Artifact{ 487 Name: "artifact3-name", 488 Path: filepath.Join(tmpdir, "artifact3"), 489 Goos: "linux", 490 Goarch: "amd64", 491 Type: artifact.UploadableBinary, 492 Extra: map[string]interface{}{ 493 artifact.ExtraID: "foo", 494 artifact.ExtraBinary: "artifact3-name", 495 }, 496 }) 497 ctx.Artifacts.Add(&artifact.Artifact{ 498 Name: "artifact4", 499 Path: filepath.Join(tmpdir, "linux_amd64", "artifact4"), 500 Goos: "linux", 501 Goarch: "amd64", 502 Type: artifact.Binary, 503 Extra: map[string]interface{}{ 504 artifact.ExtraID: "foo3", 505 artifact.ExtraBinary: "artifact4-name", 506 }, 507 }) 508 ctx.Artifacts.Add(&artifact.Artifact{ 509 Name: "artifact5.tar.gz", 510 Path: filepath.Join(tmpdir, "artifact5.tar.gz"), 511 Type: artifact.UploadableSourceArchive, 512 }) 513 ctx.Artifacts.Add(&artifact.Artifact{ 514 Name: "package1.deb", 515 Path: filepath.Join(tmpdir, "package1.deb"), 516 Type: artifact.LinuxPackage, 517 Extra: map[string]interface{}{ 518 artifact.ExtraID: "foo", 519 }, 520 }) 521 522 // configure the pipeline 523 require.NoError(tb, Pipe{}.Default(ctx)) 524 525 // run the pipeline 526 if expectedErrMsg != "" { 527 err := Pipe{}.Run(ctx) 528 require.ErrorContains(tb, err, expectedErrMsg) 529 return 530 } 531 if expectedErrAs != nil { 532 require.ErrorAs(tb, Pipe{}.Run(ctx), expectedErrAs) 533 return 534 } 535 536 require.NoError(tb, Pipe{}.Run(ctx)) 537 538 // ensure all artifacts have an ID 539 for _, arti := range ctx.Artifacts.Filter(artifact.ByType(artifact.SBOM)).List() { 540 require.NotEmptyf(tb, arti.ID(), ".Extra.ID on %s", arti.Path) 541 } 542 543 // verify that only the artifacts and the sboms are in the dist dir 544 gotFiles := []string{} 545 546 require.NoError(tb, filepath.Walk(tmpdir, 547 func(path string, info os.FileInfo, err error) error { 548 if err != nil { 549 return err 550 } 551 if info.IsDir() { 552 return nil 553 } 554 relPath, err := filepath.Rel(tmpdir, path) 555 if err != nil { 556 return err 557 } 558 gotFiles = append(gotFiles, relPath) 559 return nil 560 }), 561 ) 562 563 wantFiles := append(artifacts, sbomPaths...) 564 sort.Strings(wantFiles) 565 require.ElementsMatch(tb, wantFiles, gotFiles, "SBOM paths differ") 566 567 var sbomArtifacts []string 568 for _, sig := range ctx.Artifacts.Filter(artifact.ByType(artifact.SBOM)).List() { 569 sbomArtifacts = append(sbomArtifacts, sig.Name) 570 } 571 572 require.ElementsMatch(tb, sbomArtifacts, sbomNames, "SBOM names differ") 573 } 574 575 func Test_subprocessDistPath(t *testing.T) { 576 cwd, err := os.Getwd() 577 require.NoError(t, err) 578 579 tests := []struct { 580 name string 581 distDir string 582 pathRelativeToCwd string 583 expects string 584 }{ 585 { 586 name: "relative dist with anchor", 587 distDir: "./dist", 588 pathRelativeToCwd: "dist/my.sbom", 589 expects: "my.sbom", 590 }, 591 { 592 name: "relative dist without anchor", 593 distDir: "dist", 594 pathRelativeToCwd: "dist/my.sbom", 595 expects: "my.sbom", 596 }, 597 { 598 name: "relative dist with nested resource", 599 distDir: "dist", 600 pathRelativeToCwd: "dist/something/my.sbom", 601 expects: "something/my.sbom", 602 }, 603 { 604 name: "absolute dist with nested resource", 605 distDir: filepath.Join(cwd, "dist/"), 606 pathRelativeToCwd: "dist/something/my.sbom", 607 expects: "something/my.sbom", 608 }, 609 } 610 for _, test := range tests { 611 t.Run(test.name, func(t *testing.T) { 612 actual, err := subprocessDistPath(test.distDir, test.pathRelativeToCwd) 613 require.NoError(t, err) 614 assert.Equal(t, test.expects, actual) 615 }) 616 } 617 } 618 619 func Test_templateNames(t *testing.T) { 620 art := artifact.Artifact{ 621 Name: "name-it", 622 Path: "to/a/place", 623 Goos: "darwin", 624 Goarch: "amd64", 625 Type: artifact.Binary, 626 Extra: map[string]interface{}{ 627 artifact.ExtraID: "id-it", 628 "Binary": "binary-name", 629 }, 630 } 631 632 wd, err := os.Getwd() 633 require.NoError(t, err) 634 635 tests := []struct { 636 name string 637 dist string 638 version string 639 cfg config.SBOM 640 artifact artifact.Artifact 641 expectedValues map[string]string 642 expectedPaths []string 643 }{ 644 { 645 name: "default configuration", 646 artifact: art, 647 cfg: config.SBOM{}, 648 dist: "/somewhere/to/dist", 649 expectedPaths: []string{ 650 "/somewhere/to/dist/name-it.sbom", 651 }, 652 expectedValues: map[string]string{ 653 "artifact": "to/a/place", 654 "artifactID": "id-it", 655 "document": "/somewhere/to/dist/name-it.sbom", 656 "document0": "/somewhere/to/dist/name-it.sbom", 657 }, 658 }, 659 { 660 name: "default configuration + relative dist", 661 artifact: art, 662 cfg: config.SBOM{}, 663 dist: "somewhere/to/dist", 664 expectedPaths: []string{ 665 filepath.Join(wd, "somewhere/to/dist/name-it.sbom"), 666 }, 667 expectedValues: map[string]string{ 668 "artifact": "to/a/place", // note: this is always relative to ${dist} 669 "artifactID": "id-it", 670 "document": filepath.Join(wd, "somewhere/to/dist/name-it.sbom"), 671 "document0": filepath.Join(wd, "somewhere/to/dist/name-it.sbom"), 672 }, 673 }, 674 { 675 name: "custom document using $artifact", 676 // note: this configuration is probably a misconfiguration since it is placing SBOMs within each bin 677 // directory, however, it will behave as correctly as possible. 678 artifact: art, 679 cfg: config.SBOM{ 680 Documents: []string{ 681 // note: the artifact name is probably an incorrect value here since it can't express all attributes 682 // of the binary (os, arch, etc), so builds with multiple architectures will create SBOMs with the 683 // same name. 684 "${artifact}.cdx.sbom", 685 }, 686 }, 687 dist: "somewhere/to/dist", 688 expectedPaths: []string{ 689 filepath.Join(wd, "somewhere/to/dist/to/a/place.cdx.sbom"), 690 }, 691 expectedValues: map[string]string{ 692 "artifact": "to/a/place", 693 "artifactID": "id-it", 694 "document": filepath.Join(wd, "somewhere/to/dist/to/a/place.cdx.sbom"), 695 "document0": filepath.Join(wd, "somewhere/to/dist/to/a/place.cdx.sbom"), 696 }, 697 }, 698 { 699 name: "custom document using build vars", 700 artifact: art, 701 cfg: config.SBOM{ 702 Documents: []string{ 703 "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}.cdx.sbom", 704 }, 705 }, 706 version: "1.0.0", 707 dist: "somewhere/to/dist", 708 expectedPaths: []string{ 709 filepath.Join(wd, "somewhere/to/dist/binary-name_1.0.0_darwin_amd64.cdx.sbom"), 710 }, 711 expectedValues: map[string]string{ 712 "artifact": "to/a/place", 713 "artifactID": "id-it", 714 "document": filepath.Join(wd, "somewhere/to/dist/binary-name_1.0.0_darwin_amd64.cdx.sbom"), 715 "document0": filepath.Join(wd, "somewhere/to/dist/binary-name_1.0.0_darwin_amd64.cdx.sbom"), 716 }, 717 }, 718 { 719 name: "env vars with go templated options", 720 artifact: art, 721 cfg: config.SBOM{ 722 Documents: []string{ 723 "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}.cdx.sbom", 724 }, 725 Env: []string{ 726 "with-env-var=value", 727 "custom-os={{ .Os }}-unique", 728 "custom-arch={{ .Arch }}-unique", 729 }, 730 }, 731 version: "1.0.0", 732 dist: "somewhere/to/dist", 733 expectedPaths: []string{ 734 filepath.Join(wd, "somewhere/to/dist/binary-name_1.0.0_darwin_amd64.cdx.sbom"), 735 }, 736 expectedValues: map[string]string{ 737 "artifact": "to/a/place", 738 "artifactID": "id-it", 739 "with-env-var": "value", 740 "custom-os": "darwin-unique", 741 "custom-arch": "amd64-unique", 742 "document": filepath.Join(wd, "somewhere/to/dist/binary-name_1.0.0_darwin_amd64.cdx.sbom"), 743 "document0": filepath.Join(wd, "somewhere/to/dist/binary-name_1.0.0_darwin_amd64.cdx.sbom"), 744 }, 745 }, 746 } 747 for _, tt := range tests { 748 t.Run(tt.name, func(t *testing.T) { 749 ctx := testctx.NewWithCfg(config.Project{ 750 Dist: tt.dist, 751 }, testctx.WithVersion(tt.version)) 752 753 cfg := tt.cfg 754 require.NoError(t, setConfigDefaults(&cfg)) 755 756 var inputArgs []string 757 var expectedArgs []string 758 for key, value := range tt.expectedValues { 759 inputArgs = append(inputArgs, fmt.Sprintf("${%s}", key)) 760 expectedArgs = append(expectedArgs, value) 761 } 762 cfg.Args = inputArgs 763 764 actualArgs, actualEnvs, actualPaths, err := applyTemplate(ctx, cfg, &tt.artifact) 765 require.NoError(t, err) 766 767 assert.Equal(t, tt.expectedPaths, actualPaths, "paths differ") 768 769 assert.Equal(t, expectedArgs, actualArgs, "arguments differ") 770 771 actualEnv := make(map[string]string) 772 for _, str := range actualEnvs { 773 k, v, ok := strings.Cut(str, "=") 774 require.True(t, ok) 775 actualEnv[k] = v 776 } 777 778 for k, v := range tt.expectedValues { 779 assert.Equal(t, v, actualEnv[k]) 780 } 781 }) 782 } 783 } 784 785 func TestDependencies(t *testing.T) { 786 ctx := testctx.NewWithCfg(config.Project{ 787 SBOMs: []config.SBOM{ 788 {Cmd: "syft"}, 789 {Cmd: "foobar"}, 790 }, 791 }) 792 require.Equal(t, []string{"syft", "foobar"}, Pipe{}.Dependencies(ctx)) 793 }