Metadata-Version: 2.4
Name: baobab-auth-core
Version: 0.5.0
Summary: Librairie métier pure d'authentification et d'autorisation de l'écosystème Baobab (architecture hexagonale, sans HTTP/ORM/JWT).
Project-URL: Homepage, https://github.com/baobabgit/baobab-auth-core
Project-URL: Repository, https://github.com/baobabgit/baobab-auth-core
Project-URL: Documentation, https://your-repo.readthedocs.io
Project-URL: Issues, https://github.com/baobabgit/baobab-auth-core/issues
Author: Patrick ANDRIANAIVO
License: MIT License
        
        Copyright (c) 2026 Michel ANDRIANAIVO
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: authentication,authorization,domain,hexagonal,rbac
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.12
Provides-Extra: dev
Requires-Dist: bandit[sarif,toml]>=1.7; extra == 'dev'
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pip-audit>=2.7; extra == 'dev'
Requires-Dist: pre-commit>=3.8; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: docs
Requires-Dist: furo>=2024.0; extra == 'docs'
Requires-Dist: sphinx>=7.0; extra == 'docs'
Description-Content-Type: text/markdown

# baobab-auth-core

[![CI](https://github.com/baobabgit/baobab-auth-core/actions/workflows/ci.yml/badge.svg)](https://github.com/baobabgit/baobab-auth-core/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/baobabgit/baobab-auth-core/branch/main/graph/badge.svg)](https://codecov.io/gh/baobabgit/baobab-auth-core)
[![PyPI version](https://img.shields.io/pypi/v/baobab-auth-core.svg)](https://pypi.org/project/baobab-auth-core/)
[![Python versions](https://img.shields.io/pypi/pyversions/baobab-auth-core.svg)](https://pypi.org/project/baobab-auth-core/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit)
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org)

> Librairie métier **pure** d'authentification et d'autorisation de l'écosystème **Baobab** :
> identités, sessions, tokens, rôles, permissions et audit — **sans** HTTP, ORM ni JWT concret.

## Table des matières

- [À propos](#à-propos)
- [Fonctionnalités](#fonctionnalités)
- [Stack technique](#stack-technique)
- [Architecture](#architecture)
- [Structure du projet](#structure-du-projet)
- [Installation](#installation)
- [Démarrage rapide](#démarrage-rapide)
- [Configuration](#configuration)
- [Tests](#tests)
- [Documentation](#documentation)
- [Sécurité](#sécurité)
- [Contribuer](#contribuer)
- [Changelog](#changelog)
- [Licence](#licence)
- [Remerciements & Auteur](#remerciements--auteur)

## À propos

`baobab-auth-core` est le socle d'authentification de l'écosystème Baobab. Conçue en
**architecture hexagonale**, elle porte les **entités, value objects, policies, cas d'usage
et ports** du domaine et délègue toute l'infrastructure (HTTP, base de données, JWT, hachage)
à des adaptateurs externes (`baobab-auth-api`, `baobab-auth-client`). Elle est **installable
et testable sans serveur ni base de données**.

## Fonctionnalités

### US-001 — Socle métier

| Cas d'usage / composant | Description |
|---|---|
| `RegisterUser` | Inscription avec validation email unique, politique de complexité et hachage |
| `User` + `UserProfile` | Identité stable (`auth_subject`), statuts de compte, profil séparé |
| `PasswordPolicy` | Règles de complexité : longueur, casse, chiffre, spécial, non-égal à l'email |
| `AuditEvent` + `AuditEventType` | Traçabilité de 14 événements sensibles avec sévérité |

### US-002 — Authentification & sessions

| Cas d'usage | Description |
|---|---|
| `AuthenticateUser` | Authentification email/mot de passe, création de session, refresh token |
| `RefreshSession` | Rotation du refresh token avec invalidation de l'ancien |
| `Logout` | Déconnexion propre (session `REVOKED`) |
| `RevokeSession` | Révocation d'une session par le propriétaire ou un ADMIN |
| `SessionPolicy` | Durée de vie des sessions (défaut 30 jours) |

### US-003 — RBAC & autorisation

| Cas d'usage / composant | Description |
|---|---|
| `AssignRole` / `RemoveRole` | Attribution/retrait de rôles par ADMIN ou SUPER_ADMIN |
| `AuthorizationService` | Construit un `AuthContext` (rôles + permissions agrégées) |
| `AuthContext` | `has_role()` / `has_permission()` immutables |
| `RolePolicy` | Garde anti-suppression du dernier SUPER_ADMIN |

### US-004 — Durcissement

| Cas d'usage / composant | Description |
|---|---|
| `LockoutPolicy` | Verrouillage progressif après N échecs (défaut : 5 tentatives, 15 min) |
| `ChangePassword` | Changement de mot de passe self-service ; révoque les autres sessions |
| `RevokeAllSessions` | Révocation globale des sessions (propriétaire ou ADMIN) |

### US-005 — Catalogue RBAC par défaut

| Composant | Description |
|---|---|
| `DefaultAuthCatalog` | 4 rôles système + 10 permissions `auth:*` clé en main |
| `ROLE_SUPER_ADMIN / ADMIN / MANAGER / USER` | Constantes prêtes à l'emploi |

### US-006 — API publique v1.0.0 *(BREAKING)*

| Changement | Description |
|---|---|
| Identifiants typés | `UserId`, `RoleId`, `SessionId`… remplacent les `str` bruts |
| Ports `async def` | Tous les ports sont asynchrones ; `async with uow:` |
| `TokenProvider` complet | `issue_token_pair`, `verify_*`, `revoke_token` |
| DTOs publics | `AuthenticatedUser`, `TokenPair`, `TokenClaims`, `SessionDTO` |
| `actor: AuthContext` | Remplace `actor_subject: str` dans les commandes |

> Guide de migration : [`docs/guides/how-to/migrate-v1.rst`](docs/guides/how-to/migrate-v1.rst)

### US-007 — Compléments fonctionnels

| Composant | Description |
|---|---|
| `AuditEvent` enrichi | `ip_address`, `user_agent`, `metadata` sur chaque événement |
| `PasswordHasher.needs_rehash()` | Détection des hashs obsolètes |
| `AuthorizationService` complet | `session_id` + `authenticated_at` optionnel (défaut `clock.now()`) |
| Exceptions complètes | `InvalidEmailError`, `WeakPasswordError`, `AccountDisabledError`, `AccountPendingError` |

### US-008 — Documentation & qualité

| Livrable | Description |
|---|---|
| `py.typed` | Marqueur PEP 561 — autocomplétion mypy pour les projets aval |
| 6 guides RST | `domain_model`, `ports`, `rbac`, `security_rules`, `testing`, `migrate-v1` |

### US-011 — Stabilisation des contrats d'intégration *(BREAKING)*

| Livrable | Description |
|---|---|
| API publique | `__all__` exporte value objects, DTO et exceptions ; test d'imports |
| Codes d'erreurs | `error_code` + `safe_message` sur chaque exception (mapping HTTP) |
| DTO | `TokenIssueContext` ; `AuthenticatedUser`/`TokenClaims`/`SessionDTO`/`TokenPair` réalignés |
| Lecture | `GetCurrentUser`, `GetUserBySubject`, `ListRoles`, `ListPermissions`, `ListUserSessions` |
| Admin | `BootstrapSuperAdmin`, `DisableUser`, `EnableUser`, `RequestJwkRotation` |
| Contrats | `docs/*_contract.md` + `docs/integration_contracts.md` + `docs/versioning.md` |

### Qualité transverse

- **Hexagonal** : tous les ports sont des `Protocol` `async def` ; fakes in-memory fournis (`baobab_auth_core.testing`).
- **Sécurité** : erreur générique `InvalidCredentialsError` (pas d'énumération), aucun secret dans `repr()`.
- **Tests** : 489 tests, couverture ≥ 96 %, `ruff` + `mypy` strict, `py.typed` (PEP 561).

## Stack technique

| Domaine        | Outil                                     |
| -------------- | ----------------------------------------- |
| Langage        | Python ≥ 3.12                             |
| Architecture   | hexagonale (domain / application / ports) |
| Environnement  | `venv` (`.venv`) + `pip`                  |
| Lint & format  | `ruff`                                    |
| Typage         | `mypy` (strict) + `py.typed` (PEP 561)   |
| Tests          | `pytest` + `pytest-cov` + `pytest-asyncio`|
| Documentation  | `sphinx` (+ `furo`), reStructuredText     |
| Dépendances    | aucune au runtime (cœur pur)              |
| CI / Hooks     | GitHub Actions, `pre-commit`              |

## Architecture

Deux axes orthogonaux structurent le projet :

- **Le « quoi »** : `Cahier des charges → US → FEAT → Task` (arbre de besoin).
- **Le « quand »** : sprints (champ *Iteration* de GitHub Projects).

```
Besoin (docs/specifications, RST)
   └─ US-001 ──► Issue ─┐
        └─ FEAT-001.1 ──► sub-issue ─┐  ◄── code (src/) + tests (tests/, miroir)
             └─ TASK-001.1.1 ──► sub-issue ──► sprint (Iteration)
```

## Structure du projet

```
.
├── AGENTS.md              # Règles de dev — SOURCE UNIQUE DE VÉRITÉ
├── CLAUDE.md             # Adaptateur Claude Code (importe AGENTS.md)
├── .cursor/rules/        # Adaptateur Cursor (reflète AGENTS.md)
├── src/baobab_auth_core/  # Code (1 classe par fichier)
├── tests/baobab_auth_core/# Tests en miroir de src/
├── docs/                 # Sphinx : specifications/ · api/ · guides/
│   └── workflow/         # Process multi-IA : rôles, gates, handoff, prompts
├── .github/              # CI + templates d'issues (US/FEAT/Task) + PR
├── pyproject.toml        # Config unique (projet, ruff, mypy, pytest, coverage)
├── .pre-commit-config.yaml
└── Makefile              # Commandes standard (install, lint, type, test, docs)
```

## Installation

```bash
pip install baobab-auth-core
```

Pour le développement (lint, types, tests, docs) :

```bash
git clone https://github.com/baobabgit/baobab-auth-core.git
cd baobab-auth-core
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev,docs]"
pre-commit install
```

## Démarrage rapide

```python
from baobab_auth_core.application.use_cases.register_user import RegisterUser
from baobab_auth_core.application.commands.register_user_command import RegisterUserCommand
from baobab_auth_core.domain.policies.password_policy import PasswordPolicy
from baobab_auth_core.testing.in_memory_user_repository import InMemoryUserRepository
from baobab_auth_core.testing.fake_password_hasher import FakePasswordHasher
from baobab_auth_core.testing.fake_id_generator import FakeIdGenerator
from baobab_auth_core.testing.fake_clock import FakeClock
from baobab_auth_core.testing.in_memory_audit_repository import InMemoryAuditRepository
from baobab_auth_core.testing.in_memory_unit_of_work import InMemoryUnitOfWork

import asyncio
from datetime import datetime, timezone

async def main() -> None:
    uc = RegisterUser(
        users=InMemoryUserRepository(),
        hasher=FakePasswordHasher(),
        id_gen=FakeIdGenerator(),
        clock=FakeClock(datetime(2026, 1, 1, tzinfo=timezone.utc)),
        audit=InMemoryAuditRepository(),
        policy=PasswordPolicy(),
        uow=InMemoryUnitOfWork(),
    )
    result = await uc.execute(RegisterUserCommand(
        email="alice@example.com",
        password="AliceSecret1!",
        ip_address="127.0.0.1",
        user_agent="my-app/1.0",
    ))
    print(result.user_id)

asyncio.run(main())
```

## Configuration

La configuration passe par des **variables d'environnement** validées via
`pydantic-settings`. Copiez le modèle et renseignez vos valeurs :

```bash
cp .env.example .env
```

| Variable    | Description                      | Défaut        |
| ----------- | -------------------------------- | ------------- |
| `APP_ENV`   | Environnement applicatif         | `development` |
| `LOG_LEVEL` | Niveau de journalisation         | `INFO`        |

## Tests

```bash
pytest                    # tests + couverture
ruff check src/ tests/    # lint
mypy src/ tests/          # vérification de types
make check                # lint + types + tests (tout en un)
```

392 tests, couverture ≥ 96 %, `asyncio_mode = "auto"` (pytest-asyncio).

## Documentation

La documentation Sphinx est sous `docs/` :

```bash
make docs        # génère docs/_build/html/
```

Guides techniques disponibles sous `docs/guides/how-to/` :

- **`domain_model.rst`** — entités, value objects, cycle de vie
- **`ports.rst`** — contrats des ports, conseils d'implémentation
- **`rbac.rst`** — modèle RBAC, `DefaultAuthCatalog`, `RolePolicy`
- **`security_rules.rst`** — `PasswordPolicy`, `LockoutPolicy`, opacité des erreurs
- **`testing.rst`** — fakes in-memory, patterns AAA, inspection audit
- **`migrate-v1.rst`** — guide de migration vers v1.0.0 (BREAKING CHANGES)
- **`migrate-v2.rst`** — guide de migration vers v2.0.0 (correctifs de sécurité)

Contrats d'intégration inter-briques (Markdown, à lire directement) :

- **`docs/integration_contracts.md`** — index des contrats + responsabilités
- **`docs/public_api.md`** — contrat public (`__all__`) + `py.typed`
- **`docs/error_codes.md`** — mapping exception → HTTP
- **`docs/{database,security,api,client,admin}_contract.md`** — contrat par brique
- **`docs/versioning.md`** — politique SemVer et réconciliation de version

## Sécurité

- **Aucun secret** dans le code ni dans Git : `.env` est gitignoré ; seul
  `.env.example` (sans valeurs) est versionné.
- Le hook `detect-private-key` et `pre-commit` bloquent les fuites évidentes.
- Analyse `bandit` (SAST) + `pip-audit` (vulns des dépendances) + Dependabot.
- Signalez toute vulnérabilité en privé (voir [`SECURITY.md`](SECURITY.md)) plutôt
  que via une issue publique.

## Contribuer

Les règles de développement sont décrites dans [`AGENTS.md`](AGENTS.md) et le
processus dans [`CONTRIBUTING.md`](CONTRIBUTING.md). En résumé : branche dédiée,
**Conventional Commits** avec ID spec, PR verte (lint + types + tests ≥ 90 %).

## Changelog

Voir [`CHANGELOG.md`](CHANGELOG.md) pour l'historique complet des versions.

Dernières versions :

- **v2.0.0** — Correctifs de sécurité BREAKING : `Logout`, `RevokeSession`, `RefreshSession`
  requièrent `id_gen` ; `AssignRole` bloque l'élévation ADMIN→SUPER_ADMIN ; atomicité UoW.
- **v1.1.0** — US-005 / US-007 / US-008 : `DefaultAuthCatalog`, compléments fonctionnels,
  `py.typed`, guides RST.
- **v1.0.0** — US-006 BREAKING : ports `async def`, identifiants typés, `AuthContext`
  enrichi, `TokenProvider` complet, `actor: AuthContext` dans les commandes.

## Licence

Distribué sous licence **MIT**. Voir [`LICENSE`](LICENSE).

## Remerciements & Auteur

Outils et standards qui rendent ce projet possible : Python, Ruff, mypy,
pytest, Sphinx, pre-commit, GitHub Actions, et les documentations de Claude Code,
Cursor et OpenAI Codex.

**Michel ANDRIANAIVO** — [patrick.andri@gmail.com](mailto:patrick.andri@gmail.com)
