dify/api/tests/unit_tests/services/test_credential_permission_service.py
YungLe 86497045c9
feat: per-credential visibility control for plugin credentials (#35468)
Co-authored-by: Yang <yang@Yangs-MacBook-Pro.local>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 05:56:18 +00:00

104 lines
3.8 KiB
Python

"""Unit tests for CredentialPermissionService.
Tests the visibility filtering logic, partial-member read path,
and admin bypass behavior.
"""
from types import SimpleNamespace
from unittest.mock import MagicMock, patch
from uuid import uuid4
import pytest
from sqlalchemy import select
from models.credential_permission import CredentialType
from services.credential_permission_service import CredentialPermissionService
@pytest.fixture
def tenant_id():
return str(uuid4())
@pytest.fixture
def user_id():
return str(uuid4())
@pytest.fixture
def other_user_id():
return str(uuid4())
@pytest.fixture
def credential_id():
return str(uuid4())
class TestGetPartialMemberList:
def test_returns_empty_when_no_permissions(self, credential_id):
with patch("services.credential_permission_service.db") as mock_db:
mock_db.session.scalars.return_value.all.return_value = []
result = CredentialPermissionService.get_partial_member_list(
credential_id, CredentialType.TRIGGER_SUBSCRIPTION
)
assert result == []
def test_returns_account_ids(self, credential_id, user_id, other_user_id):
with patch("services.credential_permission_service.db") as mock_db:
mock_db.session.scalars.return_value.all.return_value = [user_id, other_user_id]
result = CredentialPermissionService.get_partial_member_list(
credential_id, CredentialType.TRIGGER_SUBSCRIPTION
)
assert set(result) == {user_id, other_user_id}
class TestApplyVisibilityFilter:
"""Test the visibility filter logic using mock model columns."""
def _make_mock_columns(self):
"""Create mock model columns for testing."""
model_id = MagicMock(name="id_column")
model_user_id = MagicMock(name="user_id_column")
model_visibility = MagicMock(name="visibility_column")
return model_id, model_user_id, model_visibility
def _make_user(self, user_id: str, is_admin: bool):
return SimpleNamespace(id=user_id, is_admin_or_owner=is_admin)
def test_admin_gets_filtered_too(self, user_id):
"""Admin should NOT bypass visibility — personal credentials are private regardless of role."""
from models.trigger import TriggerSubscription
query = select(TriggerSubscription)
result = CredentialPermissionService.apply_visibility_filter(
query,
model_id_column=TriggerSubscription.id,
model_user_id_column=TriggerSubscription.user_id,
model_visibility_column=TriggerSubscription.visibility,
credential_type=CredentialType.TRIGGER_SUBSCRIPTION,
user=self._make_user(user_id, is_admin=True),
)
# No admin bypass: query should have WHERE clause
compiled = str(result.compile(compile_kwargs={"literal_binds": True}))
assert "WHERE" in compiled
def test_non_admin_adds_filter_on_real_model(self, user_id):
"""Non-admin should get a filtered query when using real SQLAlchemy columns."""
from models.trigger import TriggerSubscription
query = select(TriggerSubscription)
result = CredentialPermissionService.apply_visibility_filter(
query,
model_id_column=TriggerSubscription.id,
model_user_id_column=TriggerSubscription.user_id,
model_visibility_column=TriggerSubscription.visibility,
credential_type=CredentialType.TRIGGER_SUBSCRIPTION,
user=self._make_user(user_id, is_admin=False),
)
# The compiled SQL should include a WHERE clause referencing user_id and visibility
compiled = str(result.compile(compile_kwargs={"literal_binds": True}))
assert "WHERE" in compiled
assert "visibility" in compiled
assert "user_id" in compiled