chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
from pathlib import Path
|
||||
|
||||
from mlflow.environment_variables import MLFLOW_TRACKING_PASSWORD, MLFLOW_TRACKING_USERNAME
|
||||
from mlflow.server.auth import auth_config
|
||||
from mlflow.utils.workspace_utils import DEFAULT_WORKSPACE_NAME
|
||||
|
||||
from tests.helper_functions import random_str
|
||||
from tests.tracking.integration_test_utils import _send_rest_tracking_post_request
|
||||
|
||||
PERMISSION = "READ"
|
||||
NEW_PERMISSION = "EDIT"
|
||||
ADMIN_USERNAME = auth_config.admin_username
|
||||
ADMIN_PASSWORD = auth_config.admin_password
|
||||
|
||||
|
||||
def write_isolated_auth_config(tmp_path: Path) -> Path:
|
||||
"""Write a basic_auth.ini under ``tmp_path`` whose ``database_uri`` points
|
||||
at an SQLite file inside the same dir, and return the config path.
|
||||
|
||||
Tests that spawn the auth server via ``_init_server`` must point
|
||||
``MLFLOW_AUTH_CONFIG_PATH`` at the returned file (through ``extra_env``) so
|
||||
the spawned auth server writes to the temp DB instead of the repo-root
|
||||
``basic_auth.db`` shared with the dev server. Without this, integration
|
||||
tests pollute (and depending on the fixture, delete) the developer's local
|
||||
auth state.
|
||||
"""
|
||||
config_path = tmp_path / "basic_auth.ini"
|
||||
db_path = tmp_path / "basic_auth.db"
|
||||
config_path.write_text(
|
||||
"[mlflow]\n"
|
||||
"default_permission = READ\n"
|
||||
f"database_uri = sqlite:///{db_path}\n"
|
||||
f"admin_username = {ADMIN_USERNAME}\n"
|
||||
f"admin_password = {ADMIN_PASSWORD}\n"
|
||||
"authorization_function = mlflow.server.auth:authenticate_request_basic_auth\n"
|
||||
"grant_default_workspace_access = false\n"
|
||||
)
|
||||
return config_path
|
||||
|
||||
|
||||
def create_user(tracking_uri: str, username: str | None = None, password: str | None = None):
|
||||
username = random_str() if username is None else username
|
||||
password = random_str() if password is None else password
|
||||
response = _send_rest_tracking_post_request(
|
||||
tracking_uri,
|
||||
"/api/2.0/mlflow/users/create",
|
||||
{
|
||||
"username": username,
|
||||
"password": password,
|
||||
},
|
||||
auth=(ADMIN_USERNAME, ADMIN_PASSWORD),
|
||||
)
|
||||
response.raise_for_status()
|
||||
return username, password
|
||||
|
||||
|
||||
def grant_role_permission(
|
||||
tracking_uri: str,
|
||||
username: str,
|
||||
resource_type: str,
|
||||
resource_pattern: str,
|
||||
permission: str,
|
||||
workspace: str = DEFAULT_WORKSPACE_NAME,
|
||||
auth: tuple[str, str] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Grant ``username`` ``permission`` on ``(resource_type, resource_pattern)`` via the
|
||||
role API. Creates a throwaway role in ``workspace`` with a single permission row,
|
||||
then assigns it to the user. Useful for auth-flow tests that previously called
|
||||
``POST /mlflow/experiments/permissions/create`` (and equivalents) to set up state.
|
||||
"""
|
||||
auth = auth or (ADMIN_USERNAME, ADMIN_PASSWORD)
|
||||
role_name = f"_test_{resource_type}_{random_str()}"
|
||||
create_resp = _send_rest_tracking_post_request(
|
||||
tracking_uri,
|
||||
"/api/3.0/mlflow/roles/create",
|
||||
{"name": role_name, "workspace": workspace},
|
||||
auth=auth,
|
||||
)
|
||||
create_resp.raise_for_status()
|
||||
role_id = create_resp.json()["role"]["id"]
|
||||
add_resp = _send_rest_tracking_post_request(
|
||||
tracking_uri,
|
||||
"/api/3.0/mlflow/roles/permissions/add",
|
||||
{
|
||||
"role_id": role_id,
|
||||
"resource_type": resource_type,
|
||||
"resource_pattern": resource_pattern,
|
||||
"permission": permission,
|
||||
},
|
||||
auth=auth,
|
||||
)
|
||||
add_resp.raise_for_status()
|
||||
assign_resp = _send_rest_tracking_post_request(
|
||||
tracking_uri,
|
||||
"/api/3.0/mlflow/roles/assign",
|
||||
{"username": username, "role_id": role_id},
|
||||
auth=auth,
|
||||
)
|
||||
assign_resp.raise_for_status()
|
||||
|
||||
|
||||
class User:
|
||||
def __init__(self, username, password, monkeypatch):
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.monkeypatch = monkeypatch
|
||||
|
||||
def __enter__(self):
|
||||
self.monkeypatch.setenv(MLFLOW_TRACKING_USERNAME.name, self.username)
|
||||
self.monkeypatch.setenv(MLFLOW_TRACKING_PASSWORD.name, self.password)
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.monkeypatch.delenv(MLFLOW_TRACKING_USERNAME.name, raising=False)
|
||||
self.monkeypatch.delenv(MLFLOW_TRACKING_PASSWORD.name, raising=False)
|
||||
Reference in New Issue
Block a user