| // 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 database | |
| import ( | |
| "fmt" | |
| "golang.org/x/vulndb/internal/osv" | |
| "golang.org/x/vulndb/internal/osvutils" | |
| ) | |
| // New creates a new database from the given entries. | |
| // Errors if there are multiple entries with the same ID. | |
| func New(entries ...osv.Entry) (*Database, error) { | |
| db := &Database{ | |
| DB: DBMeta{}, | |
| Modules: make(ModulesIndex), | |
| Vulns: make(VulnsIndex), | |
| Entries: make([]osv.Entry, 0, len(entries)), | |
| } | |
| for _, entry := range entries { | |
| if err := db.Add(entry); err != nil { | |
| return nil, err | |
| } | |
| } | |
| return db, nil | |
| } | |
| // Add adds new entries to a database, erroring if any of the entries | |
| // is already in the database. | |
| func (db *Database) Add(entries ...osv.Entry) error { | |
| for _, entry := range entries { | |
| if err := db.Vulns.add(entry); err != nil { | |
| return err | |
| } | |
| // Only add the entry once we are sure it won't | |
| // cause an error. | |
| db.Entries = append(db.Entries, entry) | |
| db.Modules.add(entry) | |
| db.DB.add(entry) | |
| } | |
| return nil | |
| } | |
| func (dbi *DBMeta) add(entry osv.Entry) { | |
| if entry.Modified.After(dbi.Modified.Time) { | |
| dbi.Modified = entry.Modified | |
| } | |
| } | |
| func (m *ModulesIndex) add(entry osv.Entry) { | |
| for _, affected := range entry.Affected { | |
| modulePath := affected.Module.Path | |
| if _, ok := (*m)[modulePath]; !ok { | |
| (*m)[modulePath] = &Module{ | |
| Path: modulePath, | |
| Vulns: []ModuleVuln{}, | |
| } | |
| } | |
| module := (*m)[modulePath] | |
| module.Vulns = append(module.Vulns, ModuleVuln{ | |
| ID: entry.ID, | |
| Modified: entry.Modified, | |
| Fixed: osvutils.LatestFixed(affected.Ranges), | |
| }) | |
| } | |
| } | |
| func (v *VulnsIndex) add(entry osv.Entry) error { | |
| if _, ok := (*v)[entry.ID]; ok { | |
| return fmt.Errorf("id %q appears twice in database", entry.ID) | |
| } | |
| (*v)[entry.ID] = &Vuln{ | |
| ID: entry.ID, | |
| Modified: entry.Modified, | |
| Aliases: entry.Aliases, | |
| } | |
| return nil | |
| } |