# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commands

```bash
# Install dependencies
make pip_dev            # uv sync --group dev --all-extras

# Run unit tests (fast, no Docker required)
make test               # uv run py.test tests/unit/
uv run py.test tests/unit/path/to/test_file.py::test_function_name  # single test

# Lint and type-check
make lint               # ruff check + ruff format --check + mypy

# Run integration tests (requires Docker)
make local_test_integration

# Run Cerbos policy tests
make test_cerbos

# Open HTML coverage report (run make test first)
make unit_cov_report

# Run full Docker dev stack (port 8000)
make up

# Run service locally without Docker (port 5000)
make dev
```

## Architecture

**ows-pdp** is a centralized Policy Decision Point (PDP) — a FastAPI service that answers "is this identity allowed to do X on resource Y in tenant Z?" for other Sony PDE services.

### Request flow

1. JWT middleware extracts the authenticated identity UUID and their pre-resolved tenant roles from the JWT scope (via `pdp/fastapi/auth.py`)
2. A router handler (`pdp/fastapi/routers/identity.py`) receives the request
3. Logic layer (`pdp/logic/`) coordinates:
   - Fetching tenant hierarchy from OWS Account / OWS Participant services (cached in Redis)
   - Building a Cerbos `Principal` with roles/attributes
   - Calling Cerbos in batches (configurable `CERBOS_BATCH_SIZE`, default 50)
4. Cerbos evaluates YAML policies (`cerbos/policies/`) and returns ALLOW/DENY per resource+action
5. Result is returned and optionally cached in Redis

### Key packages

| Package | Role |
|---|---|
| `pdp/fastapi/` | Routes, schemas, auth middleware wiring |
| `pdp/logic/` | Business logic: Cerbos decision assembly, identity ops, cache management |
| `pdp/models/` | DynamoDB `Identity` model (partition: `identity_uuid`, sort: `tenant_uuid`) |
| `pdp/connectors/` | Thin clients for DynamoDB, Redis, Cerbos, OWS Account/Participant/Permissions, Split.io |
| `pdp/proxies/` | Tenant hierarchy resolution and ID↔UUID exchange |
| `pdp/constants/` | Shared enums, role definitions, error codes |
| `pdp/utils/` | Auth token parsing, cache key helpers, DynamoDB utilities |
| `pdp/cli/` | Typer CLI with `dynamodb`, `derived_roles`, and `redis` command groups |
| `cerbos/policies/` | YAML authorization policies (evaluated by Cerbos sidecar) |
| `cerbos/tests/` | Cerbos policy unit tests |

### Data stores

- **DynamoDB** (`dev_pp_identity` table): source of truth for identity↔tenant role assignments. Partition key: `identity_uuid`, sort key: `tenant_uuid`.
- **Redis**: caches role lookups, allowed-tenant results, and tenant hierarchy calls. TTLs are configurable per cache type via env vars.

### Tenant hierarchy

Tenants form a hierarchy: `ParentCompany → Company → Brand → Account → Subaccount`. Resource authorization decisions often require knowing a resource's full tenant ancestry — this is fetched from OWS Account/Participant services and cached. The `MultiTenantProxy` (`pdp/proxies/multi_tenant_proxy.py`) batches these lookups concurrently.

### Feature flags

Split.io is used for feature flagging. In local/test environments, flags are read from a file (`tests/.split`). Copy `.split.shadow` to `.split` to configure local flag values.

### Routers

- `identity` — core authorization endpoints (`/identity/self/check/resources/`, `/identity/{uuid}/roles/`, attach/detach roles, deactivate, etc.)
- `infra` — health check, connectivity probes, cache bust/bludgeon, tenant ID↔UUID exchange
- `temp` — temporary/experimental endpoints

### Environment

The `Environment` env var controls behavior (`dev` default, `qa`, `prod`, `test`). JWT auth and Sentry are disabled in `dev`. Config lives in `pdp/config.py`.

### Cerbos policies

Policies live in `cerbos/policies/` and are organized by domain:

- **Root-level** (`account.yml`, `identity.yml`, `subaccount.yml`, etc.) — core PDP resource kinds
- **Domain subdirs** (`abacus/`, `content/`, `fansifter/`, `neighbouring_rights/`, `tap/`, `demo/`) — service-specific resource policies
- **`machines/`** — machine identity policies nested by service (`pp/`, `auth0/`, `content/`, etc.)
- **`derived_roles/`** — reusable role hierarchies imported by resource policies
- **`variables/`** and **`constants/`** — shared lookups (tenant UUIDs, feature controls)

Cerbos tests (`cerbos/tests/`) are YAML test suites (schema: `https://api.cerbos.dev/latest/cerbos/policy/v1/TestSuite.schema.json`) with named `principals`, `resources`, and `tests` blocks. Shared principal definitions live in `cerbos/tests/testdata/principals.yaml`.
