src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

index.go (2513B)


      1 // Copyright 2023 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package client
      6 
      7 import (
      8 	"encoding/json"
      9 	"fmt"
     10 	"io/fs"
     11 	"os"
     12 	"path/filepath"
     13 
     14 	"golang.org/x/vuln/internal/osv"
     15 	isem "golang.org/x/vuln/internal/semver"
     16 )
     17 
     18 // indexFromDir returns a raw index created from a directory
     19 // containing OSV entries.
     20 // It skips any non-JSON files but errors if any of the JSON files
     21 // cannot be unmarshaled into OSV, or have a filename other than <ID>.json.
     22 func indexFromDir(dir string) (map[string][]byte, error) {
     23 	idx := newIndex()
     24 	f := os.DirFS(dir)
     25 
     26 	if err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
     27 		fname := d.Name()
     28 		ext := filepath.Ext(fname)
     29 		switch {
     30 		case err != nil:
     31 			return err
     32 		case d.IsDir():
     33 			return nil
     34 		case ext != ".json":
     35 			return nil
     36 		}
     37 
     38 		b, err := fs.ReadFile(f, d.Name())
     39 		if err != nil {
     40 			return err
     41 		}
     42 		var entry osv.Entry
     43 		if err := json.Unmarshal(b, &entry); err != nil {
     44 			return err
     45 		}
     46 		if fname != entry.ID+".json" {
     47 			return fmt.Errorf("OSV entries must have filename of the form <ID>.json, got %s", fname)
     48 		}
     49 
     50 		idx.add(&entry)
     51 		return nil
     52 	}); err != nil {
     53 		return nil, err
     54 	}
     55 
     56 	return idx.raw()
     57 }
     58 
     59 func indexFromEntries(entries []*osv.Entry) (map[string][]byte, error) {
     60 	idx := newIndex()
     61 
     62 	for _, entry := range entries {
     63 		idx.add(entry)
     64 	}
     65 
     66 	return idx.raw()
     67 }
     68 
     69 type index struct {
     70 	db      *dbMeta
     71 	modules modulesIndex
     72 }
     73 
     74 func newIndex() *index {
     75 	return &index{
     76 		db:      &dbMeta{},
     77 		modules: make(map[string]*moduleMeta),
     78 	}
     79 }
     80 
     81 func (i *index) add(entry *osv.Entry) {
     82 	// Add to db index.
     83 	if entry.Modified.After(i.db.Modified) {
     84 		i.db.Modified = entry.Modified
     85 	}
     86 	// Add to modules index.
     87 	for _, affected := range entry.Affected {
     88 		modulePath := affected.Module.Path
     89 		if _, ok := i.modules[modulePath]; !ok {
     90 			i.modules[modulePath] = &moduleMeta{
     91 				Path:  modulePath,
     92 				Vulns: []moduleVuln{},
     93 			}
     94 		}
     95 		module := i.modules[modulePath]
     96 		module.Vulns = append(module.Vulns, moduleVuln{
     97 			ID:       entry.ID,
     98 			Modified: entry.Modified,
     99 			Fixed:    isem.NonSupersededFix(affected.Ranges),
    100 		})
    101 	}
    102 }
    103 
    104 func (i *index) raw() (map[string][]byte, error) {
    105 	data := make(map[string][]byte)
    106 
    107 	b, err := json.Marshal(i.db)
    108 	if err != nil {
    109 		return nil, err
    110 	}
    111 	data[dbEndpoint] = b
    112 
    113 	b, err = json.Marshal(i.modules)
    114 	if err != nil {
    115 		return nil, err
    116 	}
    117 	data[modulesEndpoint] = b
    118 
    119 	return data, nil
    120 }