All checks were successful
check / check (push) Successful in 2m3s
Replace .golangci.yml with the canonical v2-schema config (default: all minus six disabled linters, lll 88, tests included) and bump every golangci-lint pin to v2.12.2: - Dockerfile: golangci/golangci-lint:v2.12.2-alpine (hash-pinned) - script/bootstrap: GOLANGCI_LINT_VERSION 2.12.2 with new linux-amd64/arm64 release-archive sha256 pins Fix all 747 findings the stricter config surfaces, with no behavior changes: t.Parallel() throughout the test suite, static sentinel errors and errors.Is comparisons, checked error returns, context propagation (contextcheck/noctx), 88-column wrapping, extracted constants and helpers for goconst/dupl/funlen/cyclop, exhaustive switch cases replicating existing defaults, and white-box test files renamed to *_internal_test.go for testpackage. Three nolint:tagliatelle directives preserve the existing snake_case JSON wire and on-disk metadata formats.
92 lines
2.3 KiB
Go
92 lines
2.3 KiB
Go
package session_test
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"sneak.berlin/go/pixa/internal/session"
|
|
)
|
|
|
|
// TestSessionCookieAttributesAlwaysSecure verifies that every cookie
|
|
// emitted by the session manager carries HttpOnly, Secure, and a
|
|
// SameSite mode of Lax or stricter. Session cookies contain the
|
|
// authentication state and must never be exposed to script (HttpOnly),
|
|
// sent over plaintext HTTP (Secure), or attached to cross-site
|
|
// requests (SameSite). Nothing may weaken these attributes.
|
|
//
|
|
// This covers both cookie-writing paths: CreateSession (the login
|
|
// set-cookie path) and ClearSession (the logout delete-cookie path).
|
|
func TestSessionCookieAttributesAlwaysSecure(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mgr, err := session.NewManager("test-signing-key-12345")
|
|
if err != nil {
|
|
t.Fatalf("NewManager() error = %v", err)
|
|
}
|
|
|
|
writePaths := []struct {
|
|
name string
|
|
setCookie func(t *testing.T, w http.ResponseWriter)
|
|
}{
|
|
{
|
|
name: "CreateSession",
|
|
setCookie: func(t *testing.T, w http.ResponseWriter) {
|
|
t.Helper()
|
|
|
|
err := mgr.CreateSession(w)
|
|
if err != nil {
|
|
t.Fatalf("CreateSession() error = %v", err)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "ClearSession",
|
|
setCookie: func(t *testing.T, w http.ResponseWriter) {
|
|
t.Helper()
|
|
mgr.ClearSession(w)
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, writePath := range writePaths {
|
|
t.Run(writePath.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
w := httptest.NewRecorder()
|
|
writePath.setCookie(t, w)
|
|
|
|
var sessionCookie *http.Cookie
|
|
|
|
for _, c := range w.Result().Cookies() {
|
|
if c.Name == session.CookieName {
|
|
sessionCookie = c
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
if sessionCookie == nil {
|
|
t.Fatalf("no cookie named %q was set", session.CookieName)
|
|
}
|
|
|
|
t.Logf("cookie attributes: HttpOnly=%v Secure=%v SameSite=%v",
|
|
sessionCookie.HttpOnly, sessionCookie.Secure, sessionCookie.SameSite)
|
|
|
|
if !sessionCookie.HttpOnly {
|
|
t.Error("session cookie must have HttpOnly set")
|
|
}
|
|
|
|
if !sessionCookie.Secure {
|
|
t.Error("session cookie must have Secure set")
|
|
}
|
|
|
|
if sessionCookie.SameSite != http.SameSiteLaxMode &&
|
|
sessionCookie.SameSite != http.SameSiteStrictMode {
|
|
t.Errorf("session cookie SameSite = %v, want Lax (%v) or Strict (%v)",
|
|
sessionCookie.SameSite, http.SameSiteLaxMode, http.SameSiteStrictMode)
|
|
}
|
|
})
|
|
}
|
|
}
|