@@ -20,6 +20,35 @@ const ROLE_PRIORITY: Record<ContactRole, number> = {
2020
2121const TIER_RANK : Record < SourceTier , number > = { A : 4 , B : 3 , C : 2 , D : 1 }
2222
23+ // RFC 2606 reserved domains — always unedited template placeholders (e.g. security@example.com).
24+ const PLACEHOLDER_EMAIL_DOMAINS = new Set ( [
25+ 'example.com' ,
26+ 'example.org' ,
27+ 'example.net' ,
28+ 'example.edu' ,
29+ ] )
30+
31+ // Generic GitHub/Dependabot help pages that templated SECURITY.md files link to — never a
32+ // project-specific contact, unlike an actual github.com/<owner>/<repo>/... URL.
33+ const GENERIC_URL_HOSTS = new Set ( [ 'docs.github.com' , 'dependabot.com' , 'www.dependabot.com' ] )
34+
35+ function isJunkContact ( c : RawContact ) : boolean {
36+ if ( c . channel === 'email' ) {
37+ const domain = c . value . split ( '@' ) [ 1 ] ?. toLowerCase ( ) . trim ( )
38+ return domain != null && PLACEHOLDER_EMAIL_DOMAINS . has ( domain )
39+ }
40+ if ( c . channel === 'url' || c . channel === 'web-form' ) {
41+ let host : string
42+ try {
43+ host = new URL ( c . value ) . hostname . toLowerCase ( )
44+ } catch {
45+ return true
46+ }
47+ return GENERIC_URL_HOSTS . has ( host ) || host === 'localhost' || host . startsWith ( '127.' )
48+ }
49+ return false
50+ }
51+
2352function normalizeValue ( channel : ContactChannel , value : string ) : string {
2453 const v = value . trim ( )
2554 return channel === 'email' || channel === 'github-handle' ? v . toLowerCase ( ) : v
@@ -90,7 +119,7 @@ function identityLinkMerge(contacts: RawContact[]): RawContact[] {
90119}
91120
92121export function reconcile ( contacts : RawContact [ ] , now : Date = new Date ( ) ) : ScoredContact [ ] {
93- const merged = identityLinkMerge ( exactMatchMerge ( contacts ) )
122+ const merged = identityLinkMerge ( exactMatchMerge ( contacts . filter ( ( c ) => ! isJunkContact ( c ) ) ) )
94123
95124 const scored : ScoredContact [ ] = merged . map ( ( c ) => {
96125 const contact = { ...c , provenance : dedupeProvenance ( c . provenance ) }
0 commit comments