analyzer: correct auth scoring weights, x-aligned-from penalty, and RBL divide-by-zero

This commit is contained in:
nemunaire 2026-05-18 16:51:30 +08:00
commit 369a13526f
5 changed files with 15 additions and 17 deletions

View file

@ -174,9 +174,7 @@ func (a *AuthenticationAnalyzer) CalculateAuthenticationScore(results *model.Aut
score += 12 * a.calculateXGoogleDKIMScore(results) / 100 score += 12 * a.calculateXGoogleDKIMScore(results) / 100
// Penalty-only: X-Aligned-From (up to -5 points on failure) // Penalty-only: X-Aligned-From (up to -5 points on failure)
if xAlignedScore := a.calculateXAlignedFromScore(results); xAlignedScore < 100 { score += 5 * a.calculateXAlignedFromScore(results) / 100
score += 5 * (xAlignedScore - 100) / 100
}
// Ensure score doesn't exceed 100 // Ensure score doesn't exceed 100
if score > 100 { if score > 100 {

View file

@ -47,7 +47,7 @@ func TestGetAuthenticationScore(t *testing.T) {
Result: model.AuthResultResultPass, Result: model.AuthResultResultPass,
}, },
}, },
expectedScore: 73, // SPF=25 + DKIM=23 + DMARC=25 expectedScore: 90, // SPF=30 + DKIM=30 + DMARC=30
}, },
{ {
name: "SPF and DKIM only", name: "SPF and DKIM only",
@ -59,7 +59,7 @@ func TestGetAuthenticationScore(t *testing.T) {
{Result: model.AuthResultResultPass}, {Result: model.AuthResultResultPass},
}, },
}, },
expectedScore: 48, // SPF=25 + DKIM=23 expectedScore: 60, // SPF=30 + DKIM=30
}, },
{ {
name: "SPF fail, DKIM pass", name: "SPF fail, DKIM pass",
@ -71,7 +71,7 @@ func TestGetAuthenticationScore(t *testing.T) {
{Result: model.AuthResultResultPass}, {Result: model.AuthResultResultPass},
}, },
}, },
expectedScore: 23, // SPF=0 + DKIM=23 expectedScore: 30, // SPF=0 + DKIM=30
}, },
{ {
name: "SPF softfail", name: "SPF softfail",
@ -80,7 +80,7 @@ func TestGetAuthenticationScore(t *testing.T) {
Result: model.AuthResultResultSoftfail, Result: model.AuthResultResultSoftfail,
}, },
}, },
expectedScore: 4, expectedScore: 5, // 30 * 17 / 100 = 5
}, },
{ {
name: "No authentication", name: "No authentication",
@ -97,7 +97,7 @@ func TestGetAuthenticationScore(t *testing.T) {
Result: model.AuthResultResultPass, Result: model.AuthResultResultPass,
}, },
}, },
expectedScore: 35, // SPF (25) + BIMI (10) expectedScore: 40, // SPF (30) + BIMI (10)
}, },
} }

View file

@ -51,16 +51,16 @@ func (a *AuthenticationAnalyzer) calculateXAlignedFromScore(results *model.Authe
if results.XAlignedFrom != nil { if results.XAlignedFrom != nil {
switch results.XAlignedFrom.Result { switch results.XAlignedFrom.Result {
case model.AuthResultResultPass: case model.AuthResultResultPass:
// pass: positive contribution // pass: no impact
return 100 return 0
case model.AuthResultResultFail: case model.AuthResultResultFail:
// fail: negative contribution // fail: negative contribution
return 0 return -100
default: default:
// neutral, none, etc.: no impact // neutral, none, etc.: no impact
return 0 return 0
} }
} }
return 100 return 0
} }

View file

@ -92,18 +92,18 @@ func TestCalculateXAlignedFromScore(t *testing.T) {
expectedScore int expectedScore int
}{ }{
{ {
name: "pass result gives positive score", name: "pass result gives no penalty",
result: &model.AuthResult{ result: &model.AuthResult{
Result: model.AuthResultResultPass, Result: model.AuthResultResultPass,
}, },
expectedScore: 100, expectedScore: 0,
}, },
{ {
name: "fail result gives zero score", name: "fail result gives full penalty",
result: &model.AuthResult{ result: &model.AuthResult{
Result: model.AuthResultResultFail, Result: model.AuthResultResultFail,
}, },
expectedScore: 0, expectedScore: -100,
}, },
{ {
name: "neutral result gives zero score", name: "neutral result gives zero score",

View file

@ -318,7 +318,7 @@ func (r *DNSListChecker) CalculateScore(results *DNSListResults, forWhitelist bo
return 100, "" return 100, ""
} }
if results.ListedCount <= 0 { if results.ListedCount <= 0 || scoringListCount <= 0 {
return 100, "A+" return 100, "A+"
} }