// 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) } }