- archive/internal/retentionapi.CORS: erlaubt genau einen konfigurierten Origin (kein Wildcard), beantwortet OPTIONS-Preflights direkt - cmd/retention-api: neue Pflicht-Env NEXARCH_RETENTION_CORS_ALLOWED_ORIGIN, mux mit CORS umschlossen - gefunden durch Sichtpruefung des laufenden RET-06-Frontends: curl umgeht CORS, ein echter Browser haette den Fetch blockiert - weder Go- noch Vitest-Tests konnten das strukturell erfassen - 3 Tests: erlaubter Origin bekommt Header, Preflight korrekt beantwortet, fremder Origin bekommt keinen Header - real deployed auf 131, genau der bei der Sichtpruefung fehlgeschlagene Aufruf (Origin http://127.0.0.1:3099) liefert jetzt 200 mit korrektem Access-Control-Allow-Origin Pruefungen siehe archive/docs/RET-10-PRUEFPROTOKOLL.md
87 lines
3.0 KiB
Go
87 lines
3.0 KiB
Go
package retentionapi
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
const testAllowedOrigin = "http://localhost:3099"
|
|
|
|
func noopHandler() http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
}
|
|
|
|
// TestCORS_AllowedOriginGetsAccessControlHeader ist die geforderte
|
|
// Pflichtprüfung: ein echter Browser-Fetch (simuliert über den Origin-
|
|
// Header, den nur ein Browser automatisch setzt) erhält die nötigen
|
|
// CORS-Header, die Same-Origin-Policy blockiert den Zugriff nicht mehr.
|
|
func TestCORS_AllowedOriginGetsAccessControlHeader(t *testing.T) {
|
|
handler := CORS(testAllowedOrigin, noopHandler())
|
|
server := httptest.NewServer(handler)
|
|
defer server.Close()
|
|
|
|
req, _ := http.NewRequest(http.MethodGet, server.URL, nil)
|
|
req.Header.Set("Origin", testAllowedOrigin)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("get: %v", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
if got := resp.Header.Get("Access-Control-Allow-Origin"); got != testAllowedOrigin {
|
|
t.Fatalf("Access-Control-Allow-Origin = %q, want %q", got, testAllowedOrigin)
|
|
}
|
|
}
|
|
|
|
// TestCORS_PreflightRequestForPostEndpoint ist die geforderte
|
|
// Pflichtprüfung: OPTIONS-Preflight liefert korrekte CORS-Header für
|
|
// POST /retention-classes.
|
|
func TestCORS_PreflightRequestForPostEndpoint(t *testing.T) {
|
|
handler := CORS(testAllowedOrigin, noopHandler())
|
|
server := httptest.NewServer(handler)
|
|
defer server.Close()
|
|
|
|
req, _ := http.NewRequest(http.MethodOptions, server.URL+"/retention-classes", nil)
|
|
req.Header.Set("Origin", testAllowedOrigin)
|
|
req.Header.Set("Access-Control-Request-Method", "POST")
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("options: %v", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
if resp.StatusCode != http.StatusNoContent {
|
|
t.Fatalf("preflight status = %d, want 204", resp.StatusCode)
|
|
}
|
|
if got := resp.Header.Get("Access-Control-Allow-Origin"); got != testAllowedOrigin {
|
|
t.Fatalf("Access-Control-Allow-Origin = %q, want %q", got, testAllowedOrigin)
|
|
}
|
|
if got := resp.Header.Get("Access-Control-Allow-Methods"); got == "" {
|
|
t.Fatal("Access-Control-Allow-Methods fehlt in der preflight-antwort")
|
|
}
|
|
}
|
|
|
|
// TestCORS_UnconfiguredOriginGetsNoAccessControlHeader ist die geforderte
|
|
// Pflichtprüfung: Fetch von einem NICHT konfigurierten Origin bleibt
|
|
// blockiert — kein Wildcard-Leck.
|
|
func TestCORS_UnconfiguredOriginGetsNoAccessControlHeader(t *testing.T) {
|
|
handler := CORS(testAllowedOrigin, noopHandler())
|
|
server := httptest.NewServer(handler)
|
|
defer server.Close()
|
|
|
|
req, _ := http.NewRequest(http.MethodGet, server.URL, nil)
|
|
req.Header.Set("Origin", "http://boesartige-seite.example")
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("get: %v", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
if got := resp.Header.Get("Access-Control-Allow-Origin"); got != "" {
|
|
t.Fatalf("Access-Control-Allow-Origin haette bei fremdem origin leer sein muessen, war %q", got)
|
|
}
|
|
}
|