fix: address PR #589 review feedback for Login Flow v2
- Fix data loss in nc_auth_update_scopes: remove premature delete_app_password call; old password stays valid until upsert replaces it on successful re-provisioning - Replace assert with proper error return in nc_auth_check_status - Add lazy singleton for RefreshTokenStorage in auth_tools, scope_authorization, and context to avoid per-call re-initialization - Centralize _is_login_flow_mode() to get_settings().enable_login_flow and remove duplicate definitions and per-call os.getenv reads - Add dev-only comment to TOKEN_ENCRYPTION_KEY in docker-compose.yml - Gate OIDC build steps in CI behind matrix.needs-playwright - Add diagnostic step reporting Playwright skip count in CI Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,41 +4,17 @@ Tests the third enforcement mode in scope_authorization.py that checks
|
||||
application-level scopes stored alongside app passwords.
|
||||
"""
|
||||
|
||||
import os
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from nextcloud_mcp_server.auth.scope_authorization import (
|
||||
_get_stored_scopes,
|
||||
_is_login_flow_mode,
|
||||
)
|
||||
|
||||
pytestmark = pytest.mark.unit
|
||||
|
||||
|
||||
def test_is_login_flow_mode_disabled():
|
||||
"""Test that login flow mode is off by default."""
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert _is_login_flow_mode() is False
|
||||
|
||||
|
||||
def test_is_login_flow_mode_enabled():
|
||||
"""Test that login flow mode is enabled when env var is set."""
|
||||
with patch.dict(os.environ, {"ENABLE_LOGIN_FLOW": "true"}):
|
||||
assert _is_login_flow_mode() is True
|
||||
|
||||
|
||||
def test_is_login_flow_mode_case_insensitive():
|
||||
"""Test case insensitivity of the env var."""
|
||||
with patch.dict(os.environ, {"ENABLE_LOGIN_FLOW": "True"}):
|
||||
assert _is_login_flow_mode() is True
|
||||
with patch.dict(os.environ, {"ENABLE_LOGIN_FLOW": "TRUE"}):
|
||||
assert _is_login_flow_mode() is True
|
||||
with patch.dict(os.environ, {"ENABLE_LOGIN_FLOW": "false"}):
|
||||
assert _is_login_flow_mode() is False
|
||||
|
||||
|
||||
async def test_get_stored_scopes_with_scopes():
|
||||
"""Test getting specific scopes from storage."""
|
||||
mock_storage = AsyncMock()
|
||||
@@ -49,10 +25,9 @@ async def test_get_stored_scopes_with_scopes():
|
||||
"created_at": 1000,
|
||||
"updated_at": 1000,
|
||||
}
|
||||
mock_storage.initialize = AsyncMock()
|
||||
|
||||
with patch(
|
||||
"nextcloud_mcp_server.auth.storage.RefreshTokenStorage.from_env",
|
||||
"nextcloud_mcp_server.auth.scope_authorization._get_scope_storage",
|
||||
return_value=mock_storage,
|
||||
):
|
||||
result = await _get_stored_scopes("alice")
|
||||
@@ -70,10 +45,9 @@ async def test_get_stored_scopes_null_scopes():
|
||||
"created_at": 1000,
|
||||
"updated_at": 1000,
|
||||
}
|
||||
mock_storage.initialize = AsyncMock()
|
||||
|
||||
with patch(
|
||||
"nextcloud_mcp_server.auth.storage.RefreshTokenStorage.from_env",
|
||||
"nextcloud_mcp_server.auth.scope_authorization._get_scope_storage",
|
||||
return_value=mock_storage,
|
||||
):
|
||||
result = await _get_stored_scopes("bob")
|
||||
@@ -85,10 +59,9 @@ async def test_get_stored_scopes_no_password():
|
||||
"""Test that missing app password returns None."""
|
||||
mock_storage = AsyncMock()
|
||||
mock_storage.get_app_password_with_scopes.return_value = None
|
||||
mock_storage.initialize = AsyncMock()
|
||||
|
||||
with patch(
|
||||
"nextcloud_mcp_server.auth.storage.RefreshTokenStorage.from_env",
|
||||
"nextcloud_mcp_server.auth.scope_authorization._get_scope_storage",
|
||||
return_value=mock_storage,
|
||||
):
|
||||
result = await _get_stored_scopes("nobody")
|
||||
@@ -99,10 +72,10 @@ async def test_get_stored_scopes_no_password():
|
||||
async def test_get_stored_scopes_storage_error():
|
||||
"""Test that storage errors return None (fail-closed)."""
|
||||
mock_storage = AsyncMock()
|
||||
mock_storage.initialize.side_effect = RuntimeError("DB error")
|
||||
mock_storage.get_app_password_with_scopes.side_effect = RuntimeError("DB error")
|
||||
|
||||
with patch(
|
||||
"nextcloud_mcp_server.auth.storage.RefreshTokenStorage.from_env",
|
||||
"nextcloud_mcp_server.auth.scope_authorization._get_scope_storage",
|
||||
return_value=mock_storage,
|
||||
):
|
||||
result = await _get_stored_scopes("alice")
|
||||
|
||||
Reference in New Issue
Block a user