Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8,825 changes: 6,176 additions & 2,649 deletions ATTRIBUTIONS.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ requires-python = ">=3.11, <3.15"

dependencies = [
"asyncpg>=0.29,<1",
"auth0-fastapi>=1.0.0b5,<2",
"certifi>=2024",
"fastapi>=0.110,<1",
"loguru>=0.7,<1",
"platformdirs>=4,<5",
Expand All @@ -59,6 +61,8 @@ dependencies = [
"rich>=14,<15",
"sentry-sdk>=2,<3",
"sqlalchemy[asyncio]>=2,<3",
"nicegui>=3,<4",
"truststore>=0.9,<1",
"typer>=0.14,<1",
]

Expand Down
61 changes: 61 additions & 0 deletions src/aignostics_foundry_core/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,17 @@ This file provides an overview of all modules in `aignostics_foundry_core`, thei
| **models** | Shared output format enum | `OutputFormat` StrEnum with `YAML` and `JSON` values for use in CLI and API responses |
| **process** | Current process introspection | `ProcessInfo`, `ParentProcessInfo` Pydantic models and `get_process_info()` for runtime process metadata; `SUBPROCESS_CREATION_FLAGS` for subprocess creation |
| **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 |
| **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 |
| **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`, `init_api()` |
| **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` |
| **log** | Configurable loguru logging initialisation | `logging_initialize(project_name, version, env_file, filter_func)`, `LogSettings` (env-prefix configurable), `InterceptHandler` for stdlib-to-loguru bridging |
| **sentry** | Configurable Sentry integration | `sentry_initialize(project_name, version, environment, integrations, …)`, `SentrySettings` (env-prefix configurable), `set_sentry_user(user, role_claim)` for Auth0 user context |
| **service** | FastAPI-injectable base service | `BaseService` ABC with `get_service()` (cached per-class FastAPI `Depends` factory), `key()`, and abstract `health()` / `info()` methods; concrete subclasses implement health checks and module info |
| **database** | Async SQLAlchemy session management | `init_engine(db_url, pool_size, max_overflow, pool_timeout)`, `dispose_engine()`, `get_db_session()` (FastAPI dependency), `execute_with_session(func, …)`, `cli_run_with_db(func, …, db_url)`, `cli_run_with_engine(func, …, db_url)`, `with_engine(db_url)` decorator factory; auto-resets engine after `fork()` |
| **cli** | Typer CLI preparation utilities | `prepare_cli(cli, epilog, project_name)` — discovers and registers subcommands via `locate_implementations`, sets epilog recursively, installs `no_args_is_help` workaround; `no_args_is_help_workaround(ctx)` — raises `typer.Exit` when no subcommand is invoked |
| **boot** | Application / library boot sequence | `boot(project_name, version, sentry_integrations, is_library_mode, log_filter, show_cmdline)` — runs once per process: parses `--env` CLI args, initialises logging and Sentry, amends the SSL trust chain via *truststore* and *certifi*, and logs boot/shutdown messages |
| **user_agent** | Parameterised HTTP user-agent string builder | `user_agent(project_name, version, repository_url)` — builds `{project_name}-python-sdk/{version} (…)` string including platform info, current test, and GitHub Actions run URL |
| **gui** | NiceGUI page helpers, auth decorators, and nav builder | `GUINamespace` (configurable page decorator namespace), `gui` (default singleton), `page_public/authenticated/admin/internal/internal_admin` decorators, `get_gui_user`, `require_gui_user`, `BaseNavBuilder`, `NavItem`, `NavGroup`, `gui_get_nav_groups`, `BasePageBuilder`, `gui_register_pages`, `gui_run`; constants `WINDOW_SIZE`, `BROWSER_RECONNECT_TIMEOUT`, `RESPONSE_TIMEOUT` |
| **console** | Themed terminal output | Module-level `console` object (Rich `Console`) with colour theme and `_get_console()` factory |
| **di** | Dependency injection | `locate_subclasses`, `locate_implementations`, `load_modules`, `discover_plugin_packages`, `clear_caches`, `PLUGIN_ENTRY_POINT_GROUP` for plugin and subclass discovery |
| **health** | Service health checks | `Health` model and `HealthStatus` enum for tree-structured health status |
Expand All @@ -42,6 +47,62 @@ This file provides an overview of all modules in `aignostics_foundry_core`, thei
- **Dependencies**: `fastapi>=0.110,<1` (mandatory); `loguru` (used lazily inside `unhandled_exception_handler`)
- **Import**: `from aignostics_foundry_core.api.exceptions import ApiException, NotFoundException, AccessDeniedException, api_exception_handler, unhandled_exception_handler, validation_exception_handler`

### api.auth

**Auth0 authentication and authorization FastAPI dependencies**

- **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.
- **Key Features**:
- `AuthSettings(OpaqueSettings)` — reads from `FOUNDRY_AUTH_*` env vars by default; override prefix via constructor kwargs (e.g. `AuthSettings(_env_prefix="BRIDGE_AUTH_", _env_file=".env")`). Fields: `internal_org_id` (for internal org check), `auth0_role_claim` (JWT claim name for role)
- `UnauthenticatedError(Exception)` — raised when a user session is missing or invalid
- `ForbiddenError(ApiException)` — `status_code = 403`; raised when user lacks required role or org membership
- `get_auth_client(request)` — retrieves `AuthClient` from `request.app.state.auth_client`; raises `RuntimeError` if not configured
- `get_user(request, _cookie)` — async FastAPI dependency; returns user dict from Auth0 session or `None`; validates expiry; sets Sentry user context
- `require_authenticated` — dependency: requires a valid session
- `require_admin` — dependency: requires admin role
- `require_internal` — dependency: requires internal organization membership
- `require_internal_admin` — dependency: requires internal org membership AND admin role
- Auth0 cookie security scheme constants: `AUTH0_SESSION_COOKIE_NAME`, `AUTH0_TRANSACTION_COOKIE_NAME`, `AUTH0_ROLE_ADMIN`, `DEFAULT_AUTH0_ROLE_CLAIM`
- **Location**: `aignostics_foundry_core/api/auth.py`
- **Dependencies**: `auth0-fastapi>=1.0.0b5,<2`, `fastapi>=0.110,<1`, `loguru>=0.7,<1` (all mandatory)
- **Import**: `from aignostics_foundry_core.api.auth import AuthSettings, ForbiddenError, UnauthenticatedError, get_auth_client, get_user, require_authenticated, require_admin, require_internal, require_internal_admin`

### api.core

**Versioned API router and FastAPI application factory**

- **Purpose**: Provides `VersionedAPIRouter` for building versioned FastAPI sub-applications, typed tag constants, convenience router factory functions, metadata helpers, and a generic `init_api()` factory that registers the standard exception handlers.
- **Key Features**:
- `VersionedAPIRouter` — class-level `_instances` registry; `__new__` creates a real `fastapi.APIRouter` subclass at runtime (lazy import); `get_instances()` returns a copy of the registry
- `API_TAG_PUBLIC`, `API_TAG_AUTHENTICATED`, `API_TAG_ADMIN`, `API_TAG_INTERNAL`, `API_TAG_INTERNAL_ADMIN` — string constants for OpenAPI tagging
- `create_public_router(module_tag, *, version, prefix, …)` — public (unauthenticated) router
- `create_authenticated_router`, `create_admin_router`, `create_internal_router`, `create_internal_admin_router` — router factories that inject the appropriate `require_*` dependency from `api.auth`
- `build_api_metadata(title, description, author_name, author_email, repository_url, documentation_url, version)` — returns a `dict` suitable for `FastAPI(**metadata)`
- `build_versioned_api_tags(version_name, repository_url)` — OpenAPI tags for a single versioned sub-app
- `build_root_api_tags(base_url, versions)` — OpenAPI tags for the root app linking to each version's docs
- `get_versioned_api_instances(project_name, versions, build_metadata)` — loads project modules, creates one `FastAPI` per version, routes registered `VersionedAPIRouter` instances to the matching version
- `init_api(root_path, lifespan, exception_handler_registrations, **fastapi_kwargs)` — creates a `FastAPI` with the standard Foundry exception handlers (`ApiException`, `RequestValidationError`, `ValidationError`, `Exception`) pre-registered
- **Location**: `aignostics_foundry_core/api/core.py`
- **Dependencies**: `fastapi>=0.110,<1` (mandatory); `aignostics_foundry_core.di` (`load_modules`)
- **Import**: `from aignostics_foundry_core.api.core import VersionedAPIRouter, init_api, build_api_metadata, …` or `from aignostics_foundry_core.api import …`

### boot

**Application / library boot sequence**

- **Purpose**: Provides a single, idempotent `boot()` entry-point that initialises the full observability and SSL stack in the correct order. All project-specific metadata is injected as parameters so the function is reusable across any project.
- **Key Features**:
- `boot(project_name, version, sentry_integrations, is_library_mode, log_filter, show_cmdline)` — runs once per process; subsequent calls are silent no-ops
- Parses `--env`/`-e KEY=VALUE` CLI arguments: vars matching `{PROJECT_NAME_UPPER}_*` are injected into `os.environ` and removed from `sys.argv`
- Calls `logging_initialize` with project metadata
- Calls `_amend_ssl_trust_chain`: injects *truststore* into the SSL context (if available) and sets `SSL_CERT_FILE` to the *certifi* bundle path when no system CA bundle is detected
- Calls `sentry_initialize`; reads deployment environment from `{PROJECT_NAME_UPPER}_ENVIRONMENT` env var (default: `"production"`)
- Logs a boot message (project, version, pid, parent process, optional cmdline) at DEBUG level
- Registers an atexit handler that logs a shutdown trace (skipped inside pytest to avoid closed-stream errors)
- **Location**: `aignostics_foundry_core/boot.py`
- **Dependencies**: `loguru>=0.7,<1`, `certifi>=2024`, `truststore>=0.9,<1` (all mandatory); `aignostics_foundry_core.log`, `aignostics_foundry_core.sentry`, `aignostics_foundry_core.process`
- **Import**: `from aignostics_foundry_core.boot import boot`

### log

**Configurable loguru logging initialisation**
Expand Down
79 changes: 79 additions & 0 deletions src/aignostics_foundry_core/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,49 @@

Sub-modules:
- exceptions: ApiException hierarchy and FastAPI exception handlers
- auth: Auth0 authentication and authorisation FastAPI dependencies
- core: VersionedAPIRouter, router factories, and init_api
"""

from .auth import (
AUTH0_COOKIE_SCHEME_DESCRIPTION,
AUTH0_COOKIE_SCHEME_NAME,
AUTH0_ROLE_ADMIN,
AUTH0_SESSION_COOKIE_NAME,
AUTH0_TRANSACTION_COOKIE_NAME,
DEFAULT_AUTH0_ROLE_CLAIM,
AuthSettings,
ForbiddenError,
UnauthenticatedError,
auth0_admin_scheme,
auth0_internal_admin_scheme,
auth0_internal_scheme,
auth0_session_scheme,
get_auth_client,
get_user,
require_admin,
require_authenticated,
require_internal,
require_internal_admin,
)
from .core import (
API_TAG_ADMIN,
API_TAG_AUTHENTICATED,
API_TAG_INTERNAL,
API_TAG_INTERNAL_ADMIN,
API_TAG_PUBLIC,
VersionedAPIRouter,
build_api_metadata,
build_root_api_tags,
build_versioned_api_tags,
create_admin_router,
create_authenticated_router,
create_internal_admin_router,
create_internal_router,
create_public_router,
get_versioned_api_instances,
init_api,
)
from .exceptions import (
AccessDeniedException,
ApiException,
Expand All @@ -14,10 +55,48 @@
)

__all__ = [
# core
"API_TAG_ADMIN",
"API_TAG_AUTHENTICATED",
"API_TAG_INTERNAL",
"API_TAG_INTERNAL_ADMIN",
"API_TAG_PUBLIC",
# auth
"AUTH0_COOKIE_SCHEME_DESCRIPTION",
"AUTH0_COOKIE_SCHEME_NAME",
"AUTH0_ROLE_ADMIN",
"AUTH0_SESSION_COOKIE_NAME",
"AUTH0_TRANSACTION_COOKIE_NAME",
"DEFAULT_AUTH0_ROLE_CLAIM",
# exceptions
"AccessDeniedException",
"ApiException",
"AuthSettings",
"ForbiddenError",
"NotFoundException",
"UnauthenticatedError",
"VersionedAPIRouter",
"api_exception_handler",
"auth0_admin_scheme",
"auth0_internal_admin_scheme",
"auth0_internal_scheme",
"auth0_session_scheme",
"build_api_metadata",
"build_root_api_tags",
"build_versioned_api_tags",
"create_admin_router",
"create_authenticated_router",
"create_internal_admin_router",
"create_internal_router",
"create_public_router",
"get_auth_client",
"get_user",
"get_versioned_api_instances",
"init_api",
"require_admin",
"require_authenticated",
"require_internal",
"require_internal_admin",
"unhandled_exception_handler",
"validation_exception_handler",
]
Loading
Loading