Удалены authenticateUIDemoToken, uiDemoToken/uiDemoTenantID/uiDemoEmail и их константы (demo-ui-shared-sqs-ngcloud-2026) — публичный путь входа в UI мимо JWT-валидации. seed.go теперь создаёт demo-тенанта со СЛУЧАЙНЫМИ кредами (tenant.Create), без захардкоженного SecretKey в исходнике. Тест TestJWTAuth_AllowsDemoToken заменён на TestJWTAuth_RejectsMissingToken.
64 lines
1.9 KiB
Go
64 lines
1.9 KiB
Go
// app/admin/admin_test.go
|
|
// Focused tests for UI auth and scoping
|
|
package admin
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"shared-sqs/app/tenant"
|
|
)
|
|
|
|
// TestJWTAuth_RejectsMissingToken verifies jwtAuth rejects a request without a token.
|
|
func TestJWTAuth_RejectsMissingToken(t *testing.T) {
|
|
store := tenant.NewTenantStore()
|
|
h := NewHandler(store, "admin-token")
|
|
req := httptest.NewRequest(http.MethodPost, "/ui/api/auth", strings.NewReader(`{}`))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
w := httptest.NewRecorder()
|
|
|
|
h.jwtAuth(w, req)
|
|
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Fatalf("jwtAuth() status = %d, want 400", w.Code)
|
|
}
|
|
}
|
|
|
|
// TestListTenants_UIContextReturnsOnlyOwnTenant verifies that UI API listing is scoped to the authenticated tenant.
|
|
func TestListTenants_UIContextReturnsOnlyOwnTenant(t *testing.T) {
|
|
store := tenant.NewTenantStore()
|
|
firstTenant, err := store.CreateFixed("demo-service", 10, "t-demo-test", "SSAK-demo-test", "demo-secret")
|
|
if err != nil {
|
|
t.Fatalf("CreateFixed(first): %v", err)
|
|
}
|
|
if _, err := store.CreateFixed("other-service", 10, "t-other-test", "SSAK-other-test", "other-secret"); err != nil {
|
|
t.Fatalf("CreateFixed(second): %v", err)
|
|
}
|
|
|
|
h := NewHandler(store, "admin-token")
|
|
req := httptest.NewRequest(http.MethodGet, "/ui/api/tenants", nil)
|
|
req = req.WithContext(context.WithValue(req.Context(), uiTenantContextKey, firstTenant))
|
|
w := httptest.NewRecorder()
|
|
|
|
h.listTenants(w, req)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("listTenants() status = %d, body = %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
var resp []map[string]any
|
|
if err := json.NewDecoder(w.Body).Decode(&resp); err != nil {
|
|
t.Fatalf("decode response: %v", err)
|
|
}
|
|
if len(resp) != 1 {
|
|
t.Fatalf("len(response) = %d, want 1", len(resp))
|
|
}
|
|
if got := resp[0]["id"]; got != firstTenant.ID {
|
|
t.Fatalf("response[0].id = %v, want %s", got, firstTenant.ID)
|
|
}
|
|
}
|