@@ -87,41 +87,35 @@ export function VulnerabilityFixBySeverityMetric(
8787) : Record < string , Record < string , number > > {
8888 const timeline : Record < string , Record < string , number > > = { } ;
8989
90- for ( const [ , commitEntry ] of Object . entries ( commitHistory ) ) {
91- if ( ! commitEntry || ! Array . isArray ( commitEntry . history ) ) continue ;
92- const historyArray = commitEntry . history ;
93-
94- for ( const entry of historyArray ) {
95- if (
96- entry . action !== 'MODIFIED' ||
97- ! entry . fromVersion ||
98- ! entry . toVersion ||
99- ! entry . date ||
100- ! entry . depinderDependencyName
101- ) continue ;
90+ const isSemverVulnerable = ( version : string | undefined , range : string ) : boolean =>
91+ ! ! version && semver . valid ( version ) !== null && semver . satisfies ( version , range ) ;
10292
103- const libKey = Object . keys ( libraryInfoMap ) . find ( k => k . endsWith ( `:${ entry . depinderDependencyName } ` ) ) ;
93+ for ( const [ , commitEntry ] of Object . entries ( commitHistory ) ) {
94+ if ( ! commitEntry ?. history ?. length ) continue ;
95+ for ( const entry of commitEntry . history ) {
96+ if ( ! entry . date || ! entry . depinderDependencyName ) continue ;
97+ const libKey = Object . keys ( libraryInfoMap ) . find ( k =>
98+ k . endsWith ( `:${ entry . depinderDependencyName } ` )
99+ ) ;
104100 if ( ! libKey ) continue ;
105-
106- const libInfo = libraryInfoMap [ libKey ] ;
107- const libVulnerabilities = libInfo ?. info ?. vulnerabilities || [ ] ;
108-
101+ const vulnerabilities = libraryInfoMap [ libKey ] ?. info ?. vulnerabilities || [ ] ;
109102 const month = entry . date . slice ( 0 , 7 ) ;
110-
111- for ( const vuln of libVulnerabilities ) {
103+ for ( const vuln of vulnerabilities ) {
112104 if ( ! vuln . vulnerableRange || ! vuln . severity ) continue ;
113105 const cleanRange = vuln . vulnerableRange . replace ( / , / g, ' ' ) . trim ( ) ;
114-
115- const wasVulnerable =
116- semver . valid ( entry . fromVersion ) && semver . satisfies ( entry . fromVersion , cleanRange ) ;
117- const stillVulnerable =
118- semver . valid ( entry . toVersion ) && semver . satisfies ( entry . toVersion , cleanRange ) ;
119- const isFixed = wasVulnerable && ! stillVulnerable ;
120-
106+ const severity = vuln . severity ;
107+ let isFixed = false ;
108+ if ( entry . action === 'MODIFIED' ) {
109+ const wasVulnerable = isSemverVulnerable ( entry . fromVersion , cleanRange ) ;
110+ const stillVulnerable = isSemverVulnerable ( entry . toVersion , cleanRange ) ;
111+ isFixed = wasVulnerable && ! stillVulnerable ;
112+ }
113+ if ( entry . action === 'DELETED' ) {
114+ isFixed = isSemverVulnerable ( entry . version , cleanRange ) ;
115+ }
121116 if ( isFixed ) {
122117 if ( ! timeline [ month ] ) timeline [ month ] = { } ;
123- if ( ! timeline [ month ] [ vuln . severity ] ) timeline [ month ] [ vuln . severity ] = 0 ;
124- timeline [ month ] [ vuln . severity ] ++ ;
118+ timeline [ month ] [ severity ] = ( timeline [ month ] [ severity ] || 0 ) + 1 ;
125119 }
126120 }
127121 }
@@ -153,8 +147,10 @@ export function VulnerabilityFixTimelinessMetric(
153147 if ( ! commitEntry ?. history ?. length ) continue ;
154148
155149 for ( const entry of commitEntry . history ) {
156- if ( ! entry . date || ! entry . fromVersion || ! entry . depinderDependencyName ) continue ;
157- const libKey = Object . keys ( libraryInfoMap ) . find ( k => k . endsWith ( `:${ entry . depinderDependencyName } ` ) ) ;
150+ if ( ! entry . date || ! entry . depinderDependencyName ) continue ;
151+ const libKey = Object . keys ( libraryInfoMap ) . find ( k =>
152+ k . endsWith ( `:${ entry . depinderDependencyName } ` )
153+ ) ;
158154 if ( ! libKey ) continue ;
159155
160156 const vulnerabilities = libraryInfoMap [ libKey ] ?. info ?. vulnerabilities || [ ] ;
@@ -164,26 +160,32 @@ export function VulnerabilityFixTimelinessMetric(
164160 if ( ! vuln . vulnerableRange || ! vuln . severity ) continue ;
165161 const cleanRange = vuln . vulnerableRange . replace ( / , / g, ' ' ) . trim ( ) ;
166162 const key = `${ entry . depinderDependencyName } @@${ cleanRange } ` ;
167-
168- const seenValid = semver . valid ( entry . fromVersion ) && semver . satisfies ( entry . fromVersion , cleanRange ) ;
169- if ( seenValid ) {
163+ const versionToCheck =
164+ entry . action === 'MODIFIED' ? entry . fromVersion :
165+ entry . action === 'DELETED' ? entry . version :
166+ undefined ;
167+ const isVersionVulnerable =
168+ ! ! versionToCheck && semver . valid ( versionToCheck ) && semver . satisfies ( versionToCheck , cleanRange ) ;
169+ if ( isVersionVulnerable ) {
170170 if ( ! firstSeenMap [ key ] || entryDate < firstSeenMap [ key ] ) {
171171 firstSeenMap [ key ] = entryDate ;
172172 }
173173 }
174-
175- const isFix = entry . action === 'MODIFIED' &&
174+ const isFixViaModification =
175+ entry . action === 'MODIFIED' &&
176176 ! ! entry . toVersion &&
177- semver . valid ( entry . fromVersion ) &&
178177 semver . valid ( entry . toVersion ) &&
179- semver . satisfies ( entry . fromVersion , cleanRange ) &&
178+ isVersionVulnerable &&
180179 ! semver . satisfies ( entry . toVersion , cleanRange ) ;
181-
180+ const isFixViaDeletion =
181+ entry . action === 'DELETED' &&
182+ isVersionVulnerable ;
183+ const isFix = isFixViaModification || isFixViaDeletion ;
182184 if ( isFix ) {
183185 const introducedDate = firstSeenMap [ key ] ?? entryDate ;
184- const daysToFix : number = differenceInBusinessDays ( entryDate , introducedDate ) ;
185- const severity : SeverityLevel = vuln . severity . toUpperCase ( ) as SeverityLevel ;
186- const fixDeadlineDays : number = severityFixTimeLimits [ severity ] ?? 999 ;
186+ const daysToFix = differenceInBusinessDays ( entryDate , introducedDate ) ;
187+ const severity = vuln . severity . toUpperCase ( ) as SeverityLevel ;
188+ const fixDeadlineDays : any = severityFixTimeLimits [ severity ] ?? 999 ;
187189 const fixCategory : FixCategory = daysToFix <= fixDeadlineDays ? 'fixedInTime' : 'fixedLate' ;
188190 const month = entryDate . toISOString ( ) . slice ( 0 , 7 ) ;
189191
0 commit comments