diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md index a933f58..f93cf51 100644 --- a/ATTRIBUTIONS.md +++ b/ATTRIBUTIONS.md @@ -360,7 +360,7 @@ SOFTWARE. ``` -## aignostics-foundry-core (0.12.1) - MIT License +## aignostics-foundry-core (0.13.0) - MIT License 🏭 Foundational infrastructure for Foundry components. diff --git a/README.md b/README.md index ffd7f74..0a2f88a 100644 --- a/README.md +++ b/README.md @@ -210,13 +210,20 @@ ctx = make_context(database=DatabaseSettings(_env_prefix="TEST_DB_", url="sqlite #### Authentication (`{PREFIX}AUTH_`) -Settings class: `AuthSettings`. Both fields are required — no defaults. Only needed when using +Settings class: `AuthSettings`. All fields are optional with defaults unless `enabled=True`, which +activates several cross-field requirements. Only needed when using `aignostics_foundry_core.api.auth` dependencies. -| Variable | Required | Description | -|---|---|---| -| `{PREFIX}AUTH_INTERNAL_ORG_ID` | yes | Auth0 organization ID identifying the internal org (used by `require_internal`). | -| `{PREFIX}AUTH_AUTH0_ROLE_CLAIM` | yes | JWT claim name containing the user's role (e.g. `https://myapp.example.com/roles`). | +| Variable | Required | Default | Description | +|---|---|---|---| +| `{PREFIX}AUTH_ENABLED` | no | `false` | Enable Auth0 authentication. When `true`, several other fields become required. | +| `{PREFIX}AUTH_SESSION_SECRET` | when enabled | `""` | Secret to sign session cookies. Required when `AUTH_ENABLED=true`. | +| `{PREFIX}AUTH_SESSION_EXPIRATION` | no | `86400` | Session cookie expiration in seconds (range: 61–31536000). | +| `{PREFIX}AUTH_DOMAIN` | when enabled | `""` | Auth0 domain (e.g. `myapp.eu.auth0.com`). Required when `AUTH_ENABLED=true`. | +| `{PREFIX}AUTH_CLIENT_ID` | when enabled | `""` | Auth0 client ID (max 32 chars). Required when `AUTH_ENABLED=true`. | +| `{PREFIX}AUTH_CLIENT_SECRET` | when enabled | `""` | Auth0 client secret (64 chars). Required when `AUTH_ENABLED=true`. | +| `{PREFIX}AUTH_INTERNAL_ORG_ID` | when enabled | `""` | Auth0 organization ID identifying the internal org (used by `require_internal`). Required when `AUTH_ENABLED=true`. | +| `{PREFIX}AUTH_ROLE_CLAIM` | when enabled | `""` | JWT claim name containing the user's role (e.g. `https://myapp.example.com/roles`). Required when `AUTH_ENABLED=true`. | #### Console diff --git a/src/aignostics_foundry_core/api/auth.py b/src/aignostics_foundry_core/api/auth.py index a0d30ed..194ae49 100644 --- a/src/aignostics_foundry_core/api/auth.py +++ b/src/aignostics_foundry_core/api/auth.py @@ -5,7 +5,7 @@ - Authentication dependencies (require_authenticated, require_admin, etc.) - get_user: Get authenticated user from session - get_auth_client: Get Auth0 client from app state -- AuthSettings: Auth settings whose env prefix is derived from the active FoundryContext +- AuthSettings: Full auth configuration (enabled, session, domain, credentials, org, role claim) """ import time @@ -15,6 +15,7 @@ from fastapi import Request, Security from fastapi.security import APIKeyCookie from loguru import logger +from pydantic import Field, PlainSerializer, SecretStr, StringConstraints, model_validator from pydantic_settings import SettingsConfigDict from aignostics_foundry_core.foundry import get_context @@ -28,6 +29,7 @@ AUTH0_COOKIE_SCHEME_DESCRIPTION = "Auth0 session cookie authentication scheme." AUTH0_ROLE_ADMIN = "admin" USER_NOT_AUTHENTICATED = "User is not authenticated" +AUTH_SESSION_EXPIRATION_DEFAULT = 60 * 60 * 24 # 1 day in seconds class AuthSettings(OpaqueSettings): @@ -37,20 +39,73 @@ class AuthSettings(OpaqueSettings): ``FoundryContext.env_file``, both resolved at instantiation time via :func:`aignostics_foundry_core.foundry.get_context`. - Both ``internal_org_id`` and ``auth0_role_claim`` are required — they must be - provided via environment variables or ``.env`` files (no defaults). + Fields: + enabled: Enable Auth0 authentication (AUTH_ENABLED). + session_secret: Secret used to sign session cookies (AUTH_SESSION_SECRET). + session_expiration: Session cookie expiration in seconds (AUTH_SESSION_EXPIRATION). + domain: Auth0 domain (AUTH_DOMAIN). + client_id: Auth0 client ID (AUTH_CLIENT_ID). + client_secret: Auth0 client secret (AUTH_CLIENT_SECRET). + internal_org_id: Auth0 org ID for the internal organisation (AUTH_INTERNAL_ORG_ID). + role_claim: JWT claim name containing the user's role (AUTH_ROLE_CLAIM). + + Cross-field rules (validated after field assignment): + - enabled=True requires session_secret not None, client_secret not None, + non-empty domain, client_id, internal_org_id, and role_claim """ model_config = SettingsConfigDict(extra="ignore") - internal_org_id: str - auth0_role_claim: str + enabled: bool = Field(default=False) + session_secret: Annotated[ + SecretStr | None, + PlainSerializer(func=OpaqueSettings.serialize_sensitive_info, return_type=str, when_used="always"), + ] = Field(default=None) + session_expiration: int = Field(default=AUTH_SESSION_EXPIRATION_DEFAULT, gt=60, le=31536000) + domain: Annotated[str, StringConstraints(max_length=255)] = Field(default="") + client_id: Annotated[str, StringConstraints(max_length=32)] = Field(default="") + client_secret: Annotated[ + SecretStr | None, + PlainSerializer(func=OpaqueSettings.serialize_sensitive_info, return_type=str, when_used="always"), + ] = Field(default=None, min_length=64, max_length=64) + internal_org_id: str = "" + role_claim: str = "" def __init__(self, **kwargs: Any) -> None: # noqa: ANN401 """Initialise settings, deriving env_prefix and env files from the active FoundryContext.""" ctx = get_context() super().__init__(_env_prefix=f"{ctx.env_prefix}AUTH_", _env_file=ctx.env_file, **kwargs) # pyright: ignore[reportCallIssue] + @model_validator(mode="after") + def validate_auth_dependencies(self) -> "AuthSettings": + """Validate cross-field auth dependencies. + + Returns: + AuthSettings: The validated settings instance. + + Raises: + ValueError: If any cross-field dependency is violated. + """ + if self.enabled and self.session_secret is None: + msg = "AUTH_SESSION_SECRET must not be None when AUTH_ENABLED is True" + raise ValueError(msg) + if self.enabled and self.client_secret is None: + msg = "AUTH_CLIENT_SECRET must not be None when AUTH_ENABLED is True" + raise ValueError(msg) + if self.enabled and not self.domain: + msg = "AUTH_DOMAIN must not be empty when AUTH_ENABLED is True" + raise ValueError(msg) + if self.enabled and not self.client_id: + msg = "AUTH_CLIENT_ID must not be empty when AUTH_ENABLED is True" + raise ValueError(msg) + if self.enabled and not self.internal_org_id: + msg = "AUTH_INTERNAL_ORG_ID must not be empty when AUTH_ENABLED is True" + raise ValueError(msg) + if self.enabled and not self.role_claim: + msg = "AUTH_ROLE_CLAIM must not be empty when AUTH_ENABLED is True" + raise ValueError(msg) + return self + class UnauthenticatedError(Exception): """Raised when user is not authenticated.""" @@ -104,7 +159,7 @@ def get_auth_client(request: Request) -> AuthClient: name=AUTH0_SESSION_COOKIE_NAME, scheme_name="Auth0AdminCookie", description="Auth0 session cookie authentication with admin role requirement. " - f"User must have '{AUTH0_ROLE_ADMIN}' role in their configured auth0_role_claim.", + f"User must have '{AUTH0_ROLE_ADMIN}' role in their configured role_claim.", auto_error=False, ) # Security scheme specifically for admin endpoints @@ -138,7 +193,7 @@ async def _require_authenticated_impl( request: The incoming request. _cookie: The session cookie. role: Optional role required (e.g., "admin"). If specified, user must have - this role in their configured auth0_role_claim. + this role in their configured role_claim. Raises: UnauthenticatedError: If the session is not valid or missing. @@ -154,7 +209,7 @@ async def _require_authenticated_impl( # Check role if specified if role is not None: - user_role = user.get(auth_settings.auth0_role_claim) + user_role = user.get(auth_settings.role_claim) if user_role != role: msg = f"User role '{user_role}' does not match required role '{role}'" logger.warning(msg) @@ -237,7 +292,7 @@ async def require_internal_admin( Checks if the authenticated user is both: 1. A member of the configured internal organization (FOUNDRY_AUTH_INTERNAL_ORG_ID) - 2. Has the admin role in their configured auth0_role_claim + 2. Has the admin role in their configured role_claim Args: request: The incoming request. @@ -263,7 +318,7 @@ async def require_internal_admin( raise ForbiddenError(msg) # Check admin role - user_role = user.get(auth_settings.auth0_role_claim) + user_role = user.get(auth_settings.role_claim) if user_role != AUTH0_ROLE_ADMIN: msg = f"User role '{user_role}' does not match required role '{AUTH0_ROLE_ADMIN}'" logger.warning(msg) @@ -315,7 +370,7 @@ async def me(user: Annotated[dict[str, Any], Depends(get_user)]): return None user: dict[str, Any] = raw_user # pyright: ignore[reportUnknownVariableType] - set_sentry_user(user, role_claim=auth_settings.auth0_role_claim) + set_sentry_user(user, role_claim=auth_settings.role_claim) # Check if expired exp = user.get("exp") diff --git a/src/aignostics_foundry_core/gui/auth.py b/src/aignostics_foundry_core/gui/auth.py index bc2f762..8f57107 100644 --- a/src/aignostics_foundry_core/gui/auth.py +++ b/src/aignostics_foundry_core/gui/auth.py @@ -170,7 +170,7 @@ async def get_gui_user(request: Request) -> dict[str, Any] | None: return None user: dict[str, Any] = raw_user # pyright: ignore[reportUnknownVariableType] - set_sentry_user(user, role_claim=auth_settings.auth0_role_claim) # pyright: ignore[reportUnknownArgumentType] + set_sentry_user(user, role_claim=auth_settings.role_claim) # pyright: ignore[reportUnknownArgumentType] exp = user.get("exp") if not exp: @@ -319,7 +319,7 @@ async def wrapper(request: Request) -> None: return auth_settings = load_settings(AuthSettings) - role = user.get(auth_settings.auth0_role_claim) + role = user.get(auth_settings.role_claim) if role != AUTH0_ROLE_ADMIN: with _frame_context(frame_func, resolved_title, user): ui.label(f"{MSG_403_FORBIDDEN} - Admin access required").classes(CLASS_FORBIDDEN_ERROR) @@ -402,7 +402,7 @@ async def wrapper(request: Request) -> None: auth_settings = load_settings(AuthSettings) org_id = user.get("org_id") - role = user.get(auth_settings.auth0_role_claim) + role = user.get(auth_settings.role_claim) if org_id != auth_settings.internal_org_id or role != AUTH0_ROLE_ADMIN: with _frame_context(frame_func, resolved_title, user): diff --git a/tests/aignostics_foundry_core/api/__init__.py b/tests/aignostics_foundry_core/api/__init__.py index 9e46522..2f2a06c 100644 --- a/tests/aignostics_foundry_core/api/__init__.py +++ b/tests/aignostics_foundry_core/api/__init__.py @@ -3,4 +3,4 @@ from tests.conftest import TEST_PROJECT_PREFIX INTERNAL_ORG_ID_VAR_NAME = f"{TEST_PROJECT_PREFIX}AUTH_INTERNAL_ORG_ID" -AUTH0_ROLE_CLAIM_VAR_NAME = f"{TEST_PROJECT_PREFIX}AUTH_AUTH0_ROLE_CLAIM" +ROLE_CLAIM_VAR_NAME = f"{TEST_PROJECT_PREFIX}AUTH_ROLE_CLAIM" diff --git a/tests/aignostics_foundry_core/api/auth_test.py b/tests/aignostics_foundry_core/api/auth_test.py index 537f273..e602970 100644 --- a/tests/aignostics_foundry_core/api/auth_test.py +++ b/tests/aignostics_foundry_core/api/auth_test.py @@ -1,15 +1,15 @@ """Tests for aignostics_foundry_core.api.auth.""" -import os import time -from collections.abc import Generator from pathlib import Path from unittest.mock import AsyncMock, MagicMock +import pydantic import pytest from aignostics_foundry_core.api.auth import ( AUTH0_ROLE_ADMIN, + AUTH_SESSION_EXPIRATION_DEFAULT, AuthSettings, ForbiddenError, UnauthenticatedError, @@ -21,7 +21,7 @@ require_internal_admin, ) from aignostics_foundry_core.foundry import set_context -from tests.aignostics_foundry_core.api import AUTH0_ROLE_CLAIM_VAR_NAME, INTERNAL_ORG_ID_VAR_NAME +from tests.aignostics_foundry_core.api import INTERNAL_ORG_ID_VAR_NAME, ROLE_CLAIM_VAR_NAME from tests.conftest import make_context _INTERNAL_ORG_ID = "org_internal_123" @@ -30,20 +30,10 @@ _USER_NOT_AUTHENTICATED = "User is not authenticated" _USER_SUB = "auth0|x" _USER_EMAIL = "x@x.com" - - -@pytest.fixture(autouse=True) -def _auth_context() -> Generator[None, None, None]: # pyright: ignore[reportUnusedFunction] - """Set a real FoundryContext and required AuthSettings env vars for all auth tests. - - Yields: - None - """ - os.environ[INTERNAL_ORG_ID_VAR_NAME] = _INTERNAL_ORG_ID - os.environ[AUTH0_ROLE_CLAIM_VAR_NAME] = _TEST_ROLE_CLAIM - yield - os.environ.pop(INTERNAL_ORG_ID_VAR_NAME, None) - os.environ.pop(AUTH0_ROLE_CLAIM_VAR_NAME, None) +_TEST_SESSION_SECRET = "test-session-secret" # noqa: S105 +_TEST_CLIENT_SECRET = "x" * 64 +_TEST_CLIENT_ID = "x" * 32 +_TEST_DOMAIN = "example.auth0.com" @pytest.mark.unit @@ -98,21 +88,87 @@ def test_get_auth_client_returns_client_when_present(self) -> None: class TestAuthSettings: """Tests for AuthSettings.""" + def test_auth_settings_defaults(self) -> None: + """AuthSettings has correct defaults when no env vars are set.""" + settings = AuthSettings() + assert settings.enabled is False + assert not settings.internal_org_id + assert not settings.role_claim + assert not settings.domain + assert not settings.client_id + assert settings.session_expiration == AUTH_SESSION_EXPIRATION_DEFAULT + + def test_auth_settings_reads_env_vars(self, monkeypatch: pytest.MonkeyPatch) -> None: + """AuthSettings reads field values from env vars using the context's env prefix.""" + monkeypatch.setenv(INTERNAL_ORG_ID_VAR_NAME, "myorg") + settings = AuthSettings() + assert settings.internal_org_id == "myorg" + def test_auth_settings_uses_context_env_prefix(self, monkeypatch: pytest.MonkeyPatch) -> None: - """AuthSettings reads both required fields from env vars using the context's prefix.""" - monkeypatch.setenv(AUTH0_ROLE_CLAIM_VAR_NAME, "https://custom/role") + """AuthSettings reads fields from env vars using the context's prefix.""" + monkeypatch.setenv(ROLE_CLAIM_VAR_NAME, "https://custom/role") settings = AuthSettings() - assert settings.auth0_role_claim == "https://custom/role" - assert settings.internal_org_id == _INTERNAL_ORG_ID + assert settings.role_claim == "https://custom/role" - def test_auth_settings_raises_when_required_fields_absent(self, monkeypatch: pytest.MonkeyPatch) -> None: - """AuthSettings raises ValidationError when required env vars are absent.""" - import pydantic + def test_enabled_requires_session_secret(self) -> None: + """enabled=True with session_secret=None raises ValidationError.""" + with pytest.raises(pydantic.ValidationError): + AuthSettings(enabled=True, session_secret=None) - monkeypatch.delenv(INTERNAL_ORG_ID_VAR_NAME, raising=False) - monkeypatch.delenv(AUTH0_ROLE_CLAIM_VAR_NAME, raising=False) + def test_enabled_requires_client_secret(self) -> None: + """enabled=True with client_secret=None raises ValidationError.""" + with pytest.raises(pydantic.ValidationError): + AuthSettings( + enabled=True, + session_secret=_TEST_SESSION_SECRET, + client_secret=None, + ) + + def test_enabled_requires_non_empty_domain(self) -> None: + """enabled=True with empty domain raises ValidationError.""" + with pytest.raises(pydantic.ValidationError): + AuthSettings( + enabled=True, + session_secret=_TEST_SESSION_SECRET, + client_secret=_TEST_CLIENT_SECRET, + domain="", + ) + + def test_enabled_requires_non_empty_client_id(self) -> None: + """enabled=True with empty client_id raises ValidationError.""" + with pytest.raises(pydantic.ValidationError): + AuthSettings( + enabled=True, + session_secret=_TEST_SESSION_SECRET, + client_secret=_TEST_CLIENT_SECRET, + domain=_TEST_DOMAIN, + client_id="", + ) + + def test_enabled_requires_non_empty_internal_org_id(self) -> None: + """enabled=True with empty internal_org_id raises ValidationError.""" with pytest.raises(pydantic.ValidationError): - AuthSettings() + AuthSettings( + enabled=True, + session_secret=_TEST_SESSION_SECRET, + client_secret=_TEST_CLIENT_SECRET, + domain=_TEST_DOMAIN, + client_id=_TEST_CLIENT_ID, + internal_org_id="", + ) + + def test_enabled_requires_non_empty_role_claim(self) -> None: + """enabled=True with empty role_claim raises ValidationError.""" + with pytest.raises(pydantic.ValidationError): + AuthSettings( + enabled=True, + session_secret=_TEST_SESSION_SECRET, + client_secret=_TEST_CLIENT_SECRET, + domain=_TEST_DOMAIN, + client_id=_TEST_CLIENT_ID, + internal_org_id=_INTERNAL_ORG_ID, + role_claim="", + ) @pytest.mark.integration @@ -122,21 +178,21 @@ class TestAuthSettingsEnvFile: def test_auth_settings_reads_fields_from_env_file_via_context( self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: - """AuthSettings reads required fields from a .env file listed in the active FoundryContext.""" + """AuthSettings reads fields from a .env file listed in the active FoundryContext.""" env_file = tmp_path / ".env" env_file.write_text( - f"{INTERNAL_ORG_ID_VAR_NAME}=org_from_env_file\n{AUTH0_ROLE_CLAIM_VAR_NAME}=claim_from_env_file\n" + f"{INTERNAL_ORG_ID_VAR_NAME}=org_from_env_file\n{ROLE_CLAIM_VAR_NAME}=claim_from_env_file\n" ) set_context(make_context(env_file=[env_file])) monkeypatch.delenv(INTERNAL_ORG_ID_VAR_NAME, raising=False) - monkeypatch.delenv(AUTH0_ROLE_CLAIM_VAR_NAME, raising=False) + monkeypatch.delenv(ROLE_CLAIM_VAR_NAME, raising=False) settings = AuthSettings() assert settings.internal_org_id == "org_from_env_file" - assert settings.auth0_role_claim == "claim_from_env_file" + assert settings.role_claim == "claim_from_env_file" @pytest.mark.integration @@ -247,7 +303,7 @@ class TestRequireAdmin: async def test_no_user_raises_forbidden_error(self, monkeypatch: pytest.MonkeyPatch) -> None: """require_admin raises ForbiddenError when no session is available.""" - monkeypatch.setenv(AUTH0_ROLE_CLAIM_VAR_NAME, _TEST_ROLE_CLAIM) + monkeypatch.setenv(ROLE_CLAIM_VAR_NAME, _TEST_ROLE_CLAIM) request = MagicMock() request.app.state = MagicMock(spec=[]) # no auth_client → get_user returns None @@ -256,7 +312,7 @@ async def test_no_user_raises_forbidden_error(self, monkeypatch: pytest.MonkeyPa async def test_wrong_role_raises_forbidden_error(self, monkeypatch: pytest.MonkeyPatch) -> None: """require_admin raises ForbiddenError when user has a non-admin role.""" - monkeypatch.setenv(AUTH0_ROLE_CLAIM_VAR_NAME, _TEST_ROLE_CLAIM) + monkeypatch.setenv(ROLE_CLAIM_VAR_NAME, _TEST_ROLE_CLAIM) request = MagicMock() user = {"sub": _USER_SUB, _TEST_ROLE_CLAIM: "viewer", "exp": int(time.time()) + 3600} fake_client = MagicMock() @@ -268,7 +324,7 @@ async def test_wrong_role_raises_forbidden_error(self, monkeypatch: pytest.Monke async def test_admin_role_passes(self, monkeypatch: pytest.MonkeyPatch) -> None: """require_admin returns None without raising when user has the admin role.""" - monkeypatch.setenv(AUTH0_ROLE_CLAIM_VAR_NAME, _TEST_ROLE_CLAIM) + monkeypatch.setenv(ROLE_CLAIM_VAR_NAME, _TEST_ROLE_CLAIM) request = MagicMock() user = {"sub": _USER_SUB, _TEST_ROLE_CLAIM: AUTH0_ROLE_ADMIN, "exp": int(time.time()) + 3600} fake_client = MagicMock() @@ -340,6 +396,8 @@ async def test_wrong_org_raises_forbidden_error(self, monkeypatch: pytest.Monkey async def test_correct_org_wrong_role_raises_forbidden_error(self, monkeypatch: pytest.MonkeyPatch) -> None: """require_internal_admin raises ForbiddenError when user is in internal org but lacks admin role.""" + monkeypatch.setenv(INTERNAL_ORG_ID_VAR_NAME, _INTERNAL_ORG_ID) + monkeypatch.setenv(ROLE_CLAIM_VAR_NAME, _TEST_ROLE_CLAIM) request = MagicMock() user = { "sub": _USER_SUB, @@ -356,6 +414,8 @@ async def test_correct_org_wrong_role_raises_forbidden_error(self, monkeypatch: async def test_internal_admin_passes(self, monkeypatch: pytest.MonkeyPatch) -> None: """require_internal_admin returns None without raising when user is internal org admin.""" + monkeypatch.setenv(INTERNAL_ORG_ID_VAR_NAME, _INTERNAL_ORG_ID) + monkeypatch.setenv(ROLE_CLAIM_VAR_NAME, _TEST_ROLE_CLAIM) request = MagicMock() user = { "sub": _USER_SUB, diff --git a/tests/aignostics_foundry_core/gui/conftest.py b/tests/aignostics_foundry_core/gui/conftest.py index c2a9770..ad454d2 100644 --- a/tests/aignostics_foundry_core/gui/conftest.py +++ b/tests/aignostics_foundry_core/gui/conftest.py @@ -6,7 +6,7 @@ import pytest from aignostics_foundry_core.gui import clear_page_registry -from tests.aignostics_foundry_core.api import AUTH0_ROLE_CLAIM_VAR_NAME, INTERNAL_ORG_ID_VAR_NAME +from tests.aignostics_foundry_core.api import INTERNAL_ORG_ID_VAR_NAME, ROLE_CLAIM_VAR_NAME _INTERNAL_ORG = "org_internal" _ROLE_CLAIM = "https://example.com/role" @@ -24,7 +24,7 @@ def _clear_registry() -> Generator[None, None, None]: # pyright: ignore[reportU def _gui_auth_context() -> Generator[None, None, None]: # pyright: ignore[reportUnusedFunction] """Set required AuthSettings environment variables for GUI auth tests.""" os.environ[INTERNAL_ORG_ID_VAR_NAME] = _INTERNAL_ORG - os.environ[AUTH0_ROLE_CLAIM_VAR_NAME] = _ROLE_CLAIM + os.environ[ROLE_CLAIM_VAR_NAME] = _ROLE_CLAIM yield os.environ.pop(INTERNAL_ORG_ID_VAR_NAME, None) - os.environ.pop(AUTH0_ROLE_CLAIM_VAR_NAME, None) + os.environ.pop(ROLE_CLAIM_VAR_NAME, None) diff --git a/tests/aignostics_foundry_core/gui/gui_test.py b/tests/aignostics_foundry_core/gui/gui_test.py index 2e02b5c..fa3d62d 100644 --- a/tests/aignostics_foundry_core/gui/gui_test.py +++ b/tests/aignostics_foundry_core/gui/gui_test.py @@ -847,7 +847,7 @@ def test_page_admin_renders_forbidden_when_role_is_missing(self) -> None: user = {_ROLE_CLAIM: "other_role"} fake_auth = MagicMock() - fake_auth.auth0_role_claim = _ROLE_CLAIM + fake_auth.role_claim = _ROLE_CLAIM page_admin(_TEST_PATH)(lambda u: None) # pyright: ignore[reportUnknownLambdaType] wrappers, nicegui_mock = self._actualize_via_register_pages() @@ -871,7 +871,7 @@ def my_page(user: object) -> None: user = {_ROLE_CLAIM: "admin"} fake_auth = MagicMock() - fake_auth.auth0_role_claim = _ROLE_CLAIM + fake_auth.role_claim = _ROLE_CLAIM page_admin(_TEST_PATH)(my_page) wrappers, _ = self._actualize_via_register_pages() @@ -934,7 +934,7 @@ def test_page_internal_admin_renders_forbidden_when_only_org_matches(self) -> No user = {"org_id": _INTERNAL_ORG_ID, _ROLE_CLAIM: "other_role"} fake_auth = MagicMock() fake_auth.internal_org_id = _INTERNAL_ORG_ID - fake_auth.auth0_role_claim = _ROLE_CLAIM + fake_auth.role_claim = _ROLE_CLAIM page_internal_admin(_TEST_PATH)(lambda u: None) # pyright: ignore[reportUnknownLambdaType] wrappers, nicegui_mock = self._actualize_via_register_pages() @@ -954,7 +954,7 @@ def test_page_internal_admin_renders_forbidden_when_only_role_matches(self) -> N user = {"org_id": _OTHER_ORG, _ROLE_CLAIM: "admin"} fake_auth = MagicMock() fake_auth.internal_org_id = _INTERNAL_ORG_ID - fake_auth.auth0_role_claim = _ROLE_CLAIM + fake_auth.role_claim = _ROLE_CLAIM page_internal_admin(_TEST_PATH)(lambda u: None) # pyright: ignore[reportUnknownLambdaType] wrappers, nicegui_mock = self._actualize_via_register_pages() @@ -979,7 +979,7 @@ def my_page(user: object) -> None: user = {"org_id": _INTERNAL_ORG_ID, _ROLE_CLAIM: "admin"} fake_auth = MagicMock() fake_auth.internal_org_id = _INTERNAL_ORG_ID - fake_auth.auth0_role_claim = _ROLE_CLAIM + fake_auth.role_claim = _ROLE_CLAIM page_internal_admin(_TEST_PATH)(my_page) wrappers, _ = self._actualize_via_register_pages()