-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Aleksandr Chikovani
committed
Aug 14, 2024
1 parent
a6bc386
commit 4421864
Showing
12 changed files
with
339 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
[run] | ||
source = ./ | ||
omit = mlflow_oidc_auth/tests/*,mlflow_oidc_auth/db/migrations/versions/* | ||
omit = mlflow_oidc_auth/tests/*,mlflow_oidc_auth/db/migrations/versions/*,mlflow_oidc_auth/app.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
name: Unit tests | ||
on: | ||
pull_request: | ||
types: | ||
- opened | ||
- edited | ||
- reopened | ||
- synchronize | ||
jobs: | ||
python-tests: | ||
name: Run python tests | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 | ||
with: | ||
fetch-depth: 0 | ||
- name: Set up Python | ||
uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1 | ||
with: | ||
python-version: 3.11 | ||
- name: Install build dependencies | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install tox | ||
tox -e py | ||
- name: Build coverage file | ||
run: | | ||
tox -e py | ||
# pytest --cache-clear --junitxml=coverage.xml --cov-report=term-missing:skip-covered --cov=mlflow_oidc_auth > pytest-coverage.txt | ||
- name: Override Coverage Source Path for Sonar | ||
run: sed -i "s@<source>/home/runner/work/mlflow-oidc-auth/mlflow-oidc-auth</source>@<source>/github/workspace</source>@g" /home/runner/work/mlflow-oidc-auth/mlflow-oidc-auth/coverage.xml | ||
- name: debug cov | ||
run: | | ||
pwd | ||
ls -alh | ||
head -n50 coverage.xml | ||
- name: SonarCloud Scan | ||
uses: SonarSource/sonarcloud-github-action@e44258b109568baa0df60ed515909fc6c72cba92 # v2.3.0 | ||
env: | ||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | ||
# todo: remove GH App |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
from unittest import mock | ||
|
||
|
||
""" | ||
AppConfig initiates it's values on import. | ||
This test is to ensure that all expected properties are present. | ||
""" | ||
|
||
|
||
class TestAppConfig: | ||
MOCK_OIDC_RESPONSE = { | ||
"authorization_endpoint": "https://example.com/auth", | ||
"token_endpoint": "https://example.com/token", | ||
"userinfo_endpoint": "https://example.com/userinfo", | ||
} | ||
MOCK_OIDC_DISCOVERY_URL = "https://example.com/.well-known/openid-configuration" | ||
|
||
@mock.patch("requests.get") | ||
def test_ext_call(self, mock_get, monkeypatch): | ||
mock_response = mock_get.return_value | ||
mock_response.json.return_value = self.MOCK_OIDC_RESPONSE | ||
monkeypatch.setenv("OIDC_DISCOVERY_URL", self.MOCK_OIDC_DISCOVERY_URL) | ||
|
||
from mlflow_oidc_auth.config import AppConfig | ||
|
||
conf = AppConfig | ||
|
||
assert conf.OIDC_AUTHORIZATION_URL == self.MOCK_OIDC_RESPONSE["authorization_endpoint"] | ||
|
||
mock_get.assert_called_once_with(self.MOCK_OIDC_DISCOVERY_URL) | ||
assert conf.OIDC_TOKEN_URL == self.MOCK_OIDC_RESPONSE["token_endpoint"] | ||
assert conf.OIDC_USER_URL == self.MOCK_OIDC_RESPONSE["userinfo_endpoint"] | ||
|
||
def test_configurations_presented(self): | ||
from mlflow_oidc_auth.config import AppConfig | ||
|
||
assert len(AppConfig.SECRET_KEY) == 16 * 2 # 16 bytes in hex | ||
|
||
assert all( | ||
conf is not None | ||
for conf in [ | ||
AppConfig.DEFAULT_MLFLOW_PERMISSION, | ||
AppConfig.SESSION_TYPE, | ||
AppConfig.OIDC_USERS_DB_URI, | ||
AppConfig.OIDC_GROUP_NAME, | ||
AppConfig.OIDC_ADMIN_GROUP_NAME, | ||
AppConfig.OIDC_PROVIDER_DISPLAY_NAME, | ||
AppConfig.OIDC_GROUPS_ATTRIBUTE, | ||
AppConfig.OIDC_SCOPE, | ||
] | ||
) | ||
|
||
assert all( | ||
conf is None | ||
for conf in [ | ||
AppConfig.OIDC_GROUP_DETECTION_PLUGIN, | ||
AppConfig.OIDC_REDIRECT_URI, | ||
AppConfig.OIDC_CLIENT_ID, | ||
AppConfig.OIDC_CLIENT_SECRET, | ||
] | ||
) | ||
|
||
def test_get_property(self): | ||
from mlflow_oidc_auth.config import AppConfig | ||
|
||
assert AppConfig.get_property("SECRET_KEY") == AppConfig.SECRET_KEY | ||
assert AppConfig.get_property("THIS_PROPERTY_DOES_NOT_EXIST") is None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import unittest | ||
from unittest.mock import patch | ||
from sqlalchemy import create_engine | ||
from sqlalchemy.orm import sessionmaker | ||
|
||
|
||
class TestMigrate: | ||
@patch("alembic.command.upgrade") | ||
def test_migrate(self, mock_upgrade): | ||
from mlflow_oidc_auth.db.utils import migrate | ||
|
||
engine = create_engine("sqlite:///:memory:") | ||
with sessionmaker(bind=engine)(): | ||
migrate(engine, "head") | ||
|
||
mock_upgrade.assert_called_once() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import unittest | ||
from mlflow_oidc_auth.entities import User, ExperimentPermission, RegisteredModelPermission, Group | ||
|
||
|
||
class TestUser(unittest.TestCase): | ||
def test_user_to_json(self): | ||
user = User( | ||
id_="123", | ||
username="test_user", | ||
password_hash="password", | ||
is_admin=True, | ||
display_name="Test User", | ||
experiment_permissions=[ExperimentPermission("exp1", "read")], | ||
registered_model_permissions=[RegisteredModelPermission("model1", "write")], | ||
groups=[Group("group1", "Group 1")], | ||
) | ||
|
||
expected_json = { | ||
"id": "123", | ||
"username": "test_user", | ||
"is_admin": True, | ||
"display_name": "Test User", | ||
"experiment_permissions": [{"experiment_id": "exp1", "permission": "read", "user_id": None, "group_id": None}], | ||
"registered_model_permissions": [{"name": "model1", "permission": "write", "user_id": None, "group_id": None}], | ||
"groups": [{"id": "group1", "group_name": "Group 1"}], | ||
} | ||
|
||
self.assertEqual(user.to_json(), expected_json) | ||
|
||
def test_user_from_json(self): | ||
json_data = { | ||
"id": "123", | ||
"username": "test_user", | ||
"is_admin": True, | ||
"display_name": "Test User", | ||
"experiment_permissions": [{"experiment_id": "exp1", "permission": "read", "user_id": None, "group_id": None}], | ||
"registered_model_permissions": [{"name": "model1", "permission": "write", "user_id": None, "group_id": None}], | ||
"groups": [{"id": "group1", "group_name": "Group 1"}], | ||
} | ||
|
||
user = User.from_json(json_data) | ||
|
||
self.assertEqual(user.id, "123") | ||
self.assertEqual(user.username, "test_user") | ||
self.assertEqual(user.password_hash, "REDACTED") | ||
self.assertTrue(user.is_admin) | ||
self.assertEqual(user.display_name, "Test User") | ||
self.assertEqual(len(user.experiment_permissions), 1) | ||
self.assertEqual(user.experiment_permissions[0].experiment_id, "exp1") | ||
self.assertEqual(user.experiment_permissions[0].permission, "read") | ||
self.assertEqual(len(user.registered_model_permissions), 1) | ||
self.assertEqual(user.registered_model_permissions[0].name, "model1") | ||
self.assertEqual(user.registered_model_permissions[0].permission, "write") | ||
self.assertEqual(len(user.groups), 1) | ||
self.assertEqual(user.groups[0].id, "group1") | ||
self.assertEqual(user.groups[0].group_name, "Group 1") |
31 changes: 31 additions & 0 deletions
31
mlflow_oidc_auth/tests/test_plugins_group_detecntion_msft_entra_id.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import unittest | ||
from unittest.mock import Mock, patch | ||
from mlflow_oidc_auth.plugins.group_detection_microsoft_entra_id import get_user_groups | ||
|
||
|
||
class TestGetUserGroups(unittest.TestCase): | ||
@patch("mlflow_oidc_auth.plugins.group_detection_microsoft_entra_id.requests.get") | ||
def test_get_user_groups(self, mock_get): | ||
mock_response = Mock() | ||
mock_response.json.return_value = { | ||
"value": [ | ||
{"displayName": "Group 1"}, | ||
{"displayName": "Group 2"}, | ||
{"displayName": "Group 3"}, | ||
] | ||
} | ||
mock_get.return_value = mock_response | ||
|
||
access_token = "D34DB33F" | ||
groups = get_user_groups(access_token) | ||
|
||
mock_get.assert_called_once_with( | ||
"https://graph.microsoft.com/v1.0/me/memberOf", | ||
headers={ | ||
"Authorization": f"Bearer {access_token}", | ||
"Content-Type": "application/json", | ||
}, | ||
) | ||
|
||
expected_groups = ["Group 1", "Group 2", "Group 3"] | ||
self.assertEqual(groups, expected_groups) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
from unittest import mock | ||
from mlflow_oidc_auth import routes | ||
|
||
""" | ||
`routes` contains mutiple routes definitions. | ||
This test is to ensure that all expected routes are present. | ||
""" | ||
|
||
|
||
class TestRoutes: | ||
def test_routes_presented(self): | ||
assert all( | ||
route is not None | ||
for route in [ | ||
routes.HOME, | ||
routes.LOGIN, | ||
routes.LOGOUT, | ||
routes.CALLBACK, | ||
routes.STATIC, | ||
routes.UI, | ||
routes.UI_ROOT, | ||
routes.GET_ACCESS_TOKEN, | ||
routes.GET_CURRENT_USER, | ||
routes.GET_EXPERIMENTS, | ||
routes.GET_MODELS, | ||
routes.GET_USERS, | ||
routes.GET_USER_EXPERIMENTS, | ||
routes.GET_USER_MODELS, | ||
routes.GET_EXPERIMENT_USERS, | ||
routes.GET_MODEL_USERS, | ||
routes.CREATE_USER, | ||
routes.GET_USER, | ||
routes.UPDATE_USER_PASSWORD, | ||
routes.UPDATE_USER_ADMIN, | ||
routes.DELETE_USER, | ||
routes.CREATE_EXPERIMENT_PERMISSION, | ||
routes.GET_EXPERIMENT_PERMISSION, | ||
routes.UPDATE_EXPERIMENT_PERMISSION, | ||
routes.DELETE_EXPERIMENT_PERMISSION, | ||
routes.CREATE_REGISTERED_MODEL_PERMISSION, | ||
routes.GET_REGISTERED_MODEL_PERMISSION, | ||
routes.UPDATE_REGISTERED_MODEL_PERMISSION, | ||
routes.DELETE_REGISTERED_MODEL_PERMISSION, | ||
routes.GET_GROUPS, | ||
routes.GET_GROUP_USERS, | ||
routes.GET_GROUP_EXPERIMENTS_PERMISSION, | ||
routes.CREATE_GROUP_EXPERIMENT_PERMISSION, | ||
routes.DELETE_GROUP_EXPERIMENT_PERMISSION, | ||
routes.UPDATE_GROUP_EXPERIMENT_PERMISSION, | ||
routes.GET_GROUP_MODELS_PERMISSION, | ||
routes.CREATE_GROUP_MODEL_PERMISSION, | ||
routes.DELETE_GROUP_MODEL_PERMISSION, | ||
routes.UPDATE_GROUP_MODEL_PERMISSION, | ||
] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
sonar.projectKey=data-platform-hq_mlflow-oidc-auth | ||
sonar.organization=data-platform-hq | ||
|
||
sonar.python.version=3.11 | ||
sonar.python.coverage.reportPaths=coverage.xml | ||
sonar.test.inclusions=**/test_*.py | ||
sonar.coverage.exclusions==**/test_*.py,**/app.py,**/db/migrations/versions/**/*.*,**/sqlalchemy_store.py,**/views.py # TODO: review sqlalchemy_store.py and views.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
[tox] | ||
envlist = py311 | ||
skipsdist = True | ||
|
||
[testenv] | ||
deps = | ||
pytest | ||
coverage<=7.6 | ||
commands = | ||
pip install -e '.[test]' | ||
coverage run -m pytest -s mlflow_oidc_auth/tests | ||
coverage xml | ||
|
||
[coverage:run] | ||
# relative_files = True | ||
source = mlflow_oidc_auth/ | ||
branch = True |