refactor(10.2-01): nest framework packages under modules
- Move remaining beach packages and embedded admin assets\n- Rewrite framework, example, build, and gate paths
This commit is contained in:
92
modules/surf/cors_coverage_test.go
Normal file
92
modules/surf/cors_coverage_test.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package surf
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Gap (d): pathScopedCORS with a path matching NONE of the configured
|
||||
// globs. TestCORSPathScopedHeaders already covers the two named acme
|
||||
// groups; this fixture is framework-only (/healthz vs api/*).
|
||||
|
||||
func TestCORSPathScopedNoMatchIndependentOfAcme(t *testing.T) {
|
||||
cfg := CORSConfig{
|
||||
Paths: []string{"api/*", "oauth/mcp/*"},
|
||||
AllowedMethods: []string{"*"},
|
||||
AllowedOrigins: []string{"*"},
|
||||
AllowedHeaders: []string{"*"},
|
||||
}
|
||||
inner := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
})
|
||||
h := pathScopedCORS(cfg, inner)
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/healthz", nil))
|
||||
if rec.Code != http.StatusNoContent {
|
||||
t.Fatalf("status = %d", rec.Code)
|
||||
}
|
||||
if got := rec.Header().Get("Access-Control-Allow-Origin"); got != "" {
|
||||
t.Fatalf("unmatched path must not set ACAO, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCORSAllowOriginExactAndPattern(t *testing.T) {
|
||||
cfg := CORSConfig{
|
||||
Paths: []string{"api/*"},
|
||||
AllowedMethods: []string{"GET", "POST"},
|
||||
AllowedOrigins: []string{"https://app.example.test"},
|
||||
AllowedOriginsPatterns: []string{`^https://.*\.example\.test$`},
|
||||
AllowedHeaders: []string{"Authorization", "Content-Type"},
|
||||
ExposedHeaders: []string{"X-RateLimit-Limit"},
|
||||
MaxAge: 600,
|
||||
SupportsCredentials: true,
|
||||
}
|
||||
inner := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
h := pathScopedCORS(cfg, inner)
|
||||
|
||||
t.Run("exact origin", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/items", nil)
|
||||
req.Header.Set("Origin", "https://app.example.test")
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
if rec.Header().Get("Access-Control-Allow-Origin") != "https://app.example.test" {
|
||||
t.Fatalf("ACAO = %q", rec.Header().Get("Access-Control-Allow-Origin"))
|
||||
}
|
||||
if rec.Header().Get("Vary") != "Origin" {
|
||||
t.Fatalf("Vary = %q", rec.Header().Get("Vary"))
|
||||
}
|
||||
if rec.Header().Get("Access-Control-Allow-Credentials") != "true" {
|
||||
t.Fatal("missing credentials header")
|
||||
}
|
||||
if rec.Header().Get("Access-Control-Max-Age") != "600" {
|
||||
t.Fatalf("Max-Age = %q", rec.Header().Get("Access-Control-Max-Age"))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("pattern origin", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodOptions, "/api/v1/items", nil)
|
||||
req.Header.Set("Origin", "https://admin.example.test")
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusNoContent {
|
||||
t.Fatalf("preflight status = %d", rec.Code)
|
||||
}
|
||||
if rec.Header().Get("Access-Control-Allow-Origin") != "https://admin.example.test" {
|
||||
t.Fatalf("ACAO = %q", rec.Header().Get("Access-Control-Allow-Origin"))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("disallowed origin", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/items", nil)
|
||||
req.Header.Set("Origin", "https://evil.test")
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
if got := rec.Header().Get("Access-Control-Allow-Origin"); got != "" {
|
||||
t.Fatalf("disallowed origin ACAO = %q", got)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user