mirror of https://github.com/golang/go.git
139 lines
3.4 KiB
Go
139 lines
3.4 KiB
Go
// Copyright 2021 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.
|
|
|
|
//go:build go1.18
|
|
// +build go1.18
|
|
|
|
// Package govulncheck supports the govulncheck command.
|
|
package govulncheck
|
|
|
|
import (
|
|
"encoding/json"
|
|
"go/build"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"time"
|
|
|
|
"golang.org/x/vuln/client"
|
|
"golang.org/x/vuln/osv"
|
|
)
|
|
|
|
// The cache uses a single JSON index file for each vulnerability database
|
|
// which contains the map from packages to the time the last
|
|
// vulnerability for that package was added/modified and the time that
|
|
// the index was retrieved from the vulnerability database. The JSON
|
|
// format is as follows:
|
|
//
|
|
// $GOPATH/pkg/mod/cache/download/vulndb/{db hostname}/indexes/index.json
|
|
// {
|
|
// Retrieved time.Time
|
|
// Index client.DBIndex
|
|
// }
|
|
//
|
|
// Each package also has a JSON file which contains the array of vulnerability
|
|
// entries for the package. The JSON format is as follows:
|
|
//
|
|
// $GOPATH/pkg/mod/cache/download/vulndb/{db hostname}/{import path}/vulns.json
|
|
// []*osv.Entry
|
|
|
|
// FSCache is a thread-safe file-system cache implementing osv.Cache
|
|
//
|
|
// TODO: use something like cmd/go/internal/lockedfile for thread safety?
|
|
type FSCache struct {
|
|
mu sync.Mutex
|
|
rootDir string
|
|
}
|
|
|
|
// Assert that *FSCache implements client.Cache.
|
|
var _ client.Cache = (*FSCache)(nil)
|
|
|
|
// use cfg.GOMODCACHE available in cmd/go/internal?
|
|
var defaultCacheRoot = filepath.Join(build.Default.GOPATH, "/pkg/mod/cache/download/vulndb")
|
|
|
|
func DefaultCache() *FSCache {
|
|
return &FSCache{rootDir: defaultCacheRoot}
|
|
}
|
|
|
|
type cachedIndex struct {
|
|
Retrieved time.Time
|
|
Index client.DBIndex
|
|
}
|
|
|
|
func (c *FSCache) ReadIndex(dbName string) (client.DBIndex, time.Time, error) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
b, err := ioutil.ReadFile(filepath.Join(c.rootDir, dbName, "index.json"))
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil, time.Time{}, nil
|
|
}
|
|
return nil, time.Time{}, err
|
|
}
|
|
var index cachedIndex
|
|
if err := json.Unmarshal(b, &index); err != nil {
|
|
return nil, time.Time{}, err
|
|
}
|
|
return index.Index, index.Retrieved, nil
|
|
}
|
|
|
|
func (c *FSCache) WriteIndex(dbName string, index client.DBIndex, retrieved time.Time) error {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
path := filepath.Join(c.rootDir, dbName)
|
|
if err := os.MkdirAll(path, 0755); err != nil {
|
|
return err
|
|
}
|
|
j, err := json.Marshal(cachedIndex{
|
|
Index: index,
|
|
Retrieved: retrieved,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := ioutil.WriteFile(filepath.Join(path, "index.json"), j, 0666); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *FSCache) ReadEntries(dbName string, p string) ([]*osv.Entry, error) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
b, err := ioutil.ReadFile(filepath.Join(c.rootDir, dbName, p, "vulns.json"))
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
var entries []*osv.Entry
|
|
if err := json.Unmarshal(b, &entries); err != nil {
|
|
return nil, err
|
|
}
|
|
return entries, nil
|
|
}
|
|
|
|
func (c *FSCache) WriteEntries(dbName string, p string, entries []*osv.Entry) error {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
path := filepath.Join(c.rootDir, dbName, p)
|
|
if err := os.MkdirAll(path, 0777); err != nil {
|
|
return err
|
|
}
|
|
j, err := json.Marshal(entries)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := ioutil.WriteFile(filepath.Join(path, "vulns.json"), j, 0666); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|