github.com/anchore/syft@v1.38.2/syft/format/cpes/decoder_test.go (about)

     1  package cpes
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  
     7  	"github.com/google/go-cmp/cmp"
     8  	"github.com/google/go-cmp/cmp/cmpopts"
     9  	"github.com/stretchr/testify/require"
    10  
    11  	"github.com/anchore/syft/syft/cpe"
    12  	"github.com/anchore/syft/syft/file"
    13  	"github.com/anchore/syft/syft/pkg"
    14  	"github.com/anchore/syft/syft/sbom"
    15  )
    16  
    17  func TestDecoder_Decode(t *testing.T) {
    18  	tests := []struct {
    19  		name      string
    20  		userInput string
    21  		sbom      *sbom.SBOM
    22  	}{
    23  		{
    24  			name:      "takes a single cpe",
    25  			userInput: "cpe:/a:apache:log4j:2.14.1",
    26  			sbom: &sbom.SBOM{
    27  				Artifacts: sbom.Artifacts{
    28  					Packages: pkg.NewCollection(pkg.Package{
    29  						Name:    "log4j",
    30  						Version: "2.14.1",
    31  						CPEs: []cpe.CPE{
    32  							cpe.Must("cpe:/a:apache:log4j:2.14.1", ""),
    33  						},
    34  					}),
    35  				},
    36  			},
    37  		},
    38  		{
    39  			name: "takes multiple cpes",
    40  			userInput: `cpe:/a:apache:log4j:2.14.1
    41  						cpe:2.3:a:f5:nginx:*:*:*:*:*:*:*:*;
    42  						cpe:2.3:a:f5:nginx:0.5.2:*:*:*:*:*:*:*;
    43  						cpe:2.3:a:f5:nginx:0.5.3:*:*:*:*:*:*:*;`,
    44  			sbom: &sbom.SBOM{
    45  				Artifacts: sbom.Artifacts{
    46  					Packages: pkg.NewCollection(
    47  						pkg.Package{
    48  							Name:    "log4j",
    49  							Version: "2.14.1",
    50  							CPEs: []cpe.CPE{
    51  								cpe.Must("cpe:/a:apache:log4j:2.14.1", ""),
    52  							},
    53  						},
    54  						pkg.Package{
    55  							Name:    "nginx",
    56  							Version: "",
    57  							CPEs: []cpe.CPE{
    58  								cpe.Must("cpe:2.3:a:f5:nginx:*:*:*:*:*:*:*:*;", ""),
    59  							},
    60  						},
    61  						pkg.Package{
    62  							Name:    "nginx",
    63  							Version: "0.5.2",
    64  							CPEs: []cpe.CPE{
    65  								cpe.Must("cpe:2.3:a:f5:nginx:0.5.2:*:*:*:*:*:*:*;", ""),
    66  							},
    67  						},
    68  						pkg.Package{
    69  							Name:    "nginx",
    70  							Version: "0.5.3",
    71  							CPEs: []cpe.CPE{
    72  								cpe.Must("cpe:2.3:a:f5:nginx:0.5.3:*:*:*:*:*:*:*;", ""),
    73  							},
    74  						},
    75  					),
    76  				},
    77  			},
    78  		},
    79  		{
    80  			name:      "takes cpe with no version",
    81  			userInput: "cpe:/a:apache:log4j",
    82  			sbom: &sbom.SBOM{
    83  				Artifacts: sbom.Artifacts{
    84  					Packages: pkg.NewCollection(pkg.Package{
    85  						Name: "log4j",
    86  						CPEs: []cpe.CPE{
    87  							cpe.Must("cpe:/a:apache:log4j", ""),
    88  						},
    89  					}),
    90  				},
    91  			},
    92  		},
    93  		{
    94  			name:      "takes CPE 2.3 format",
    95  			userInput: "cpe:2.3:a:apache:log4j:2.14.1:*:*:*:*:*:*:*",
    96  			sbom: &sbom.SBOM{
    97  				Artifacts: sbom.Artifacts{
    98  					Packages: pkg.NewCollection(pkg.Package{
    99  						Name:    "log4j",
   100  						Version: "2.14.1",
   101  						CPEs: []cpe.CPE{
   102  							cpe.Must("cpe:2.3:a:apache:log4j:2.14.1:*:*:*:*:*:*:*", ""),
   103  						},
   104  					}),
   105  				},
   106  			},
   107  		},
   108  		{
   109  			name:      "deduces target SW from CPE - known target_sw",
   110  			userInput: "cpe:2.3:a:amazon:opensearch:*:*:*:*:*:ruby:*:*",
   111  			sbom: &sbom.SBOM{
   112  				Artifacts: sbom.Artifacts{
   113  					Packages: pkg.NewCollection(pkg.Package{
   114  						Name: "opensearch",
   115  						Type: pkg.GemPkg,
   116  						CPEs: []cpe.CPE{
   117  							cpe.Must("cpe:2.3:a:amazon:opensearch:*:*:*:*:*:ruby:*:*", ""),
   118  						},
   119  					}),
   120  				},
   121  			},
   122  		},
   123  		{
   124  			name:      "handles unknown target_sw CPE field",
   125  			userInput: "cpe:2.3:a:amazon:opensearch:*:*:*:*:*:loremipsum:*:*",
   126  			sbom: &sbom.SBOM{
   127  				Artifacts: sbom.Artifacts{
   128  					Packages: pkg.NewCollection(pkg.Package{
   129  						Name: "opensearch",
   130  						Type: "",
   131  						CPEs: []cpe.CPE{
   132  							cpe.Must("cpe:2.3:a:amazon:opensearch:*:*:*:*:*:loremipsum:*:*", ""),
   133  						},
   134  					}),
   135  				},
   136  			},
   137  		},
   138  		{
   139  			name:      "invalid prefix",
   140  			userInput: "dir:test-fixtures/cpe",
   141  			sbom: &sbom.SBOM{
   142  				Artifacts: sbom.Artifacts{
   143  					Packages: pkg.NewCollection(),
   144  				},
   145  			},
   146  		},
   147  	}
   148  
   149  	syftPkgOpts := []cmp.Option{
   150  		cmpopts.IgnoreFields(pkg.Package{}, "id", "Language"),
   151  		cmpopts.IgnoreUnexported(pkg.Package{}, file.LocationSet{}, pkg.LicenseSet{}),
   152  	}
   153  
   154  	for _, tc := range tests {
   155  		t.Run(tc.name, func(t *testing.T) {
   156  			dec := NewFormatDecoder()
   157  
   158  			decodedSBOM, _, _, err := dec.Decode(strings.NewReader(tc.userInput))
   159  			require.NoError(t, err)
   160  
   161  			gotSyftPkgs := decodedSBOM.Artifacts.Packages.Sorted()
   162  			wantSyftPkgs := tc.sbom.Artifacts.Packages.Sorted()
   163  			require.Equal(t, len(gotSyftPkgs), len(wantSyftPkgs))
   164  			for idx, wantPkg := range wantSyftPkgs {
   165  				if d := cmp.Diff(wantPkg, gotSyftPkgs[idx], syftPkgOpts...); d != "" {
   166  					t.Errorf("unexpected Syft Package (-want +got):\n%s", d)
   167  				}
   168  			}
   169  		})
   170  	}
   171  }