Metadata-Version: 2.4
Name: umacs
Version: 0.42.0
Summary: UMACS is a unified management and access control service.
Requires-Python: >=3.13
Description-Content-Type: text/markdown
License-File: NOTICE
Requires-Dist: pydantic>=2.11.7
Requires-Dist: httpx>=0.28.1
Requires-Dist: pyjwt[crypto]>=2.10.1
Provides-Extra: fastapi
Requires-Dist: fastapi[standard]>=0.116.1; extra == "fastapi"
Requires-Dist: starlette; extra == "fastapi"
Provides-Extra: openfga
Provides-Extra: oidc
Provides-Extra: db-sqlmodel
Requires-Dist: sqlmodel>=0.0.31; extra == "db-sqlmodel"
Provides-Extra: db-beanie
Requires-Dist: beanie>=1.27; extra == "db-beanie"
Requires-Dist: motor>=3.5; extra == "db-beanie"
Dynamic: license-file

# UMACS

[![codecov](https://codecov.io/github/csed-ucm/umacs/graph/badge.svg?token=NDVM21XN8W)](https://codecov.io/github/csed-ucm/umacs)

**UMACS** (User Management and Access Control Service) is an authN + authZ kit for CSED FastAPI apps: a Casbin-backed server plus a Python SDK so developers can mount login/session routes and protect resources without wiring JWT, cookies, or policy engines by hand.

## Features

- [x] **FastAPI consumer SDK** (`UMACSAuth`): auth routes, bearer + cookie transports, `current_user`, `@require_permission`, `require_role`, testing helpers (`umacs[fastapi]`)
- [x] **Casbin policy engine** with HTTP `POST /enforce/check`, roles, and policies APIs
- [x] **Local login** sessions (short-lived access JWT + revocable refresh) and **OIDC/JWKS** verification for production IdPs
- [x] **Users, workspaces, groups, resources** APIs; SQL decision/audit logs
- [x] **Bootstrap + examples** for a local golden path (Swagger + cookie browser demo)

## Documentation

| | |
|--|--|
| **Docs site** | [csed-ucm.github.io/umacs](https://csed-ucm.github.io/umacs/) |
| **Start here** | [15-minute guide](https://csed-ucm.github.io/umacs/fifteen-minutes/) · [Consumer SDK](https://csed-ucm.github.io/umacs/consumer/) |
| **Reference** | [SDK contract](https://csed-ucm.github.io/umacs/sdk-contract/) · [Auth & sessions](https://csed-ucm.github.io/umacs/authentication-and-sessions/) · [API sketch](https://csed-ucm.github.io/umacs/api-reference/) · [OIDC](https://csed-ucm.github.io/umacs/auth/) |
| **Product map** | [Product versions](https://csed-ucm.github.io/umacs/product-versions/) · [Deployment models](https://csed-ucm.github.io/umacs/deployment-models/) · [Prior art](https://csed-ucm.github.io/umacs/prior-art/) |
| **Wiki** | [Overview / Features / Roadmap / ADRs](https://github.com/csed-ucm/umacs/wiki) (shared CSED project map) |
| **Source Markdown** | [`docs/`](docs/) |

## Core dependencies

- FastAPI + Uvicorn
- Authlib (OIDC JWT verification)
- Casbin (RBAC + optional ABAC)
- SQLModel + AsyncSQLAlchemy
- Alembic

## Quickstart (server)

### Environment

Copy [`.env.example`](.env.example) to `.env` and set at least:

| Variable | Purpose | Default |
|----------|---------|---------|
| `SECRET_KEY` | HS256 signing for local login JWTs | `supersecret` |
| `DATABASE_URL` | Async SQLAlchemy URL | `sqlite+aiosqlite:///./test.db` |

### Install, migrate, bootstrap, run

```sh
uv sync --group server --group dev
uv run alembic upgrade head
uv run python scripts/bootstrap_local.py
uv run fastapi dev
# or: uv run uvicorn app.app:app --reload
```

Bootstrap seeds Casbin path policies and users:

| User | Password | Role |
|------|----------|------|
| `admin` | `admin` | admin |
| `demo` | `demo` | user |
| `service` | `service` | service (machine credential for `POST /enforce/check`) |

Without bootstrap, an empty Casbin policy set will 403 login and other routes. `GET /health` stays public.

### Docker

```sh
docker build -t umacs:local .
docker run --rm -p 8000:8000 \
  -e SECRET_KEY=change-me \
  -e DATABASE_URL=sqlite+aiosqlite:///./umacs.db \
  umacs:local
# probe: curl http://localhost:8000/health
```

For gated API use inside the container, still run migrations/bootstrap (or mount a pre-seeded DB).

#### GHCR tags

On a successful [semantic-release](https://github.com/csed-ucm/umacs/blob/main/.github/workflows/build.yaml) (merged PR to `main` that bumps the version), CI pushes:

| Tag | Meaning |
|-----|---------|
| `ghcr.io/csed-ucm/umacs:<version>` | Immutable release |
| `ghcr.io/csed-ucm/umacs:latest` | Newest release |

```sh
docker pull ghcr.io/csed-ucm/umacs:latest
docker run --rm -p 8000:8000 \
  -e SECRET_KEY=change-me \
  -e DATABASE_URL=sqlite+aiosqlite:///./umacs.db \
  ghcr.io/csed-ucm/umacs:latest
```

## Consumer apps (SDK)

```sh
pip install 'umacs[fastapi]'
# core client only: pip install umacs
# or: uv add umacs --extra fastapi
```

1. Set `UMACS_URL` + **`UMACS_TOKEN`** (login as `service`) for gateway enforce calls.
2. Set **`SECRET_KEY`** (same as the UMACS server) so end-user JWTs verify locally.
3. `auth = UMACSAuth.from_env()`, `app.include_router(auth.router)`, `auth.add_identity_middleware(app)`.
4. Protect routes with `@auth.require_permission` / `auth.require_role` and Swagger password flow via `/auth/token`.
5. Follow the [smoke checklist](https://csed-ucm.github.io/umacs/consumer/#manual-smoke-checklist-10-min).

| Token | Where | Role |
|-------|--------|------|
| Service | `UMACS_TOKEN` / `UMACSAuth` | Call `/enforce/check` |
| User | Bearer and/or cookie on your app | Identity for `check(sub, …)` |

Examples: [bearer](https://github.com/csed-ucm/umacs/blob/main/examples/consumer_fastapi.py) · [cookie + browser](https://github.com/csed-ucm/umacs/blob/main/examples/consumer_cookie.py)
