checker-http/checker/rules_cookies_rfc6265bis_test.go

160 lines
5.2 KiB
Go

// This file is part of the happyDomain (R) project.
// Copyright (c) 2020-2026 happyDomain
// Authors: Pierre-Olivier Mercier, et al.
package checker
import (
"strings"
"testing"
sdk "git.happydns.org/checker-sdk-go/checker"
)
func TestCookiePrefixesRule_NoHTTPS(t *testing.T) {
data := &HTTPData{Probes: []HTTPProbe{httpProbe("a:80")}}
states := runRule(t, &cookiePrefixesRule{}, data, nil)
mustStatus(t, states, sdk.StatusUnknown)
if !hasCode(states, "http.cookie_prefixes.no_https") {
t.Errorf("missing no_https code: %+v", states)
}
}
func TestCookiePrefixesRule_NoPrefixed(t *testing.T) {
p := httpsProbe("a:443")
p.Cookies = []CookieInfo{{Name: "sid", Secure: true, HttpOnly: true, SameSite: "Lax"}}
states := runRule(t, &cookiePrefixesRule{}, &HTTPData{Probes: []HTTPProbe{p}}, nil)
mustStatus(t, states, sdk.StatusInfo)
if !hasCode(states, "http.cookie_prefixes.none") {
t.Errorf("missing 'none' code: %+v", states)
}
}
func TestCookiePrefixesRule_HostOK(t *testing.T) {
p := httpsProbe("a:443")
p.Cookies = []CookieInfo{
{Name: "__Host-sid", Secure: true, HttpOnly: true, SameSite: "Strict", Path: "/"},
{Name: "__Secure-tok", Secure: true, HttpOnly: true, SameSite: "Lax", Path: "/app"},
}
states := runRule(t, &cookiePrefixesRule{}, &HTTPData{Probes: []HTTPProbe{p}}, nil)
mustStatus(t, states, sdk.StatusOK)
if !hasCode(states, "http.cookie_prefixes.ok") {
t.Errorf("missing ok code: %+v", states)
}
}
func TestCookiePrefixesRule_SecureMissingSecure(t *testing.T) {
p := httpsProbe("a:443")
p.Cookies = []CookieInfo{{Name: "__Secure-x", Secure: false, HttpOnly: true, SameSite: "Lax"}}
states := runRule(t, &cookiePrefixesRule{}, &HTTPData{Probes: []HTTPProbe{p}}, nil)
mustStatus(t, states, sdk.StatusWarn)
if !hasCode(states, "http.cookie_prefixes.invalid_secure") {
t.Errorf("missing invalid_secure code: %+v", states)
}
}
func TestCookiePrefixesRule_HostViolations(t *testing.T) {
cases := []struct {
name string
cookie CookieInfo
want []string
}{
{
name: "no Secure",
cookie: CookieInfo{Name: "__Host-a", Secure: false, Path: "/"},
want: []string{"missing Secure"},
},
{
name: "Domain set",
cookie: CookieInfo{Name: "__Host-a", Secure: true, Domain: "example.test", Path: "/"},
want: []string{"Domain attribute is forbidden"},
},
{
name: "wrong Path",
cookie: CookieInfo{Name: "__Host-a", Secure: true, Path: "/app"},
want: []string{`Path must be "/"`},
},
{
name: "all three",
cookie: CookieInfo{Name: "__Host-a", Secure: false, Domain: "x", Path: "/x"},
want: []string{"missing Secure", "Domain attribute is forbidden", `Path must be "/"`},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
p := httpsProbe("a:443")
p.Cookies = []CookieInfo{c.cookie}
states := runRule(t, &cookiePrefixesRule{}, &HTTPData{Probes: []HTTPProbe{p}}, nil)
mustStatus(t, states, sdk.StatusWarn)
if !hasCode(states, "http.cookie_prefixes.invalid_host") {
t.Fatalf("missing invalid_host code: %+v", states)
}
for _, w := range c.want {
if !strings.Contains(states[0].Message, w) {
t.Errorf("message missing %q: %s", w, states[0].Message)
}
}
})
}
}
func TestCookiePrefixesRule_LoadFailure(t *testing.T) {
states := (&cookiePrefixesRule{}).Evaluate(t.Context(), &fakeObs{failGet: true}, nil)
if len(states) != 1 || states[0].Status != sdk.StatusError {
t.Fatalf("expected single error state, got %+v", states)
}
}
func TestCookieSizeRule_NoHTTPS(t *testing.T) {
data := &HTTPData{Probes: []HTTPProbe{httpProbe("a:80")}}
states := runRule(t, &cookieSizeRule{}, data, nil)
mustStatus(t, states, sdk.StatusUnknown)
}
func TestCookieSizeRule_None(t *testing.T) {
data := &HTTPData{Probes: []HTTPProbe{httpsProbe("a:443")}}
states := runRule(t, &cookieSizeRule{}, data, nil)
mustStatus(t, states, sdk.StatusOK)
if !hasCode(states, "http.cookie_size.none") {
t.Errorf("missing 'none' code: %+v", states)
}
}
func TestCookieSizeRule_OK(t *testing.T) {
p := httpsProbe("a:443")
p.Cookies = []CookieInfo{
{Name: "small", Size: 200},
{Name: "borderline", Size: MaxCookieSize}, // exactly the limit is acceptable
}
states := runRule(t, &cookieSizeRule{}, &HTTPData{Probes: []HTTPProbe{p}}, nil)
mustStatus(t, states, sdk.StatusOK)
if !hasCode(states, "http.cookie_size.ok") {
t.Errorf("missing ok code: %+v", states)
}
}
func TestCookieSizeRule_TooLarge(t *testing.T) {
p := httpsProbe("a:443")
p.Cookies = []CookieInfo{
{Name: "small", Size: 100},
{Name: "huge", Size: MaxCookieSize + 1},
}
states := runRule(t, &cookieSizeRule{}, &HTTPData{Probes: []HTTPProbe{p}}, nil)
if len(states) != 1 {
t.Fatalf("got %d states, want 1 (only the oversized cookie)", len(states))
}
mustStatus(t, states, sdk.StatusWarn)
if !hasCode(states, "http.cookie_size.too_large") {
t.Errorf("missing too_large code: %+v", states)
}
if !strings.Contains(states[0].Message, "huge") {
t.Errorf("message should mention cookie name: %q", states[0].Message)
}
}
func TestCookieSizeRule_LoadFailure(t *testing.T) {
states := (&cookieSizeRule{}).Evaluate(t.Context(), &fakeObs{failGet: true}, nil)
if len(states) != 1 || states[0].Status != sdk.StatusError {
t.Fatalf("expected single error state, got %+v", states)
}
}