@@ -82,6 +82,24 @@ const (
8282 Filler // Has been determined to be a filler word
8383)
8484
85+ // refTypePriority is a read-only map ReferenceType to priority.
86+ // When multiple references are associated with the same URL, we deduplicate and only keep the type with the highest priority.
87+ // Priority (highest to lowest):
88+ // FIX > INTRODUCED > DETECTION > REPORT > PACKAGE > EVIDENCE > ADVISORY > ARTICLE > DISCUSSION > WEB > GIT
89+ var refTypePriority = map [osvschema.Reference_Type ]int {
90+ osvschema .Reference_FIX : 11 ,
91+ osvschema .Reference_INTRODUCED : 10 ,
92+ osvschema .Reference_DETECTION : 9 ,
93+ osvschema .Reference_REPORT : 8 ,
94+ osvschema .Reference_PACKAGE : 7 ,
95+ osvschema .Reference_EVIDENCE : 6 ,
96+ osvschema .Reference_ADVISORY : 5 ,
97+ osvschema .Reference_ARTICLE : 4 ,
98+ osvschema .Reference_DISCUSSION : 3 ,
99+ osvschema .Reference_WEB : 2 ,
100+ osvschema .Reference_GIT : 1 ,
101+ }
102+
85103// AttachExtractedVersionInfo converts the models.VersionInfo struct to OSV GIT and ECOSYSTEM AffectedRanges and AffectedPackage.
86104func AttachExtractedVersionInfo (v * Vulnerability , version models.VersionInfo ) {
87105 // commit holds a commit hash of one of the supported commit types.
@@ -662,37 +680,36 @@ func Unique[T comparable](s []T) []T {
662680}
663681
664682// ClassifyReferences annotates reference links based on their tags or their shape.
683+ // References with the same URL are deduplicated, and only keep the RefType of the highest priority (see refTypePriority).
665684func ClassifyReferences (refs []models.Reference ) []* osvschema.Reference {
666- var references []* osvschema.Reference
667- refMap := make (map [string ]map [osvschema.Reference_Type ]bool )
668-
669- for _ , reference := range refs {
670- if _ , ok := refMap [reference .URL ]; ! ok {
671- refMap [reference .URL ] = make (map [osvschema.Reference_Type ]bool )
672- }
673-
674- if len (reference .Tags ) > 0 {
675- for _ , tag := range reference .Tags {
676- refType := ClassifyReferenceLink (reference .URL , tag )
677- if ! refMap [reference.URL ][refType ] {
678- references = append (references , & osvschema.Reference {
679- Type : refType ,
680- Url : reference .URL ,
681- })
682- refMap [reference.URL ][refType ] = true
685+ references := make ([]* osvschema.Reference , 0 , len (refs ))
686+ bestTypes := make (map [string ]osvschema.Reference_Type )
687+
688+ for _ , ref := range refs {
689+ if len (ref .Tags ) > 0 {
690+ for _ , tag := range ref .Tags {
691+ refType := ClassifyReferenceLink (ref .URL , tag )
692+ bestType , ok := bestTypes [ref .URL ]
693+ if ! ok || refTypePriority [refType ] > refTypePriority [bestType ] {
694+ bestTypes [ref .URL ] = refType
683695 }
684696 }
685697 } else {
686- refType := ClassifyReferenceLink (reference .URL , "" )
687- if ! refMap [reference.URL ][refType ] {
688- references = append (references , & osvschema.Reference {
689- Type : refType ,
690- Url : reference .URL ,
691- })
692- refMap [reference.URL ][refType ] = true
698+ refType := ClassifyReferenceLink (ref .URL , "" )
699+ bestType , ok := bestTypes [ref .URL ]
700+ if ! ok || refTypePriority [refType ] > refTypePriority [bestType ] {
701+ bestTypes [ref .URL ] = refType
693702 }
694703 }
695704 }
705+
706+ for refURL , refType := range bestTypes {
707+ references = append (references , & osvschema.Reference {
708+ Type : refType ,
709+ Url : refURL ,
710+ })
711+ }
712+
696713 sort .SliceStable (references , func (i , j int ) bool {
697714 return references [i ].GetType () < references [j ].GetType ()
698715 })
0 commit comments