github.com/google/osv-scalibr@v0.4.1/binary/proto/vex_test.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package proto_test
    16  
    17  import (
    18  	"errors"
    19  	"testing"
    20  
    21  	"github.com/google/go-cmp/cmp"
    22  	"github.com/google/osv-scalibr/binary/proto"
    23  	"github.com/google/osv-scalibr/inventory/vex"
    24  	"google.golang.org/protobuf/testing/protocmp"
    25  
    26  	spb "github.com/google/osv-scalibr/binary/proto/scan_result_go_proto"
    27  )
    28  
    29  // --- Struct to Proto
    30  
    31  func TestPackageVEXToProto(t *testing.T) {
    32  	testCases := []struct {
    33  		desc    string
    34  		v       *vex.PackageExploitabilitySignal
    35  		want    *spb.PackageExploitabilitySignal
    36  		wantErr error
    37  	}{
    38  		{
    39  			desc: "nil",
    40  			v:    nil,
    41  			want: nil,
    42  		},
    43  		{
    44  			desc: "matches_specific_vulns",
    45  			v: &vex.PackageExploitabilitySignal{
    46  				Plugin:        "some-plugin",
    47  				Justification: vex.ComponentNotPresent,
    48  				VulnIdentifiers: []string{
    49  					"CVE-1234",
    50  					"CVE-5678",
    51  				},
    52  			},
    53  			want: &spb.PackageExploitabilitySignal{
    54  				Plugin:        "some-plugin",
    55  				Justification: spb.VexJustification_COMPONENT_NOT_PRESENT,
    56  				VulnFilter: &spb.PackageExploitabilitySignal_VulnIdentifiers{
    57  					VulnIdentifiers: &spb.VulnIdentifiers{
    58  						Identifiers: []string{
    59  							"CVE-1234",
    60  							"CVE-5678",
    61  						},
    62  					},
    63  				},
    64  			},
    65  		},
    66  		{
    67  			desc: "matches_all_vulns",
    68  			v: &vex.PackageExploitabilitySignal{
    69  				Plugin:          "some-plugin",
    70  				Justification:   vex.ComponentNotPresent,
    71  				MatchesAllVulns: true,
    72  			},
    73  			want: &spb.PackageExploitabilitySignal{
    74  				Plugin:        "some-plugin",
    75  				Justification: spb.VexJustification_COMPONENT_NOT_PRESENT,
    76  				VulnFilter: &spb.PackageExploitabilitySignal_MatchesAllVulns{
    77  					MatchesAllVulns: true,
    78  				},
    79  			},
    80  		},
    81  		{
    82  			desc: "both_vuln_identifiers_and_matches_all_vulns_set",
    83  			v: &vex.PackageExploitabilitySignal{
    84  				Plugin:          "some-plugin",
    85  				Justification:   vex.ComponentNotPresent,
    86  				VulnIdentifiers: []string{"CVE-1234"},
    87  				MatchesAllVulns: true,
    88  			},
    89  			wantErr: proto.ErrVulnIdentifiersAndMatchsAllSet,
    90  		},
    91  	}
    92  
    93  	for _, tc := range testCases {
    94  		t.Run(tc.desc, func(t *testing.T) {
    95  			got, err := proto.PackageVEXToProto(tc.v)
    96  			if !errors.Is(err, tc.wantErr) {
    97  				t.Errorf("PackageVEXToProto(%v) returned error %v, want error %v", tc.v, err, tc.wantErr)
    98  			}
    99  			if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" {
   100  				t.Fatalf("PackageVEXToProto(%v) returned diff (-want +got):\n%s", tc.v, diff)
   101  			}
   102  
   103  			// No need to test the reverse conversion if the result is nil.
   104  			if got == nil && tc.v != nil {
   105  				return
   106  			}
   107  
   108  			// Test the reverse conversion for completeness.
   109  			gotPB, err := proto.PackageVEXToStruct(got)
   110  			if err != nil {
   111  				t.Fatalf("PackageVEXToStruct(%v) returned error %v, want nil", got, err)
   112  			}
   113  			if diff := cmp.Diff(tc.v, gotPB, protocmp.Transform()); diff != "" {
   114  				t.Fatalf("PackageVEXToStruct(%v) returned diff (-want +got):\n%s", got, diff)
   115  			}
   116  		})
   117  	}
   118  }
   119  
   120  func TestFindingVEXToProto(t *testing.T) {
   121  	testCases := []struct {
   122  		desc string
   123  		v    *vex.FindingExploitabilitySignal
   124  		want *spb.FindingExploitabilitySignal
   125  	}{
   126  		{
   127  			desc: "nil",
   128  			v:    nil,
   129  			want: nil,
   130  		},
   131  		{
   132  			desc: "success",
   133  			v: &vex.FindingExploitabilitySignal{
   134  				Plugin:        "some-plugin",
   135  				Justification: vex.ComponentNotPresent,
   136  			},
   137  			want: &spb.FindingExploitabilitySignal{
   138  				Plugin:        "some-plugin",
   139  				Justification: spb.VexJustification_COMPONENT_NOT_PRESENT,
   140  			},
   141  		},
   142  	}
   143  
   144  	for _, tc := range testCases {
   145  		t.Run(tc.desc, func(t *testing.T) {
   146  			got := proto.FindingVEXToProto(tc.v)
   147  			if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" {
   148  				t.Fatalf("FindingVEXToProto(%v) returned diff (-want +got):\n%s", tc.v, diff)
   149  			}
   150  
   151  			// Test the reverse conversion for completeness.
   152  			gotPB := proto.FindingVEXToStruct(got)
   153  			if diff := cmp.Diff(tc.v, gotPB, protocmp.Transform()); diff != "" {
   154  				t.Fatalf("FindingVEXToStruct(%v) returned diff (-want +got):\n%s", got, diff)
   155  			}
   156  		})
   157  	}
   158  }
   159  
   160  // --- Proto to Struct
   161  
   162  func TestPackageVEXToStruct(t *testing.T) {
   163  	testCases := []struct {
   164  		desc    string
   165  		v       *spb.PackageExploitabilitySignal
   166  		want    *vex.PackageExploitabilitySignal
   167  		wantErr error
   168  	}{
   169  		{
   170  			desc: "nil",
   171  			v:    nil,
   172  			want: nil,
   173  		},
   174  		{
   175  			desc: "matches_specific_vulns",
   176  			v: &spb.PackageExploitabilitySignal{
   177  				Plugin:        "some-plugin",
   178  				Justification: spb.VexJustification_COMPONENT_NOT_PRESENT,
   179  				VulnFilter: &spb.PackageExploitabilitySignal_VulnIdentifiers{
   180  					VulnIdentifiers: &spb.VulnIdentifiers{
   181  						Identifiers: []string{
   182  							"CVE-1234",
   183  							"CVE-5678",
   184  						},
   185  					},
   186  				},
   187  			},
   188  			want: &vex.PackageExploitabilitySignal{
   189  				Plugin:        "some-plugin",
   190  				Justification: vex.ComponentNotPresent,
   191  				VulnIdentifiers: []string{
   192  					"CVE-1234",
   193  					"CVE-5678",
   194  				},
   195  			},
   196  		},
   197  		{
   198  			desc: "matches_all_vulns",
   199  			v: &spb.PackageExploitabilitySignal{
   200  				Plugin:        "some-plugin",
   201  				Justification: spb.VexJustification_COMPONENT_NOT_PRESENT,
   202  				VulnFilter: &spb.PackageExploitabilitySignal_MatchesAllVulns{
   203  					MatchesAllVulns: true,
   204  				},
   205  			},
   206  			want: &vex.PackageExploitabilitySignal{
   207  				Plugin:          "some-plugin",
   208  				Justification:   vex.ComponentNotPresent,
   209  				MatchesAllVulns: true,
   210  			},
   211  		},
   212  	}
   213  
   214  	for _, tc := range testCases {
   215  		t.Run(tc.desc, func(t *testing.T) {
   216  			got, err := proto.PackageVEXToStruct(tc.v)
   217  			if !errors.Is(err, tc.wantErr) {
   218  				t.Errorf("PackageVEXToStruct(%v) returned error %v, want error %v", tc.v, err, tc.wantErr)
   219  			}
   220  			if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" {
   221  				t.Fatalf("PackageVEXToStruct(%v) returned diff (-want +got):\n%s", tc.v, diff)
   222  			}
   223  
   224  			// No need to test the reverse conversion if the result is nil.
   225  			if got == nil && tc.v != nil {
   226  				return
   227  			}
   228  
   229  			// Test the reverse conversion for completeness.
   230  			gotPB, err := proto.PackageVEXToProto(got)
   231  			if err != nil {
   232  				t.Fatalf("PackageVEXToProto(%v) returned error %v, want nil", got, err)
   233  			}
   234  			if diff := cmp.Diff(tc.v, gotPB, protocmp.Transform()); diff != "" {
   235  				t.Fatalf("PackageVEXToProto(%v) returned diff (-want +got):\n%s", got, diff)
   236  			}
   237  		})
   238  	}
   239  }
   240  
   241  func TestFindingVEXToStruct(t *testing.T) {
   242  	testCases := []struct {
   243  		desc string
   244  		v    *spb.FindingExploitabilitySignal
   245  		want *vex.FindingExploitabilitySignal
   246  	}{
   247  		{
   248  			desc: "nil",
   249  			v:    nil,
   250  			want: nil,
   251  		},
   252  		{
   253  			desc: "success",
   254  			v: &spb.FindingExploitabilitySignal{
   255  				Plugin:        "some-plugin",
   256  				Justification: spb.VexJustification_COMPONENT_NOT_PRESENT,
   257  			},
   258  			want: &vex.FindingExploitabilitySignal{
   259  				Plugin:        "some-plugin",
   260  				Justification: vex.ComponentNotPresent,
   261  			},
   262  		},
   263  	}
   264  
   265  	for _, tc := range testCases {
   266  		t.Run(tc.desc, func(t *testing.T) {
   267  			got := proto.FindingVEXToStruct(tc.v)
   268  			if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" {
   269  				t.Fatalf("FindingVEXToStruct(%v) returned diff (-want +got):\n%s", tc.v, diff)
   270  			}
   271  
   272  			// Test the reverse conversion for completeness.
   273  			gotPB := proto.FindingVEXToProto(got)
   274  			if diff := cmp.Diff(tc.v, gotPB, protocmp.Transform()); diff != "" {
   275  				t.Fatalf("FindingVEXToProto(%v) returned diff (-want +got):\n%s", got, diff)
   276  			}
   277  		})
   278  	}
   279  }