package cli import ( "os" "strings" "testing" "github.com/anchore/stereoscope/pkg/imagetest" ) // We have schema validation mechanims in schema/cyclonedx/ // This test allows us to double check that validation against the cyclonedx-cli tool func TestValidCycloneDX(t *testing.T) { imageFixture := func(t *testing.T) string { fixtureImageName := "image-pkg-coverage" imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName) tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName) return "docker-archive:" + tarPath } // TODO update image to exercise entire cyclonedx schema tests := []struct { name string subcommand string args []string fixture func(*testing.T) string assertions []traitAssertion }{ { name: "validate cyclonedx output", subcommand: "packages", args: []string{"-o", "cyclonedx-json"}, fixture: imageFixture, assertions: []traitAssertion{ assertSuccessfulReturnCode, assertValidCycloneDX, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { fixtureRef := test.fixture(t) args := []string{ test.subcommand, fixtureRef, "-q", } for _, a := range test.args { args = append(args, a) } cmd, stdout, stderr := runSyft(t, nil, args...) for _, traitFn := range test.assertions { traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode()) } if t.Failed() { t.Log("STDOUT:\n", stdout) t.Log("STDERR:\n", stderr) t.Log("COMMAND:", strings.Join(cmd.Args, " ")) } validateCycloneDXJSON(t, stdout) }) } } func assertValidCycloneDX(tb testing.TB, stdout, stderr string, rc int) { tb.Helper() f, err := os.CreateTemp("", "tmpfile-") if err != nil { tb.Fatal(err) } // close and remove the temporary file at the end of the program defer f.Close() defer os.Remove(f.Name()) data := []byte(stdout) if _, err := f.Write(data); err != nil { tb.Fatal(err) } args := []string{ "validate", "--input-format", "json", "--input-version", "v1_4", "--input-file", "/sbom", } cmd, stdout, stderr := runCycloneDXInDocker(tb, nil, "cyclonedx/cyclonedx-cli", f, args...) if cmd.ProcessState.ExitCode() != 0 { tb.Errorf("expected no validation failures for cyclonedx-cli but got rc=%d", rc) } if tb.Failed() { tb.Log("STDOUT:\n", stdout) tb.Log("STDERR:\n", stderr) tb.Log("COMMAND:", strings.Join(cmd.Args, " ")) } } // validate --input-format json --input-version v1_4 --input-file bom.json func validateCycloneDXJSON(t *testing.T, stdout string) { f, err := os.CreateTemp("", "tmpfile-") if err != nil { t.Fatal(err) } // close and remove the temporary file at the end of the program defer f.Close() defer os.Remove(f.Name()) data := []byte(stdout) if _, err := f.Write(data); err != nil { t.Fatal(err) } args := []string{ "validate", "--input-format", "json", "--input-version", "v1_4", "--input-file", "/sbom", } cmd, stdout, stderr := runCycloneDXInDocker(t, nil, "cyclonedx/cyclonedx-cli", f, args...) if strings.Contains(stdout, "BOM is not valid") { t.Errorf("expected no validation failures for cyclonedx-cli but found invalid BOM") } if t.Failed() { t.Log("STDOUT:\n", stdout) t.Log("STDERR:\n", stderr) t.Log("COMMAND:", strings.Join(cmd.Args, " ")) } }