Metadata-Version: 2.5
Name: mic-platform
Version: 0.1.27
Summary: MIC — policy, contrôle et intégrations d'identité (Keycloak, OPA/OpenFGA, ratelimit).
Project-URL: Homepage, https://mic.uman.social/
Project-URL: Documentation, https://mic.uman.social/
Project-URL: Repository, https://gitlab.com/code-idea/code-libs/python/mic/mic-struct
Project-URL: Issues, https://gitlab.com/code-idea/code-libs/python/mic/mic-struct/-/issues
Project-URL: Changelog, https://gitlab.com/code-idea/code-libs/python/mic/mic-struct/-/blob/master/CHANGELOG.md
Project-URL: Copyright, http://uman.social
Author: UMAN
License-Expression: MIT
Requires-Python: >=3.14
Requires-Dist: mic-core
Requires-Dist: mic-datastore
Provides-Extra: keycloak
Requires-Dist: mic-core[client]; extra == 'keycloak'
Provides-Extra: opa
Requires-Dist: mic-core[client]; extra == 'opa'
Provides-Extra: openfga
Requires-Dist: mic-core[client]; extra == 'openfga'
Provides-Extra: redis
Requires-Dist: mic-datastore[redis]; extra == 'redis'
Description-Content-Type: text/markdown

# mic-platform

Briques **policy, contrôle et intégrations d'identité** du framework MIC. Sommet du DAG
`platform → data → core` : dépend de `mic-core` ET `mic-datastore`.

La page [Hors périmètre][out-of-scope] précise ce que ces intégrations ne
prennent pas en charge, notamment le provisionnement et l'exploitation des
services de plateforme. Le guide [Quitter MIC][leaving-mic] décrit leur
remplacement progressif par des clients ou bibliothèques directs.

[out-of-scope]: https://gitlab.com/code-idea/code-libs/python/mic/mic-struct/-/blob/develop/docs/guides/out-of-scope.md
[leaving-mic]: https://gitlab.com/code-idea/code-libs/python/mic/mic-struct/-/blob/develop/docs/guides/leaving-mic.md

## Prérequis Python

`mic-platform` exige Python 3.14 ou une version ultérieure. CPython 3.14 est la
cible actuellement qualifiée par un gate CI bloquant ; Python 3.13 et les
versions antérieures ne sont pas pris en charge. Consultez la
[politique Python][python-runtime-policy] avant une adoption sur un hébergement
dont l'environnement d'exécution ou l'image de base n'est pas sous votre contrôle.

[python-runtime-policy]: https://gitlab.com/code-idea/code-libs/python/mic/mic-struct/-/blob/develop/docs/guides/python-runtime-policy.md

## Modules

| Module | Rôle |
| -- | -- |
| `mic.authz` | Autorisation : moteur in-memory, OPA, OpenFGA (appels API **via httpx**) |
| `mic.identity.keycloak` | Client OIDC Keycloak concret, sans dépendance FastAPI/Litestar ; client d'administration pour provisionner des clients machine |
| `mic.ratelimit` | Rate limiting (in-memory / Redis Lua) + `RateLimitMiddleware` |

Namespace **PEP 420** (pas de `mic/__init__.py`).

## Installation

```bash
pip install "mic-platform[keycloak,openfga,redis]"
```

## Extras

| Extra | Tire |
| -- | -- |
| `opa` | `mic-core[client]` (httpx — appels HTTP vers l'agent OPA) |
| `openfga` | `mic-core[client]` (httpx — API OpenFGA ; **pas** le SDK officiel) |
| `keycloak` | `mic-core[client]` (httpx : discovery, authorization code + PKCE, refresh, logout, Admin REST) |
| `redis` | `mic-datastore[redis]` (backend Lua du rate limiter) |

> ℹ️ L'adaptateur OpenFGA (`mic.authz.openfga`) parle à l'API HTTP via `httpx`,
> il n'utilise **pas** `openfga-sdk`.

`mic.identity.keycloak.KeycloakClient` ne dépend d'aucun transport entrant :
les adaptateurs FastAPI, Litestar, WebSocket ou gRPC extraient les credentials,
puis appellent ce client et `mic.auth.OidcTokenVerifier`. Le client ne réimplémente
pas la validation JWT/JWKS et n'expose volontairement pas le password grant.

`mic.identity.keycloak.KeycloakAdminClient` provisionne des **clients machine**
(agents, workers, services partenaires) par l'API Admin REST, authentifié en
`client_credentials` :

```python
from mic.identity import KeycloakAdminClient

with KeycloakAdminClient(server_url="https://sso.example.org", realm="library",
                         client_id="library-provisioner", client_secret=secret) as admin:
    agent = admin.ensure_confidential_client(client_id="agent-site-a", name="Agent site A",
                                             default_client_scopes=["ingestion:deposit"])
    credential = admin.get_client_secret(agent.id)      # SecretStr
    admin.rotate_client_secret(agent.id)                # révocation du secret
    admin.set_client_enabled(agent.id, False)           # plus aucun jeton émis
```

`ensure_confidential_client` est idempotent : un client existant garde son secret et
son état (jamais réactivé) ; un client existant qui n'est pas un client machine
confidentiel (public, flux navigateur, password grant) lève `keycloak.client_conflict`
au lieu d'être modifié. Rôles minimaux de l'identité d'administration
(`realm-management`) : `manage-clients`, `view-clients`, plus `manage-users` pour
`grant_service_account_realm_roles`.

## Versionnage

Brique volatile (OPA/OpenFGA bougent vite) — reste en `0.x`. Contraindre avec
`>=0.1,<1`. Release : `make release-pkg PKG=platform VERSION=x.y.z` → tag
`platform-vX.Y.Z` (cf. [`../../RELEASING.md`](../../RELEASING.md)).
