Skip to content
50 changes: 10 additions & 40 deletions go/internal/database/datastore/affected_versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"slices"
"strings"

"github.com/google/osv.dev/go/internal/osvutil"
"github.com/google/osv.dev/go/osv/ecosystem"
"github.com/ossf/osv-schema/bindings/go/osvschema"
)
Expand Down Expand Up @@ -73,52 +74,21 @@ func computeAffectedVersions(vuln *osvschema.Vulnerability) []AffectedVersions {
}

hasAffected = true
var rangeEvents []AffectedEvent
var events []osvutil.Event
for _, e := range r.GetEvents() {
if e.GetIntroduced() != "" {
rangeEvents = append(rangeEvents, AffectedEvent{Type: "introduced", Value: e.GetIntroduced()})
} else if e.GetFixed() != "" {
rangeEvents = append(rangeEvents, AffectedEvent{Type: "fixed", Value: e.GetFixed()})
} else if e.GetLimit() != "" {
rangeEvents = append(rangeEvents, AffectedEvent{Type: "limit", Value: e.GetLimit()})
} else if e.GetLastAffected() != "" {
rangeEvents = append(rangeEvents, AffectedEvent{Type: "last_affected", Value: e.GetLastAffected()})
evt := osvutil.FromSchemaEvent(e)
if evt.Version != "" {
events = append(events, evt)
}
}

var eventsMap = map[string]int{
"introduced": 0,
"last_affected": 1,
"fixed": 2,
"limit": 3,
}

if exists {
// If we have an ecosystem helper, sort the events to help with querying.
slices.SortFunc(rangeEvents, func(a, b AffectedEvent) int {
pa, errA := eHelper.Parse(a.Value)
pb, errB := eHelper.Parse(b.Value)
if errA != nil || errB != nil {
if a.Value != b.Value {
return strings.Compare(a.Value, b.Value)
}

return eventsMap[a.Type] - eventsMap[b.Type]
}
res, errC := pa.Compare(pb)
if errC != nil {
if a.Value != b.Value {
return strings.Compare(a.Value, b.Value)
}

return eventsMap[a.Type] - eventsMap[b.Type]
}
if res != 0 {
return res
}
_ = osvutil.SortEvents(eHelper, events)
}

return eventsMap[a.Type] - eventsMap[b.Type]
})
var rangeEvents []AffectedEvent
for _, e := range events {
rangeEvents = append(rangeEvents, AffectedEvent{Type: e.Type.String(), Value: e.Version})
}

coarseMin := minCoarseVersion
Expand Down
87 changes: 87 additions & 0 deletions go/internal/database/datastore/relations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package datastore

import (
"context"
"errors"
"fmt"
"slices"

"cloud.google.com/go/datastore"
"github.com/google/osv.dev/go/internal/models"
)

type RelationsStore struct {
client *datastore.Client
}

var _ models.RelationsStore = (*RelationsStore)(nil)

func NewRelationsStore(client *datastore.Client) *RelationsStore {
return &RelationsStore{client: client}
}

func (s *RelationsStore) GetAliases(ctx context.Context, id string) (*models.GetAliasResult, error) {
var aliasGroups []AliasGroup
q := datastore.NewQuery("AliasGroup").FilterField("bug_ids", "=", id)
_, err := s.client.GetAll(ctx, q, &aliasGroups)
if err != nil {
return nil, fmt.Errorf("failed to get alias group: %w", err)
}
if len(aliasGroups) == 0 {
return nil, models.ErrNotFound
}
if len(aliasGroups) > 1 {
return nil, errors.New("id belongs to multiple aliases")
}
aliasGroup := aliasGroups[0]
aliases := make([]string, 0, len(aliasGroup.VulnIDs)-1)
for _, vulnID := range aliasGroup.VulnIDs {
if vulnID != id {
aliases = append(aliases, vulnID)
}
}
slices.Sort(aliases)

return &models.GetAliasResult{
Aliases: aliases,
Modified: aliasGroup.Modified,
}, nil
}

func (s *RelationsStore) GetRelated(ctx context.Context, id string) (*models.GetRelatedResult, error) {
var relatedGroup RelatedGroup
err := s.client.Get(ctx, datastore.NameKey("RelatedGroup", id, nil), &relatedGroup)
if errors.Is(err, datastore.ErrNoSuchEntity) {
return nil, models.ErrNotFound
}
if err != nil {
return nil, fmt.Errorf("failed to get related group: %w", err)
}
related := make([]string, len(relatedGroup.RelatedIDs))
copy(related, relatedGroup.RelatedIDs)
slices.Sort(related)

return &models.GetRelatedResult{
Related: related,
Modified: relatedGroup.Modified,
}, nil
}

func (s *RelationsStore) GetUpstream(ctx context.Context, id string) (*models.GetUpstreamResult, error) {
var upstreamGroup UpstreamGroup
err := s.client.Get(ctx, datastore.NameKey("UpstreamGroup", id, nil), &upstreamGroup)
if errors.Is(err, datastore.ErrNoSuchEntity) {
return nil, models.ErrNotFound
}
if err != nil {
return nil, fmt.Errorf("failed to get upstream group: %w", err)
}
upstream := make([]string, len(upstreamGroup.UpstreamIDs))
copy(upstream, upstreamGroup.UpstreamIDs)
slices.Sort(upstream)

return &models.GetUpstreamResult{
Upstream: upstream,
Modified: upstreamGroup.Modified,
}, nil
}
Loading
Loading