Files
Charon/backend/internal/services/security_score_test.go
GitHub Actions 3169b05156 fix: skip incomplete system log viewer tests
- Marked 12 tests as skip pending feature implementation
- Features tracked in GitHub issue #686 (system log viewer feature completion)
- Tests cover sorting by timestamp/level/method/URI/status, pagination controls, filtering by text/level, download functionality
- Unblocks Phase 2 at 91.7% pass rate to proceed to Phase 3 security enforcement validation
- TODO comments in code reference GitHub #686 for feature completion tracking
- Tests skipped: Pagination (3), Search/Filter (2), Download (2), Sorting (1), Log Display (4)
2026-02-09 21:55:55 +00:00

167 lines
5.9 KiB
Go

package services
import (
"testing"
"github.com/Wikid82/charon/backend/internal/models"
"github.com/stretchr/testify/assert"
)
func TestCalculateSecurityScore_AllEnabled(t *testing.T) {
profile := &models.SecurityHeaderProfile{
HSTSEnabled: true,
HSTSMaxAge: 63072000,
HSTSIncludeSubdomains: true,
HSTSPreload: true,
CSPEnabled: true,
CSPDirectives: `{"default-src":["'self'"],"script-src":["'self'"],"style-src":["'self'"]}`,
XFrameOptions: "DENY",
XContentTypeOptions: true,
ReferrerPolicy: "no-referrer",
PermissionsPolicy: `[{"feature":"camera","allowlist":[]}]`,
CrossOriginOpenerPolicy: "same-origin",
CrossOriginResourcePolicy: "same-origin",
CrossOriginEmbedderPolicy: "require-corp",
}
result := CalculateSecurityScore(profile)
assert.Equal(t, 100, result.TotalScore)
assert.Equal(t, 100, result.MaxScore)
assert.Equal(t, 25, result.Breakdown["hsts"])
assert.Equal(t, 25, result.Breakdown["csp"])
assert.Equal(t, 10, result.Breakdown["x_frame_options"])
assert.Equal(t, 10, result.Breakdown["x_content_type_options"])
assert.Equal(t, 10, result.Breakdown["referrer_policy"])
assert.Equal(t, 10, result.Breakdown["permissions_policy"])
assert.Equal(t, 10, result.Breakdown["cross_origin"])
assert.Empty(t, result.Suggestions)
}
func TestCalculateSecurityScore_HSTSOnly(t *testing.T) {
profile := &models.SecurityHeaderProfile{
HSTSEnabled: true,
HSTSMaxAge: 31536000,
HSTSIncludeSubdomains: true,
HSTSPreload: false,
CSPEnabled: false,
XFrameOptions: "SAMEORIGIN",
XContentTypeOptions: true,
ReferrerPolicy: "strict-origin-when-cross-origin",
}
result := CalculateSecurityScore(profile)
assert.Equal(t, 20, result.Breakdown["hsts"]) // 10 + 5 + 5, missing preload
assert.Equal(t, 0, result.Breakdown["csp"])
assert.Equal(t, 7, result.Breakdown["x_frame_options"]) // SAMEORIGIN = 7 points
assert.Equal(t, 10, result.Breakdown["x_content_type_options"])
assert.Equal(t, 10, result.Breakdown["referrer_policy"])
assert.Equal(t, 0, result.Breakdown["permissions_policy"])
assert.Equal(t, 0, result.Breakdown["cross_origin"])
assert.Contains(t, result.Suggestions, "Consider HSTS preload for browser preload lists")
assert.Contains(t, result.Suggestions, "Enable Content-Security-Policy")
}
func TestCalculateSecurityScore_NoHeaders(t *testing.T) {
profile := &models.SecurityHeaderProfile{
HSTSEnabled: false,
CSPEnabled: false,
XFrameOptions: "",
XContentTypeOptions: false,
ReferrerPolicy: "",
}
result := CalculateSecurityScore(profile)
assert.Equal(t, 0, result.TotalScore)
assert.Equal(t, 100, result.MaxScore)
assert.Contains(t, result.Suggestions, "Enable HSTS to enforce HTTPS")
assert.Contains(t, result.Suggestions, "Enable Content-Security-Policy")
assert.Contains(t, result.Suggestions, "Set X-Frame-Options to DENY or SAMEORIGIN")
assert.Contains(t, result.Suggestions, "Enable X-Content-Type-Options: nosniff")
}
func TestCalculateSecurityScore_UnsafeCSP(t *testing.T) {
profile := &models.SecurityHeaderProfile{
HSTSEnabled: true,
HSTSMaxAge: 31536000,
CSPEnabled: true,
CSPDirectives: `{"default-src":["'self'"],"script-src":["'self'","'unsafe-inline'","'unsafe-eval'"]}`,
XFrameOptions: "DENY",
XContentTypeOptions: true,
ReferrerPolicy: "strict-origin",
}
result := CalculateSecurityScore(profile)
assert.Equal(t, 15, result.Breakdown["csp"]) // Base 15, no bonus for unsafe directives
assert.Contains(t, result.Suggestions, "Avoid 'unsafe-inline' in CSP for better security")
assert.Contains(t, result.Suggestions, "Avoid 'unsafe-eval' in CSP for better security")
}
func TestCalculateSecurityScore_PartialCrossOrigin(t *testing.T) {
profile := &models.SecurityHeaderProfile{
HSTSEnabled: true,
HSTSMaxAge: 31536000,
CSPEnabled: false,
XFrameOptions: "DENY",
XContentTypeOptions: true,
ReferrerPolicy: "strict-origin",
CrossOriginOpenerPolicy: "same-origin",
CrossOriginResourcePolicy: "same-origin",
}
result := CalculateSecurityScore(profile)
assert.Equal(t, 7, result.Breakdown["cross_origin"]) // 4 + 3, missing embedder
assert.Contains(t, result.Suggestions, "Add Cross-Origin isolation headers")
}
func TestCalculateSecurityScore_WeakReferrerPolicy(t *testing.T) {
profile := &models.SecurityHeaderProfile{
HSTSEnabled: true,
HSTSMaxAge: 31536000,
XFrameOptions: "DENY",
XContentTypeOptions: true,
ReferrerPolicy: "origin-when-cross-origin",
}
result := CalculateSecurityScore(profile)
assert.Equal(t, 7, result.Breakdown["referrer_policy"])
assert.Contains(t, result.Suggestions, "Use a stricter Referrer-Policy")
}
func TestCalculateSecurityScore_UnknownReferrerPolicy(t *testing.T) {
profile := &models.SecurityHeaderProfile{
HSTSEnabled: true,
HSTSMaxAge: 31536000,
XFrameOptions: "DENY",
XContentTypeOptions: true,
ReferrerPolicy: "unsafe-url",
}
result := CalculateSecurityScore(profile)
assert.Equal(t, 3, result.Breakdown["referrer_policy"]) // Non-empty but not strict
assert.Contains(t, result.Suggestions, "Use a stricter Referrer-Policy")
}
func TestCalculateSecurityScore_ShortHSTSMaxAge(t *testing.T) {
profile := &models.SecurityHeaderProfile{
HSTSEnabled: true,
HSTSMaxAge: 86400, // 1 day - too short
HSTSIncludeSubdomains: false,
XFrameOptions: "DENY",
XContentTypeOptions: true,
ReferrerPolicy: "strict-origin",
}
result := CalculateSecurityScore(profile)
assert.Equal(t, 10, result.Breakdown["hsts"]) // Only base score, no bonus
assert.Contains(t, result.Suggestions, "Increase HSTS max-age to at least 1 year")
assert.Contains(t, result.Suggestions, "Enable HSTS for subdomains")
}