refactor(core): lift Settings, TokenManager, and tool-credentials into crewai-core

- New crewai_core.{settings,token_manager,tool_credentials} absorb the previously
  duplicated Settings class (~200 LOC), TokenManager (~185 LOC), and
  build_env_with_*_credentials helpers from both crewai and crewai-cli.
- crewai_core.constants gains the OAuth2/enterprise URL constants.
- crewai.settings, crewai.auth.token_manager, crewai_cli.config, and
  crewai_cli.shared.token_manager are now thin re-export shims (deprecation
  warnings on the crewai.* paths; crewai_cli.* paths kept silent re-exports).
- Internal callers (plus_api, auth.token, auth.oauth2, agent_utils,
  trace_batch_manager) migrated to crewai_core.* imports.
- Tests updated to patch crewai_core.{settings,token_manager}.* paths.
- crewai-core gains pydantic, cryptography, tomli deps; crewai-cli's redundant
  cryptography dep can stay (still imported by crewai_cli.shared.token_manager
  shim users) — no behavior change.
- Standalone CLI smoke still passes; crewai's full mypy (471 files) clean.
This commit is contained in:
Greyson Lalonde
2026-05-05 14:20:41 +08:00
parent 8b641014aa
commit fb045534aa
22 changed files with 557 additions and 937 deletions

View File

