github.com/khulnasoft-lab/tunnel-db@v0.0.0-20231117205118-74e1113bd007/pkg/vulnsrc/redhat-oval/parse.go (about)

     1  package redhatoval
     2  
     3  import (
     4  	"encoding/json"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"golang.org/x/xerrors"
     9  )
    10  
    11  type rpmInfoTest struct {
    12  	Name           string
    13  	SignatureKeyID signatureKeyID
    14  	FixedVersion   string
    15  	Arch           string
    16  }
    17  
    18  func unmarshalJSONFile(v interface{}, fileName string) error {
    19  	f, err := os.Open(fileName)
    20  	if err != nil {
    21  		return xerrors.Errorf("unable to open a file (%s): %w", fileName, err)
    22  	}
    23  	defer f.Close()
    24  
    25  	if err = json.NewDecoder(f).Decode(v); err != nil {
    26  		return xerrors.Errorf("failed to decode Red Hat OVAL JSON: %w", err)
    27  	}
    28  	return nil
    29  }
    30  
    31  func parseObjects(dir string) (map[string]string, error) {
    32  	var objects ovalObjects
    33  	if err := unmarshalJSONFile(&objects, filepath.Join(dir, "objects", "objects.json")); err != nil {
    34  		return nil, xerrors.Errorf("failed to unmarshal objects: %w", err)
    35  	}
    36  	objs := map[string]string{}
    37  	for _, obj := range objects.RpminfoObjects {
    38  		objs[obj.ID] = obj.Name
    39  	}
    40  	return objs, nil
    41  }
    42  
    43  func parseStates(dir string) (map[string]rpminfoState, error) {
    44  	var ss ovalStates
    45  	if err := unmarshalJSONFile(&ss, filepath.Join(dir, "states", "states.json")); err != nil {
    46  		return nil, xerrors.Errorf("failed to unmarshal states: %w", err)
    47  	}
    48  
    49  	states := map[string]rpminfoState{}
    50  	for _, state := range ss.RpminfoState {
    51  		states[state.ID] = state
    52  	}
    53  	return states, nil
    54  }
    55  
    56  func parseTests(dir string) (map[string]rpmInfoTest, error) {
    57  	objects, err := parseObjects(dir)
    58  	if err != nil {
    59  		return nil, xerrors.Errorf("failed to parse objects: %w", err)
    60  	}
    61  
    62  	states, err := parseStates(dir)
    63  	if err != nil {
    64  		return nil, xerrors.Errorf("failed to parse states: %w", err)
    65  	}
    66  
    67  	var tt ovalTests
    68  	if err := unmarshalJSONFile(&tt, filepath.Join(dir, "tests", "tests.json")); err != nil {
    69  		return nil, xerrors.Errorf("failed to unmarshal states: %w", err)
    70  	}
    71  
    72  	tests := map[string]rpmInfoTest{}
    73  	for _, test := range tt.RpminfoTests {
    74  		// test.Check should be "at least one"
    75  		if test.Check != "at least one" {
    76  			continue
    77  		}
    78  
    79  		t, err := followTestRefs(test, objects, states)
    80  		if err != nil {
    81  			return nil, xerrors.Errorf("unable to follow test refs: %w", err)
    82  		}
    83  		tests[test.ID] = t
    84  	}
    85  	return tests, nil
    86  }
    87  
    88  func followTestRefs(test rpminfoTest, objects map[string]string, states map[string]rpminfoState) (rpmInfoTest, error) {
    89  	var t rpmInfoTest
    90  
    91  	// Follow object ref
    92  	if test.Object.ObjectRef == "" {
    93  		return t, nil
    94  	}
    95  
    96  	pkgName, ok := objects[test.Object.ObjectRef]
    97  	if !ok {
    98  		return t, xerrors.Errorf("invalid tests data, can't find object ref: %s, test ref: %s",
    99  			test.Object.ObjectRef, test.ID)
   100  	}
   101  	t.Name = pkgName
   102  
   103  	// Follow state ref
   104  	if test.State.StateRef == "" {
   105  		return t, nil
   106  	}
   107  
   108  	state, ok := states[test.State.StateRef]
   109  	if !ok {
   110  		return t, xerrors.Errorf("invalid tests data, can't find ovalstate ref %s, test ref: %s",
   111  			test.State.StateRef, test.ID)
   112  	}
   113  
   114  	t.SignatureKeyID = state.SignatureKeyID
   115  
   116  	if state.Arch.Datatype == "string" && (state.Arch.Operation == "pattern match" || state.Arch.Operation == "equals") {
   117  		t.Arch = state.Arch.Text
   118  	}
   119  
   120  	if state.Evr.Datatype == "evr_string" && state.Evr.Operation == "less than" {
   121  		t.FixedVersion = state.Evr.Text
   122  	}
   123  
   124  	return t, nil
   125  }