| // Copyright 2022 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" | |
| "path/filepath" | |
| "golang.org/x/vulndb/internal/derrors" | |
| "golang.org/x/vulndb/internal/osv" | |
| ) | |
| // ValidateDeploy checks that the database in newPath is a valid database, | |
| // and that the database in newPath can be safely deployed on top of the | |
| // database in oldPath. | |
| func ValidateDeploy(newPath, oldPath string) (err error) { | |
| derrors.Wrap(&err, "Validate(new=%s, old=%s)", newPath, oldPath) | |
| new, err := Load(newPath) | |
| if err != nil { | |
| return err | |
| } | |
| old, err := RawLoad(filepath.Join(oldPath, idDir)) | |
| if err != nil { | |
| return err | |
| } | |
| return validate(new, old) | |
| } | |
| // validate checks for deleted files and inconsistent timestamps. | |
| func validate(new, old *Database) error { | |
| newEntriesByID := make(map[string]osv.Entry, len(new.Entries)) | |
| for _, newEntry := range new.Entries { | |
| newEntriesByID[newEntry.ID] = newEntry | |
| } | |
| for _, oldEntry := range old.Entries { | |
| newEntry, ok := newEntriesByID[oldEntry.ID] | |
| if !ok { | |
| return fmt.Errorf("%s is not present in new database. Use the %q field to delete an entry", oldEntry.ID, "withdrawn") | |
| } | |
| if newEntry.Published != oldEntry.Published { | |
| return fmt.Errorf("%s: published time cannot change (new %s, old %s)", oldEntry.ID, newEntry.Published, oldEntry.Published) | |
| } | |
| if newEntry.Modified.Before(oldEntry.Modified.Time) { | |
| return fmt.Errorf("%s: modified time cannot decrease (new %s, old %s)", oldEntry.ID, newEntry.Modified, oldEntry.Modified) | |
| } | |
| } | |
| return nil | |
| } |