From 53b3c496126e1831410fa8e7821775780841926e Mon Sep 17 00:00:00 2001 From: Denozordec Date: Mon, 6 Jul 2026 23:28:14 +0700 Subject: [PATCH] refactor(settings): simplify settings query options and remove tenant dependency Updated the settings query options to eliminate the tenant ID parameter, streamlining the settings retrieval process. Adjusted the TenantSettingsComponent to reflect this change, ensuring it now queries settings without relying on tenant-specific data. This refactor enhances code clarity and reduces complexity in the settings management flow. --- apps/web/src/queries/settings.ts | 6 +-- apps/web/src/routes/_auth/tenant-settings.tsx | 5 +-- docs/access.md | 2 +- internal/httpapi/auth.go | 9 +++-- internal/httpapi/auth_dev_settings_test.go | 38 ++++++++++++++++++- 5 files changed, 45 insertions(+), 15 deletions(-) diff --git a/apps/web/src/queries/settings.ts b/apps/web/src/queries/settings.ts index 497091b..52f1dd1 100644 --- a/apps/web/src/queries/settings.ts +++ b/apps/web/src/queries/settings.ts @@ -42,14 +42,12 @@ export const BOOLEAN_SETTING_KEYS = new Set(['runtime_logs_auto export const settingsKeys = { all: ['settings'] as const, - tenant: (tenantId: string) => [...settingsKeys.all, tenantId] as const, } -export function settingsQueryOptions(tenantId?: string | null) { +export function settingsQueryOptions() { return queryOptions({ - queryKey: settingsKeys.tenant(tenantId ?? ''), + queryKey: settingsKeys.all, queryFn: () => apiJSON('/v1/settings'), - enabled: Boolean(tenantId), staleTime: 30_000, }) } diff --git a/apps/web/src/routes/_auth/tenant-settings.tsx b/apps/web/src/routes/_auth/tenant-settings.tsx index 49393b1..76dc885 100644 --- a/apps/web/src/routes/_auth/tenant-settings.tsx +++ b/apps/web/src/routes/_auth/tenant-settings.tsx @@ -39,7 +39,6 @@ import { settingsQueryOptions, type BirdSettingKey, } from '@/queries/settings' -import { authSessionQueryOptions } from '@/queries/auth' import { apiMutate } from '@/lib/api-client' export const Route = createFileRoute('/_auth/tenant-settings')({ @@ -72,9 +71,7 @@ const BIRD_LABELS: Record = { function TenantSettingsComponent() { const search = useSearch({ from: '/_auth/tenant-settings' }) - const sessionQ = useQuery(authSessionQueryOptions()) - const tenantId = sessionQ.data?.tenant_id ?? null - const settingsQ = useQuery(settingsQueryOptions(tenantId)) + const settingsQ = useQuery(settingsQueryOptions()) const qc = useQueryClient() const partitioned = settingsQ.data ? partitionSettings(settingsQ.data) : null diff --git a/docs/access.md b/docs/access.md index 29e2a30..f6c8b04 100644 --- a/docs/access.md +++ b/docs/access.md @@ -50,7 +50,7 @@ opkey|01ARZ3NDEKTSV4RRFFQ69G5FAV|operator,nodekey|01ARZ3NDEKTSV4RRFFQ69G5FAV|nod Если в store доступен демо-tenant (`DemoIDs`, обычно `EVOBGP_SEED_DEMO` не равен `0`), заголовок **`Authorization: Bearer dev`** даёт роль **`operator`** для этого tenant. **Не зависит** от `EVOBGP_DEV_INSECURE`. -Если токен `dev` также задан в `EVOBGP_API_KEYS` или таблице `api_key`, **приоритет у явной записи** (production tenant), а не у demo-shortcut. +Без demo-tenant токен `dev` может быть задан в `EVOBGP_API_KEYS` (break-glass). **Запрещено** в продакшене: не оставляйте demo-seed с известным токеном `dev` на боевых данных. Переменная `EVOBGP_DEV_INSECURE` в текущей версии **не влияет** на аутентификацию (оставлена в compose для совместимости; не включайте в production — см. SEC-02 в инженерных правилах). diff --git a/internal/httpapi/auth.go b/internal/httpapi/auth.go index be57402..b331bfb 100644 --- a/internal/httpapi/auth.go +++ b/internal/httpapi/auth.go @@ -81,15 +81,16 @@ func authFromKeyRecord(raw string, rec apiKeyRecord) Auth { } // resolveAuth maps a bearer token to tenant identity. -// For the literal token "dev", env/DB keys take precedence over the demo shortcut (devAuth). +// For the literal token "dev", the demo shortcut (devAuth) takes precedence when demo-seed +// is available; env/DB mapping is used only when demo tenant is absent. func (s *Server) resolveAuth(raw string) (Auth, bool) { if raw == "dev" { - if rec, ok := s.keyResolver.Lookup(raw); ok { - return authFromKeyRecord(raw, rec), true - } if a, ok := s.devAuth(); ok { return a, true } + if rec, ok := s.keyResolver.Lookup(raw); ok { + return authFromKeyRecord(raw, rec), true + } return Auth{}, false } rec, ok := s.keyResolver.Lookup(raw) diff --git a/internal/httpapi/auth_dev_settings_test.go b/internal/httpapi/auth_dev_settings_test.go index a8073d5..d91ab13 100644 --- a/internal/httpapi/auth_dev_settings_test.go +++ b/internal/httpapi/auth_dev_settings_test.go @@ -31,7 +31,7 @@ func TestBearerDevGetSettings(t *testing.T) { } } -func TestBearerDevPrefersEnvAPIKeyOverDemoTenant(t *testing.T) { +func TestBearerDevPrefersDemoTenantOverEnvKey(t *testing.T) { srv, err := New(Options{SeedDemo: true, BundleSeedHex: testBundleSeed}) if err != nil { t.Fatal(err) @@ -61,7 +61,41 @@ func TestBearerDevPrefersEnvAPIKeyOverDemoTenant(t *testing.T) { t.Fatal(err) } got, _ := body["tenant_id"].(string) + if got != demoTenant { + t.Fatalf("tenant_id=%q want demo tenant %q (env=%q)", got, demoTenant, otherTenant) + } +} + +func TestBearerDevFallsBackToEnvKeyWithoutDemo(t *testing.T) { + srv, err := New(Options{SeedDemo: false, BundleSeedHex: testBundleSeed}) + if err != nil { + t.Fatal(err) + } + defer srv.Close() + + otherTenant := "00000000-0000-4000-8000-000000000001" + mustSetTestAPIKeys(t, srv, "dev|"+otherTenant+"|operator") + + ts := httptest.NewServer(srv.Handler()) + defer ts.Close() + + req, _ := http.NewRequest(http.MethodGet, ts.URL+"/v1/auth/session", nil) + req.Header.Set("Authorization", "Bearer dev") + resp, err := ts.Client().Do(req) + if err != nil { + t.Fatal(err) + } + defer func() { _ = resp.Body.Close() }() + if resp.StatusCode != http.StatusOK { + b, _ := io.ReadAll(resp.Body) + t.Fatalf("session status=%d body=%s", resp.StatusCode, b) + } + var body map[string]any + if err := json.NewDecoder(resp.Body).Decode(&body); err != nil { + t.Fatal(err) + } + got, _ := body["tenant_id"].(string) if got != otherTenant { - t.Fatalf("tenant_id=%q want env key tenant %q (demo=%q)", got, otherTenant, demoTenant) + t.Fatalf("tenant_id=%q want env key tenant %q", got, otherTenant) } }