From 16b7dcb057ee91d51e39436b4f8abcc94695101a Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 26 Mar 2026 10:31:09 +0700 Subject: [PATCH] Incorporate DNSWL (whitelist) grade into blacklist scoring CalculateScore now accepts a forWhitelist flag to handle whitelist scoring logic separately. The final blacklist grade combines both RBL and DNSWL results using MinGrade for a more accurate reputation assessment. --- pkg/analyzer/analyzer.go | 2 +- pkg/analyzer/rbl.go | 15 +++++++++++++-- pkg/analyzer/report.go | 6 ++++-- pkg/analyzer/scoring.go | 2 ++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/pkg/analyzer/analyzer.go b/pkg/analyzer/analyzer.go index 54d9e42..f21d1f8 100644 --- a/pkg/analyzer/analyzer.go +++ b/pkg/analyzer/analyzer.go @@ -138,7 +138,7 @@ func (a *APIAdapter) CheckBlacklistIP(ip string) ([]api.BlacklistCheck, []api.Bl IPsChecked: []string{ip}, ListedCount: listedCount, } - score, grade := a.analyzer.generator.rblChecker.CalculateScore(results) + score, grade := a.analyzer.generator.rblChecker.CalculateScore(results, false) // Check the IP against all configured DNSWLs (informational only) whitelists, _, err := a.analyzer.generator.dnswlChecker.CheckIP(ip) diff --git a/pkg/analyzer/rbl.go b/pkg/analyzer/rbl.go index 64db1f7..47e74e0 100644 --- a/pkg/analyzer/rbl.go +++ b/pkg/analyzer/rbl.go @@ -300,7 +300,19 @@ func (r *DNSListChecker) reverseIP(ipStr string) string { // CalculateScore calculates the list contribution to deliverability. // Informational lists are not counted in the score. -func (r *DNSListChecker) CalculateScore(results *DNSListResults) (int, string) { +func (r *DNSListChecker) CalculateScore(results *DNSListResults, forWhitelist bool) (int, string) { + scoringListCount := len(r.Lists) - len(r.informationalSet) + + if forWhitelist { + if results.ListedCount >= scoringListCount { + return 100, "A++" + } else if results.ListedCount > 0 { + return 100, "A+" + } else { + return 95, "A" + } + } + if results == nil || len(results.IPsChecked) == 0 { return 100, "" } @@ -309,7 +321,6 @@ func (r *DNSListChecker) CalculateScore(results *DNSListResults) (int, string) { return 100, "A+" } - scoringListCount := len(r.Lists) - len(r.informationalSet) percentage := 100 - results.RelevantListedCount*100/scoringListCount return percentage, ScoreToGrade(percentage) } diff --git a/pkg/analyzer/report.go b/pkg/analyzer/report.go index 6dcf588..7332307 100644 --- a/pkg/analyzer/report.go +++ b/pkg/analyzer/report.go @@ -141,8 +141,10 @@ func (r *ReportGenerator) GenerateReport(testID uuid.UUID, results *AnalysisResu blacklistScore := 0 var blacklistGrade string + var whitelistGrade string if results.RBL != nil { - blacklistScore, blacklistGrade = r.rblChecker.CalculateScore(results.RBL) + blacklistScore, blacklistGrade = r.rblChecker.CalculateScore(results.RBL, false) + _, whitelistGrade = r.dnswlChecker.CalculateScore(results.DNSWL, true) } saScore, saGrade := r.spamAnalyzer.CalculateSpamAssassinScore(results.SpamAssassin) @@ -173,7 +175,7 @@ func (r *ReportGenerator) GenerateReport(testID uuid.UUID, results *AnalysisResu AuthenticationScore: authScore, AuthenticationGrade: api.ScoreSummaryAuthenticationGrade(authGrade), BlacklistScore: blacklistScore, - BlacklistGrade: api.ScoreSummaryBlacklistGrade(blacklistGrade), + BlacklistGrade: api.ScoreSummaryBlacklistGrade(MinGrade(blacklistGrade, whitelistGrade)), ContentScore: contentScore, ContentGrade: api.ScoreSummaryContentGrade(contentGrade), HeaderScore: headerScore, diff --git a/pkg/analyzer/scoring.go b/pkg/analyzer/scoring.go index 798590f..5568c8e 100644 --- a/pkg/analyzer/scoring.go +++ b/pkg/analyzer/scoring.go @@ -73,6 +73,8 @@ func ScoreToReportGrade(score int) api.ReportGrade { // gradeRank returns a numeric rank for a grade (lower = worse) func gradeRank(grade string) int { switch grade { + case "A++": + return 7 case "A+": return 6 case "A":