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 }