affects.go (2252B)
1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package semver 6 7 import ( 8 "sort" 9 10 "golang.org/x/vuln/internal/osv" 11 ) 12 13 func Affects(a []osv.Range, v string) bool { 14 if len(a) == 0 { 15 // No ranges implies all versions are affected 16 return true 17 } 18 var semverRangePresent bool 19 for _, r := range a { 20 if r.Type != osv.RangeTypeSemver { 21 continue 22 } 23 semverRangePresent = true 24 if ContainsSemver(r, v) { 25 return true 26 } 27 } 28 // If there were no semver ranges present we 29 // assume that all semvers are affected, similarly 30 // to how to we assume all semvers are affected 31 // if there are no ranges at all. 32 return !semverRangePresent 33 } 34 35 // ContainsSemver checks if semver version v is in the 36 // range encoded by ar. If ar is not a semver range, 37 // returns false. A range is interpreted as a left-closed 38 // and right-open interval. 39 // 40 // Assumes that 41 // - exactly one of Introduced or Fixed fields is set 42 // - ranges in ar are not overlapping 43 // - beginning of time is encoded with .Introduced="0" 44 // - no-fix is not an event, as opposed to being an 45 // event where Introduced="" and Fixed="" 46 func ContainsSemver(ar osv.Range, v string) bool { 47 if ar.Type != osv.RangeTypeSemver { 48 return false 49 } 50 if len(ar.Events) == 0 { 51 return true 52 } 53 54 // Strip and then add the semver prefix so we can support bare versions, 55 // versions prefixed with 'v', and versions prefixed with 'go'. 56 v = canonicalizeSemverPrefix(v) 57 58 // Sort events by semver versions. Event for beginning 59 // of time, if present, always comes first. 60 sort.SliceStable(ar.Events, func(i, j int) bool { 61 e1 := ar.Events[i] 62 v1 := e1.Introduced 63 if v1 == "0" { 64 // -inf case. 65 return true 66 } 67 if e1.Fixed != "" { 68 v1 = e1.Fixed 69 } 70 71 e2 := ar.Events[j] 72 v2 := e2.Introduced 73 if v2 == "0" { 74 // -inf case. 75 return false 76 } 77 if e2.Fixed != "" { 78 v2 = e2.Fixed 79 } 80 81 return Less(v1, v2) 82 }) 83 84 var affected bool 85 for _, e := range ar.Events { 86 if !affected && e.Introduced != "" { 87 affected = e.Introduced == "0" || !Less(v, e.Introduced) 88 } else if affected && e.Fixed != "" { 89 affected = Less(v, e.Fixed) 90 } 91 } 92 93 return affected 94 }