@@ -9,20 +9,20 @@ from unittest.mock import patch
from cryptography.fernet import Fernet
from crewai_cli.shared.token_manager import TokenManager
from crewai_core.token_manager import TokenManager
class TestTokenManager(unittest.TestCase):
"""Test cases for TokenManager."""
@patch("crewai_cli.shared.token_manager.TokenManager._get_or_create_key")
@patch("crewai_core.token_manager.TokenManager._get_or_create_key")
def setUp(self, mock_get_key: unittest.mock.MagicMock) -> None:
"""Set up test fixtures."""
mock_get_key.return_value = Fernet.generate_key()
self.token_manager = TokenManager()
@patch("crewai_cli.shared.token_manager.TokenManager._read_secure_file")
@patch("crewai_cli.shared.token_manager.TokenManager._get_or_create_key")
@patch("crewai_core.token_manager.TokenManager._read_secure_file")
@patch("crewai_core.token_manager.TokenManager._get_or_create_key")
def test_get_or_create_key_existing(
self,
mock_get_or_create: unittest.mock.MagicMock,
@@ -44,7 +44,7 @@ class TestTokenManager(unittest.TestCase):
with (
patch.object(self.token_manager, "_read_secure_file", return_value=None) as mock_read,
patch.object(self.token_manager, "_atomic_create_secure_file", return_value=True) as mock_atomic_create,
patch("crewai_cli.shared.token_manager.Fernet.generate_key", return_value=mock_key) as mock_generate,
patch("crewai_core.token_manager.Fernet.generate_key", return_value=mock_key) as mock_generate,
):
result = self.token_manager._get_or_create_key()
@@ -61,14 +61,14 @@ class TestTokenManager(unittest.TestCase):
with (
patch.object(self.token_manager, "_read_secure_file", side_effect=[None, their_key]) as mock_read,
patch.object(self.token_manager, "_atomic_create_secure_file", return_value=False) as mock_atomic_create,
patch("crewai_cli.shared.token_manager.Fernet.generate_key", return_value=our_key),
patch("crewai_core.token_manager.Fernet.generate_key", return_value=our_key),
):
result = self.token_manager._get_or_create_key()
self.assertEqual(result, their_key)
self.assertEqual(mock_read.call_count, 2)
@patch("crewai_cli.shared.token_manager.TokenManager._atomic_write_secure_file")
@patch("crewai_core.token_manager.TokenManager._atomic_write_secure_file")
def test_save_tokens(
self, mock_write: unittest.mock.MagicMock
) -> None:
@@ -87,7 +87,7 @@ class TestTokenManager(unittest.TestCase):
expiration = datetime.fromisoformat(data["expiration"])
self.assertEqual(expiration, datetime.fromtimestamp(expires_at))
@patch("crewai_cli.shared.token_manager.TokenManager._read_secure_file")
@patch("crewai_core.token_manager.TokenManager._read_secure_file")
def test_get_token_valid(
self, mock_read: unittest.mock.MagicMock
) -> None:
@@ -102,7 +102,7 @@ class TestTokenManager(unittest.TestCase):
self.assertEqual(result, access_token)
@patch("crewai_cli.shared.token_manager.TokenManager._read_secure_file")
@patch("crewai_core.token_manager.TokenManager._read_secure_file")
def test_get_token_expired(
self, mock_read: unittest.mock.MagicMock
) -> None:
@@ -117,7 +117,7 @@ class TestTokenManager(unittest.TestCase):
self.assertIsNone(result)
@patch("crewai_cli.shared.token_manager.TokenManager._read_secure_file")
@patch("crewai_core.token_manager.TokenManager._read_secure_file")
def test_get_token_not_found(
self, mock_read: unittest.mock.MagicMock
) -> None:
@@ -128,7 +128,7 @@ class TestTokenManager(unittest.TestCase):
self.assertIsNone(result)
@patch("crewai_cli.shared.token_manager.TokenManager._delete_secure_file")
@patch("crewai_core.token_manager.TokenManager._delete_secure_file")
def test_clear_tokens(
self, mock_delete: unittest.mock.MagicMock
) -> None:
@@ -158,7 +158,7 @@ class TestAtomicFileOperations(unittest.TestCase):
import shutil
shutil.rmtree(self.temp_dir, ignore_errors=True)
@patch("crewai_cli.shared.token_manager.TokenManager._get_or_create_key")
@patch("crewai_core.token_manager.TokenManager._get_or_create_key")
def test_atomic_create_new_file(
self, mock_get_key: unittest.mock.MagicMock
) -> None:
@@ -174,7 +174,7 @@ class TestAtomicFileOperations(unittest.TestCase):
self.assertEqual(file_path.read_bytes(), b"content")
self.assertEqual(file_path.stat().st_mode & 0o777, 0o600)
@patch("crewai_cli.shared.token_manager.TokenManager._get_or_create_key")
@patch("crewai_core.token_manager.TokenManager._get_or_create_key")
def test_atomic_create_existing_file(
self, mock_get_key: unittest.mock.MagicMock
) -> None:
@@ -191,7 +191,7 @@ class TestAtomicFileOperations(unittest.TestCase):
self.assertFalse(result)
self.assertEqual(file_path.read_bytes(), b"original")
@patch("crewai_cli.shared.token_manager.TokenManager._get_or_create_key")
@patch("crewai_core.token_manager.TokenManager._get_or_create_key")
def test_atomic_write_new_file(
self, mock_get_key: unittest.mock.MagicMock
) -> None:
@@ -206,7 +206,7 @@ class TestAtomicFileOperations(unittest.TestCase):
self.assertEqual(file_path.read_bytes(), b"content")
self.assertEqual(file_path.stat().st_mode & 0o777, 0o600)
@patch("crewai_cli.shared.token_manager.TokenManager._get_or_create_key")
@patch("crewai_core.token_manager.TokenManager._get_or_create_key")
def test_atomic_write_overwrites(
self, mock_get_key: unittest.mock.MagicMock
) -> None:
@@ -221,7 +221,7 @@ class TestAtomicFileOperations(unittest.TestCase):
self.assertEqual(file_path.read_bytes(), b"new content")
@patch("crewai_cli.shared.token_manager.TokenManager._get_or_create_key")
@patch("crewai_core.token_manager.TokenManager._get_or_create_key")
def test_atomic_write_no_temp_file_on_success(
self, mock_get_key: unittest.mock.MagicMock
) -> None:
@@ -235,7 +235,7 @@ class TestAtomicFileOperations(unittest.TestCase):
temp_files = list(Path(self.temp_dir).glob(".test.txt.*"))
self.assertEqual(len(temp_files), 0)
@patch("crewai_cli.shared.token_manager.TokenManager._get_or_create_key")
@patch("crewai_core.token_manager.TokenManager._get_or_create_key")
def test_read_secure_file_exists(
self, mock_get_key: unittest.mock.MagicMock
) -> None:
@@ -250,7 +250,7 @@ class TestAtomicFileOperations(unittest.TestCase):
self.assertEqual(result, b"content")
@patch("crewai_cli.shared.token_manager.TokenManager._get_or_create_key")
@patch("crewai_core.token_manager.TokenManager._get_or_create_key")
def test_read_secure_file_not_exists(
self, mock_get_key: unittest.mock.MagicMock
) -> None:
@@ -262,7 +262,7 @@ class TestAtomicFileOperations(unittest.TestCase):
self.assertIsNone(result)
@patch("crewai_cli.shared.token_manager.TokenManager._get_or_create_key")
@patch("crewai_core.token_manager.TokenManager._get_or_create_key")
def test_delete_secure_file_exists(
self, mock_get_key: unittest.mock.MagicMock
) -> None:
@@ -277,7 +277,7 @@ class TestAtomicFileOperations(unittest.TestCase):
self.assertFalse(file_path.exists())
@patch("crewai_cli.shared.token_manager.TokenManager._get_or_create_key")
@patch("crewai_core.token_manager.TokenManager._get_or_create_key")
def test_delete_secure_file_not_exists(
self, mock_get_key: unittest.mock.MagicMock
) -> None: