mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 04:51:51 +00:00
274 lines
9.1 KiB
Python
274 lines
9.1 KiB
Python
import os
|
|
from unittest import mock
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
from prowler.providers.common.models import Connection
|
|
from prowler.providers.vercel.exceptions.exceptions import (
|
|
VercelAuthenticationError,
|
|
VercelCredentialsError,
|
|
)
|
|
from prowler.providers.vercel.models import VercelIdentityInfo, VercelSession
|
|
from prowler.providers.vercel.vercel_provider import VercelProvider
|
|
from tests.providers.vercel.vercel_fixtures import (
|
|
API_TOKEN,
|
|
TEAM_ID,
|
|
TEAM_NAME,
|
|
TEAM_SLUG,
|
|
USER_EMAIL,
|
|
USER_ID,
|
|
USERNAME,
|
|
)
|
|
|
|
|
|
class TestVercelProviderSetupSession:
|
|
def test_setup_session_with_env_var(self):
|
|
with mock.patch.dict(os.environ, {"VERCEL_TOKEN": API_TOKEN}, clear=False):
|
|
session = VercelProvider.setup_session()
|
|
|
|
assert isinstance(session, VercelSession)
|
|
assert session.token == API_TOKEN
|
|
assert session.http_session is not None
|
|
|
|
def test_setup_session_with_api_token_param(self):
|
|
with mock.patch.dict(os.environ, {}, clear=True):
|
|
session = VercelProvider.setup_session(api_token=API_TOKEN)
|
|
|
|
assert isinstance(session, VercelSession)
|
|
assert session.token == API_TOKEN
|
|
assert session.http_session is not None
|
|
|
|
def test_setup_session_with_team_id_param(self):
|
|
with mock.patch.dict(os.environ, {}, clear=True):
|
|
session = VercelProvider.setup_session(api_token=API_TOKEN, team_id=TEAM_ID)
|
|
|
|
assert session.token == API_TOKEN
|
|
assert session.team_id == TEAM_ID
|
|
|
|
def test_setup_session_no_credentials_raises(self):
|
|
with mock.patch.dict(os.environ, {}, clear=True):
|
|
os.environ.pop("VERCEL_TOKEN", None)
|
|
with pytest.raises(VercelCredentialsError):
|
|
VercelProvider.setup_session()
|
|
|
|
def test_setup_session_team_from_env(self):
|
|
with mock.patch.dict(
|
|
os.environ, {"VERCEL_TOKEN": API_TOKEN, "VERCEL_TEAM": TEAM_ID}
|
|
):
|
|
session = VercelProvider.setup_session()
|
|
|
|
assert session.team_id == TEAM_ID
|
|
|
|
|
|
class TestVercelProviderSetupIdentity:
|
|
def test_setup_identity_with_team(self):
|
|
mock_session = VercelSession(
|
|
token=API_TOKEN, team_id=TEAM_ID, http_session=MagicMock()
|
|
)
|
|
|
|
# Mock user response
|
|
user_response = MagicMock()
|
|
user_response.status_code = 200
|
|
user_response.json.return_value = {
|
|
"user": {
|
|
"id": USER_ID,
|
|
"username": USERNAME,
|
|
"email": USER_EMAIL,
|
|
}
|
|
}
|
|
user_response.raise_for_status = MagicMock()
|
|
|
|
# Mock team response
|
|
team_response = MagicMock()
|
|
team_response.status_code = 200
|
|
team_response.json.return_value = {
|
|
"id": TEAM_ID,
|
|
"name": TEAM_NAME,
|
|
"slug": TEAM_SLUG,
|
|
}
|
|
team_response.raise_for_status = MagicMock()
|
|
|
|
def mock_get(url, **kwargs):
|
|
if "/v2/user" in url:
|
|
return user_response
|
|
if f"/v2/teams/{TEAM_ID}" in url:
|
|
return team_response
|
|
return MagicMock()
|
|
|
|
mock_session.http_session.get = mock_get
|
|
|
|
identity = VercelProvider.setup_identity(mock_session)
|
|
|
|
assert isinstance(identity, VercelIdentityInfo)
|
|
assert identity.user_id == USER_ID
|
|
assert identity.username == USERNAME
|
|
assert identity.email == USER_EMAIL
|
|
assert identity.team is not None
|
|
assert identity.team.id == TEAM_ID
|
|
assert identity.team.name == TEAM_NAME
|
|
assert identity.team.slug == TEAM_SLUG
|
|
|
|
def test_setup_identity_personal_account(self):
|
|
mock_session = VercelSession(
|
|
token=API_TOKEN, team_id=None, http_session=MagicMock()
|
|
)
|
|
|
|
user_response = MagicMock()
|
|
user_response.status_code = 200
|
|
user_response.json.return_value = {
|
|
"user": {
|
|
"id": USER_ID,
|
|
"username": USERNAME,
|
|
"email": USER_EMAIL,
|
|
}
|
|
}
|
|
user_response.raise_for_status = MagicMock()
|
|
|
|
mock_session.http_session.get = MagicMock(return_value=user_response)
|
|
|
|
identity = VercelProvider.setup_identity(mock_session)
|
|
|
|
assert identity.team is None
|
|
assert identity.user_id == USER_ID
|
|
|
|
|
|
class TestVercelProviderValidateCredentials:
|
|
def test_valid_credentials(self):
|
|
mock_session = VercelSession(
|
|
token=API_TOKEN, team_id=None, http_session=MagicMock()
|
|
)
|
|
|
|
response = MagicMock()
|
|
response.status_code = 200
|
|
response.raise_for_status = MagicMock()
|
|
mock_session.http_session.get = MagicMock(return_value=response)
|
|
|
|
# Should not raise
|
|
VercelProvider.validate_credentials(mock_session)
|
|
|
|
def test_invalid_token_raises(self):
|
|
mock_session = VercelSession(
|
|
token="invalid", team_id=None, http_session=MagicMock()
|
|
)
|
|
|
|
response = MagicMock()
|
|
response.status_code = 401
|
|
mock_session.http_session.get = MagicMock(return_value=response)
|
|
|
|
with pytest.raises(VercelAuthenticationError):
|
|
VercelProvider.validate_credentials(mock_session)
|
|
|
|
def test_forbidden_raises(self):
|
|
mock_session = VercelSession(
|
|
token=API_TOKEN, team_id=None, http_session=MagicMock()
|
|
)
|
|
|
|
response = MagicMock()
|
|
response.status_code = 403
|
|
mock_session.http_session.get = MagicMock(return_value=response)
|
|
|
|
with pytest.raises(VercelAuthenticationError):
|
|
VercelProvider.validate_credentials(mock_session)
|
|
|
|
|
|
class TestVercelProviderTestConnection:
|
|
@patch.object(VercelProvider, "validate_credentials")
|
|
@patch.object(VercelProvider, "setup_session")
|
|
def test_successful_connection(self, mock_setup_session, mock_validate):
|
|
mock_setup_session.return_value = VercelSession(
|
|
token=API_TOKEN, team_id=None, http_session=MagicMock()
|
|
)
|
|
mock_validate.return_value = None
|
|
|
|
result = VercelProvider.test_connection(raise_on_exception=False)
|
|
|
|
assert isinstance(result, Connection)
|
|
assert result.is_connected is True
|
|
|
|
@patch.object(VercelProvider, "validate_credentials")
|
|
@patch.object(VercelProvider, "setup_session")
|
|
def test_successful_connection_with_params(self, mock_setup_session, mock_validate):
|
|
mock_setup_session.return_value = VercelSession(
|
|
token=API_TOKEN, team_id=TEAM_ID, http_session=MagicMock()
|
|
)
|
|
mock_validate.return_value = None
|
|
|
|
result = VercelProvider.test_connection(
|
|
api_token=API_TOKEN, team_id=TEAM_ID, raise_on_exception=False
|
|
)
|
|
|
|
assert isinstance(result, Connection)
|
|
assert result.is_connected is True
|
|
mock_setup_session.assert_called_once_with(api_token=API_TOKEN, team_id=TEAM_ID)
|
|
|
|
@patch.object(VercelProvider, "setup_session")
|
|
def test_failed_connection_no_credentials(self, mock_setup_session):
|
|
mock_setup_session.side_effect = VercelCredentialsError(
|
|
message="No credentials"
|
|
)
|
|
|
|
result = VercelProvider.test_connection(raise_on_exception=False)
|
|
|
|
assert isinstance(result, Connection)
|
|
assert result.is_connected is False
|
|
assert result.error is not None
|
|
|
|
@patch.object(VercelProvider, "setup_session")
|
|
def test_failed_connection_raises(self, mock_setup_session):
|
|
mock_setup_session.side_effect = VercelCredentialsError(
|
|
message="No credentials"
|
|
)
|
|
|
|
with pytest.raises(VercelCredentialsError):
|
|
VercelProvider.test_connection(raise_on_exception=True)
|
|
|
|
|
|
class TestVercelSessionTokenSecurity:
|
|
"""The Vercel API token must never leak through serialization or repr."""
|
|
|
|
def test_token_is_still_accessible_as_attribute(self):
|
|
session = VercelSession(token=API_TOKEN, team_id=TEAM_ID)
|
|
|
|
assert session.token == API_TOKEN
|
|
|
|
def test_token_excluded_from_dict(self):
|
|
session = VercelSession(token=API_TOKEN, team_id=TEAM_ID)
|
|
|
|
serialized = session.dict()
|
|
|
|
assert "token" not in serialized
|
|
assert API_TOKEN not in str(serialized)
|
|
assert serialized["team_id"] == TEAM_ID
|
|
|
|
def test_token_excluded_from_model_dump(self):
|
|
session = VercelSession(token=API_TOKEN, team_id=TEAM_ID)
|
|
|
|
serialized = session.model_dump()
|
|
|
|
assert "token" not in serialized
|
|
assert API_TOKEN not in str(serialized)
|
|
|
|
def test_token_excluded_from_json(self):
|
|
session = VercelSession(token=API_TOKEN, team_id=TEAM_ID)
|
|
|
|
serialized = session.json()
|
|
|
|
assert "token" not in serialized
|
|
assert API_TOKEN not in serialized
|
|
|
|
def test_token_excluded_from_model_dump_json(self):
|
|
session = VercelSession(token=API_TOKEN, team_id=TEAM_ID)
|
|
|
|
serialized = session.model_dump_json()
|
|
|
|
assert "token" not in serialized
|
|
assert API_TOKEN not in serialized
|
|
|
|
def test_token_excluded_from_repr_and_str(self):
|
|
session = VercelSession(token=API_TOKEN, team_id=TEAM_ID)
|
|
|
|
assert API_TOKEN not in repr(session)
|
|
assert API_TOKEN not in str(session)
|
|
assert "token" not in repr(session)
|