File: index.go

package info (click to toggle)
golang-golang-x-vuln 1.0.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,400 kB
  • sloc: sh: 161; asm: 40; makefile: 7
file content (120 lines) | stat: -rw-r--r-- 2,513 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package client

import (
	"encoding/json"
	"fmt"
	"io/fs"
	"os"
	"path/filepath"

	"golang.org/x/vuln/internal/osv"
	isem "golang.org/x/vuln/internal/semver"
)

// indexFromDir returns a raw index created from a directory
// containing OSV entries.
// It skips any non-JSON files but errors if any of the JSON files
// cannot be unmarshaled into OSV, or have a filename other than <ID>.json.
func indexFromDir(dir string) (map[string][]byte, error) {
	idx := newIndex()
	f := os.DirFS(dir)

	if err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
		fname := d.Name()
		ext := filepath.Ext(fname)
		switch {
		case err != nil:
			return err
		case d.IsDir():
			return nil
		case ext != ".json":
			return nil
		}

		b, err := fs.ReadFile(f, d.Name())
		if err != nil {
			return err
		}
		var entry osv.Entry
		if err := json.Unmarshal(b, &entry); err != nil {
			return err
		}
		if fname != entry.ID+".json" {
			return fmt.Errorf("OSV entries must have filename of the form <ID>.json, got %s", fname)
		}

		idx.add(&entry)
		return nil
	}); err != nil {
		return nil, err
	}

	return idx.raw()
}

func indexFromEntries(entries []*osv.Entry) (map[string][]byte, error) {
	idx := newIndex()

	for _, entry := range entries {
		idx.add(entry)
	}

	return idx.raw()
}

type index struct {
	db      *dbMeta
	modules modulesIndex
}

func newIndex() *index {
	return &index{
		db:      &dbMeta{},
		modules: make(map[string]*moduleMeta),
	}
}

func (i *index) add(entry *osv.Entry) {
	// Add to db index.
	if entry.Modified.After(i.db.Modified) {
		i.db.Modified = entry.Modified
	}
	// Add to modules index.
	for _, affected := range entry.Affected {
		modulePath := affected.Module.Path
		if _, ok := i.modules[modulePath]; !ok {
			i.modules[modulePath] = &moduleMeta{
				Path:  modulePath,
				Vulns: []moduleVuln{},
			}
		}
		module := i.modules[modulePath]
		module.Vulns = append(module.Vulns, moduleVuln{
			ID:       entry.ID,
			Modified: entry.Modified,
			Fixed:    isem.NonSupersededFix(affected.Ranges),
		})
	}
}

func (i *index) raw() (map[string][]byte, error) {
	data := make(map[string][]byte)

	b, err := json.Marshal(i.db)
	if err != nil {
		return nil, err
	}
	data[dbEndpoint] = b

	b, err = json.Marshal(i.modules)
	if err != nil {
		return nil, err
	}
	data[modulesEndpoint] = b

	return data, nil
}