mirror of
https://github.com/langgenius/dify.git
synced 2026-05-27 04:16:16 +08:00
feat(openapi): /apps/permitted — external-subject app discovery (EE)
Split route for dfoe_ external-SSO discovery, separate from /apps (dfoa_-only workspace catalog). Cross-tenant allow-list query: server calls Enterprise inner-API POST /inner/api/webapp/permitted-apps and hydrates app/tenant rows locally. New scope apps:read:permitted (no dual-meaning with apps:read). Route gated by @enterprise_only — 404 on CE — and validate_bearer(accept=ACCEPT_USER_EXT_SSO) — 403 on dfoa_. Query validator rejects workspace_id and tag (cross-tenant unresolvable); mode/name supported. EE inner-API wire-up depends on ee-2; the service-layer stub raises ServiceUnavailable until that endpoint ships. CLI dispatches between /apps and /apps/permitted client-side based on the bearer prefix in hosts.yml — see docs/specs/v1.0/apps.md §Subject dispatch. Verified via unit tests on AppPermittedListQuery and Scope wiring; HTTP integration tests deferred to ee-2 once the inner-API ships.
This commit is contained in:
@ -0,0 +1,44 @@
|
||||
"""Unit tests for AppPermittedListQuery — the /apps/permitted query validator.
|
||||
|
||||
Strict ConfigDict(extra='forbid'): cross-tenant tag/workspace_id are
|
||||
unresolvable, so the model must reject them as 422 instead of silently
|
||||
dropping them. Mode/name/page/limit have the same shape as AppListQuery.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from controllers.openapi.apps_permitted import AppPermittedListQuery
|
||||
|
||||
|
||||
def test_query_defaults_match_apps_list():
|
||||
q = AppPermittedListQuery.model_validate({})
|
||||
assert q.page == 1
|
||||
assert q.limit == 20
|
||||
assert q.mode is None
|
||||
assert q.name is None
|
||||
|
||||
|
||||
def test_query_rejects_workspace_id():
|
||||
"""workspace_id is meaningless for /permitted (cross-tenant); rejecting it
|
||||
forces CLI authors to drop the param rather than send it silently."""
|
||||
with pytest.raises(ValidationError):
|
||||
AppPermittedListQuery.model_validate({"workspace_id": "ws-1"})
|
||||
|
||||
|
||||
def test_query_rejects_tag():
|
||||
"""Tags are tenant-scoped; cross-tenant tag resolution is undefined."""
|
||||
with pytest.raises(ValidationError):
|
||||
AppPermittedListQuery.model_validate({"tag": "prod"})
|
||||
|
||||
|
||||
def test_query_validates_mode_against_app_mode():
|
||||
with pytest.raises(ValidationError):
|
||||
AppPermittedListQuery.model_validate({"mode": "not-a-mode"})
|
||||
|
||||
|
||||
def test_query_clamps_limit_at_max():
|
||||
with pytest.raises(ValidationError):
|
||||
AppPermittedListQuery.model_validate({"limit": 500})
|
||||
Reference in New Issue
Block a user