* Extract the fixed version for a specific package version from vulnerability data. * Finds all intervals that contain the current version and returns the closest fix, * preferring a nearby backport over a distant major-version bump. * @see https://ossf.github.io/osv-schema/#affectedrangesevents-
( affected: OsvAffected[] | undefined, packageName: string, currentVersion: string, )
| 187 | * @see https://ossf.github.io/osv-schema/#affectedrangesevents-fields |
| 188 | */ |
| 189 | function getFixedVersion( |
| 190 | affected: OsvAffected[] | undefined, |
| 191 | packageName: string, |
| 192 | currentVersion: string, |
| 193 | ): string | undefined { |
| 194 | if (!affected) return undefined |
| 195 | |
| 196 | // Find all affected entries for this specific package |
| 197 | const packageAffectedEntries = affected.filter( |
| 198 | a => a.package.ecosystem === 'npm' && a.package.name === packageName, |
| 199 | ) |
| 200 | |
| 201 | // Collect all matching fixed versions across all ranges |
| 202 | const matchingFixedVersions: string[] = [] |
| 203 | |
| 204 | for (const entry of packageAffectedEntries) { |
| 205 | if (!entry.ranges) continue |
| 206 | |
| 207 | for (const range of entry.ranges) { |
| 208 | // Only handle SEMVER ranges (most common for npm) |
| 209 | if (range.type !== 'SEMVER') continue |
| 210 | |
| 211 | const intervals = parseRangeIntervals(range) |
| 212 | for (const interval of intervals) { |
| 213 | const introVersion = interval.introduced === '0' ? '0.0.0' : interval.introduced |
| 214 | try { |
| 215 | const afterIntro = semver.gte(currentVersion, introVersion) |
| 216 | const beforeFixed = !interval.fixed || semver.lt(currentVersion, interval.fixed) |
| 217 | if (afterIntro && beforeFixed && interval.fixed) { |
| 218 | matchingFixedVersions.push(interval.fixed) |
| 219 | } |
| 220 | } catch { |
| 221 | continue |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | if (matchingFixedVersions.length === 0) return undefined |
| 228 | if (matchingFixedVersions.length === 1) return matchingFixedVersions[0] |
| 229 | |
| 230 | // Return the lowest (closest) fixed version — the smallest bump from the current version |
| 231 | return matchingFixedVersions.sort(semver.compare)[0] |
| 232 | } |
| 233 | |
| 234 | function getSeverityLevel(vuln: OsvVulnerability): OsvSeverityLevel { |
| 235 | const dbSeverity = vuln.database_specific?.severity?.toLowerCase() |
no test coverage detected