Skip to content

Commit 587fcf7

Browse files
olivermeyerclaude
andcommitted
fix(api.auth): pass ctx.env_file to AuthSettings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 18ca43a commit 587fcf7

File tree

4 files changed

+39
-10
lines changed

4 files changed

+39
-10
lines changed

ATTRIBUTIONS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9202,12 +9202,12 @@ SOFTWARE.
92029202

92039203
```
92049204

9205-
## pytest (9.0.2) - UNKNOWN
9205+
## pytest (9.0.3) - UNKNOWN
92069206

92079207
pytest: simple powerful testing with Python
92089208

92099209
* URL: https://docs.pytest.org/en/latest/
9210-
* Author(s): Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Florian Bruhin, Others (See AUTHORS)
9210+
* Author(s): Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Freya Bruhin, Others (See AUTHORS)
92119211

92129212
### License Text
92139213

src/aignostics_foundry_core/AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This file provides an overview of all modules in `aignostics_foundry_core`, thei
1111
| **models** | Shared output format enum | `OutputFormat` StrEnum with `YAML` and `JSON` values for use in CLI and API responses |
1212
| **process** | Current process introspection | `ProcessInfo`, `ParentProcessInfo` Pydantic models and `get_process_info()` for runtime process metadata; `SUBPROCESS_CREATION_FLAGS` for subprocess creation |
1313
| **api.exceptions** | API exception hierarchy and FastAPI handlers | `ApiException` (500), `NotFoundException` (404), `AccessDeniedException` (401); `api_exception_handler`, `unhandled_exception_handler`, `validation_exception_handler` for FastAPI registration |
14-
| **api.auth** | Auth0 authentication FastAPI dependencies | `AuthSettings` (env-prefix configurable), `UnauthenticatedError`, `ForbiddenError` (403); `get_auth_client`, `get_user`, `require_authenticated`, `require_admin`, `require_internal`, `require_internal_admin` FastAPI dependencies; Auth0 cookie security schemes |
14+
| **api.auth** | Auth0 authentication FastAPI dependencies | `AuthSettings` (env-prefix and env files derived from `ctx.env_prefix`/`ctx.env_file`), `UnauthenticatedError`, `ForbiddenError` (403); `get_auth_client`, `get_user`, `require_authenticated`, `require_admin`, `require_internal`, `require_internal_admin` FastAPI dependencies; Auth0 cookie security schemes |
1515
| **api.core** | Versioned API router and FastAPI factory | `VersionedAPIRouter` (tracks all created instances), `API_TAG_*` constants, `create_public/authenticated/admin/internal/internal_admin_router` factories, `build_api_metadata`, `build_versioned_api_tags`, `build_root_api_tags`, `get_versioned_api_instances(versions, build_metadata=None, *, context=None)`, `init_api()` |
1616
| **api** | Consolidated API sub-package | Re-exports all public symbols from `api.exceptions`, `api.auth`, and `api.core`; import any API symbol directly from `aignostics_foundry_core.api` |
1717
| **log** | Configurable loguru logging initialisation | `logging_initialize(filter_func=None, *, context=None)`, `LogSettings` (env-prefix configurable), `InterceptHandler` for stdlib-to-loguru bridging |
@@ -112,7 +112,7 @@ This file provides an overview of all modules in `aignostics_foundry_core`, thei
112112

113113
- **Purpose**: Provides Auth0 cookie-based session authentication dependencies for FastAPI routes. All project-specific settings (org ID, role claim) are loaded from `AuthSettings` whose env prefix is configurable at instantiation.
114114
- **Key Features**:
115-
- `AuthSettings(OpaqueSettings)` — uses the active FoundryContext.env_prefix to derive the env prefix (`{ctx.env_prefix}AUTH_`). Fields: `internal_org_id` (required `str`; identifies the internal organization), `auth0_role_claim` (required `str`; JWT claim name for role). Both fields are mandatory — no defaults are provided.
115+
- `AuthSettings(OpaqueSettings)` — uses the active FoundryContext to derive both the env prefix (`{ctx.env_prefix}AUTH_`) and the env file list (`ctx.env_file`). Fields: `internal_org_id` (required `str`; identifies the internal organization), `auth0_role_claim` (required `str`; JWT claim name for role). Both fields are mandatory — no defaults are provided.
116116
- `UnauthenticatedError(Exception)` — raised when a user session is missing or invalid
117117
- `ForbiddenError(ApiException)``status_code = 403`; raised when user lacks required role or org membership
118118
- `get_auth_client(request)` — retrieves `AuthClient` from `request.app.state.auth_client`; raises `RuntimeError` if not configured

src/aignostics_foundry_core/api/auth.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,14 @@
3131

3232

3333
class AuthSettings(OpaqueSettings):
34-
"""Auth settings whose env prefix is derived from the active FoundryContext.
34+
"""Auth settings whose env prefix and env files are derived from the active FoundryContext.
3535
36-
The effective prefix is ``{FoundryContext.env_prefix}AUTH_``, resolved at
37-
instantiation time via :func:`aignostics_foundry_core.foundry.get_context`.
36+
The effective prefix is ``{FoundryContext.env_prefix}AUTH_`` and the env files are
37+
``FoundryContext.env_file``, both resolved at instantiation time via
38+
:func:`aignostics_foundry_core.foundry.get_context`.
3839
3940
Both ``internal_org_id`` and ``auth0_role_claim`` are required — they must be
40-
provided via the corresponding environment variables (no defaults).
41+
provided via environment variables or ``.env`` files (no defaults).
4142
"""
4243

4344
model_config = SettingsConfigDict(extra="ignore")
@@ -46,8 +47,9 @@ class AuthSettings(OpaqueSettings):
4647
auth0_role_claim: str
4748

4849
def __init__(self, **kwargs: Any) -> None: # noqa: ANN401
49-
"""Initialise settings, deriving env_prefix from the active FoundryContext."""
50-
super().__init__(_env_prefix=f"{get_context().env_prefix}AUTH_", **kwargs) # pyright: ignore[reportCallIssue]
50+
"""Initialise settings, deriving env_prefix and env files from the active FoundryContext."""
51+
ctx = get_context()
52+
super().__init__(_env_prefix=f"{ctx.env_prefix}AUTH_", _env_file=ctx.env_file, **kwargs) # pyright: ignore[reportCallIssue]
5153

5254

5355
class UnauthenticatedError(Exception):

tests/aignostics_foundry_core/api/auth_test.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
import time
55
from collections.abc import Generator
6+
from pathlib import Path
67
from unittest.mock import AsyncMock, MagicMock
78

89
import pytest
@@ -19,7 +20,9 @@
1920
require_internal,
2021
require_internal_admin,
2122
)
23+
from aignostics_foundry_core.foundry import set_context
2224
from tests.aignostics_foundry_core.api import AUTH0_ROLE_CLAIM_VAR_NAME, INTERNAL_ORG_ID_VAR_NAME
25+
from tests.conftest import make_context
2326

2427
_INTERNAL_ORG_ID = "org_internal_123"
2528
_OTHER_ORG_ID = "org_other_456"
@@ -112,6 +115,30 @@ def test_auth_settings_raises_when_required_fields_absent(self, monkeypatch: pyt
112115
AuthSettings()
113116

114117

118+
@pytest.mark.integration
119+
class TestAuthSettingsEnvFile:
120+
"""Tests for AuthSettings env file loading."""
121+
122+
def test_auth_settings_reads_fields_from_env_file_via_context(
123+
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
124+
) -> None:
125+
"""AuthSettings reads required fields from a .env file listed in the active FoundryContext."""
126+
env_file = tmp_path / ".env"
127+
env_file.write_text(
128+
f"{INTERNAL_ORG_ID_VAR_NAME}=org_from_env_file\n{AUTH0_ROLE_CLAIM_VAR_NAME}=claim_from_env_file\n"
129+
)
130+
131+
set_context(make_context(env_file=[env_file]))
132+
133+
monkeypatch.delenv(INTERNAL_ORG_ID_VAR_NAME, raising=False)
134+
monkeypatch.delenv(AUTH0_ROLE_CLAIM_VAR_NAME, raising=False)
135+
136+
settings = AuthSettings()
137+
138+
assert settings.internal_org_id == "org_from_env_file"
139+
assert settings.auth0_role_claim == "claim_from_env_file"
140+
141+
115142
@pytest.mark.integration
116143
class TestGetUser:
117144
"""Tests for get_user FastAPI dependency."""

0 commit comments

Comments
 (0)