github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/test/cli/cyclonedx_valid_test.go (about)

     1  package cli
     2  
     3  import (
     4  	"os"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/anchore/stereoscope/pkg/imagetest"
     9  )
    10  
    11  // We have schema validation mechanims in schema/cyclonedx/
    12  // This test allows us to double check that validation against the cyclonedx-cli tool
    13  func TestValidCycloneDX(t *testing.T) {
    14  	imageFixture := func(t *testing.T) string {
    15  		fixtureImageName := "image-pkg-coverage"
    16  		imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName)
    17  		tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName)
    18  		return "docker-archive:" + tarPath
    19  	}
    20  
    21  	// TODO update image to exercise entire cyclonedx schema
    22  	tests := []struct {
    23  		name       string
    24  		subcommand string
    25  		args       []string
    26  		fixture    func(*testing.T) string
    27  		assertions []traitAssertion
    28  	}{
    29  		{
    30  			name:       "validate cyclonedx output",
    31  			subcommand: "packages",
    32  			args:       []string{"-o", "cyclonedx-json"},
    33  			fixture:    imageFixture,
    34  			assertions: []traitAssertion{
    35  				assertSuccessfulReturnCode,
    36  				assertValidCycloneDX,
    37  			},
    38  		},
    39  	}
    40  
    41  	for _, test := range tests {
    42  		t.Run(test.name, func(t *testing.T) {
    43  			fixtureRef := test.fixture(t)
    44  			args := []string{
    45  				test.subcommand, fixtureRef, "-q",
    46  			}
    47  			args = append(args, test.args...)
    48  
    49  			cmd, stdout, stderr := runSyft(t, nil, args...)
    50  			for _, traitFn := range test.assertions {
    51  				traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
    52  			}
    53  			logOutputOnFailure(t, cmd, stdout, stderr)
    54  
    55  			validateCycloneDXJSON(t, stdout)
    56  		})
    57  	}
    58  }
    59  
    60  func assertValidCycloneDX(tb testing.TB, stdout, stderr string, rc int) {
    61  	tb.Helper()
    62  	f, err := os.CreateTemp("", "tmpfile-")
    63  	if err != nil {
    64  		tb.Fatal(err)
    65  	}
    66  
    67  	// close and remove the temporary file at the end of the program
    68  	defer f.Close()
    69  	defer os.Remove(f.Name())
    70  
    71  	data := []byte(stdout)
    72  
    73  	if _, err := f.Write(data); err != nil {
    74  		tb.Fatal(err)
    75  	}
    76  
    77  	args := []string{
    78  		"validate",
    79  		"--input-format",
    80  		"json",
    81  		"--input-version",
    82  		"v1_4",
    83  		"--input-file",
    84  		"/sbom",
    85  	}
    86  
    87  	cmd, stdout, stderr := runCycloneDXInDocker(tb, nil, "cyclonedx/cyclonedx-cli", f, args...)
    88  	if cmd.ProcessState.ExitCode() != 0 {
    89  		tb.Errorf("expected no validation failures for cyclonedx-cli but got rc=%d", rc)
    90  	}
    91  
    92  	logOutputOnFailure(tb, cmd, stdout, stderr)
    93  }
    94  
    95  // validate --input-format json --input-version v1_4 --input-file bom.json
    96  func validateCycloneDXJSON(t *testing.T, stdout string) {
    97  	f, err := os.CreateTemp("", "tmpfile-")
    98  	if err != nil {
    99  		t.Fatal(err)
   100  	}
   101  
   102  	// close and remove the temporary file at the end of the program
   103  	defer f.Close()
   104  	defer os.Remove(f.Name())
   105  
   106  	data := []byte(stdout)
   107  
   108  	if _, err := f.Write(data); err != nil {
   109  		t.Fatal(err)
   110  	}
   111  
   112  	args := []string{
   113  		"validate",
   114  		"--input-format",
   115  		"json",
   116  		"--input-version",
   117  		"v1_4",
   118  		"--input-file",
   119  		"/sbom",
   120  	}
   121  
   122  	cmd, stdout, stderr := runCycloneDXInDocker(t, nil, "cyclonedx/cyclonedx-cli", f, args...)
   123  	if strings.Contains(stdout, "BOM is not valid") {
   124  		t.Errorf("expected no validation failures for cyclonedx-cli but found invalid BOM")
   125  	}
   126  
   127  	logOutputOnFailure(t, cmd, stdout, stderr)
   128  }