# CLAUDE.md

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

## Overview

Python monorepo of AWS Lambda functions automating employee offboarding across Jira, Auth0, and GitHub. Orchestrated via AWS Step Functions.

**Offboarding flow:**
1. `jira_cli` — queries Jira for offboarding tickets, extracts user data (email, full name, last working day) from Atlassian Document Format descriptions
2. `auth0_cli` — searches and deletes the user across all 11 Auth0 tenants
3. `github_cli` — searches Terraform files for user references, creates GitHub issues assigned to `copilot-swe-agent[bot]` for automated cleanup

`lambda/shared/schemas/` defines all Pydantic models used as inter-Lambda event/response contracts (Step Functions payload types): `common.py`, `auth0.py`, `jira.py`, `github.py`. Each Lambda imports from `shared.schemas` via `pythonpath = [".", ".."]` in `pyproject.toml`.

## Commands

All commands run from inside `lambda/<name>/`.

```bash
# Tests
uv run pytest ./tests/                                              # jira_cli: all tests
uv run pytest tests/unit/                                          # auth0_cli, github_cli: unit only
uv run pytest tests/integration/                                   # auth0_cli, github_cli: integration only
uv run pytest ./tests/test_jira_client.py::test_query_jira_tickets # single test

# Lint & format (replace <pkg> with the lambda's package name: jira_client, auth0_client, github_client)
uv run ruff check <pkg>/ tests/
uv run ruff format <pkg>/ tests/
uv run mypy <pkg>/

# Docker (CI equivalent)
make docker_test              # unit tests + lint
make docker_test_integration  # integration tests

# Dependencies
uv sync --frozen              # production deps
uv sync --group dev --frozen  # dev deps
```

### Operational scripts (run from repo root)

```bash
scripts/lint-and-test-all.sh               # lint + unit + integration for all Lambdas (requires AWS creds: awsume prod)
scripts/block-user-by-email.sh <email>     # suspend user across all Auth0 tenants
scripts/delete-user-by-email.sh <email>    # delete user across all Auth0 tenants
```

## Key Conventions

### Lambda handler routing
Every `<pkg>/app.py` (e.g. `jira_client/app.py`) has `handler(event, context)` dispatching on `event["action"]`. Unknown actions raise `ValueError`. Pattern: validate with `Model.model_validate(event)` → call `_handle_*` → return `.model_dump()`.

### Shared schemas
When adding/modifying Lambda inputs or outputs, update `lambda/shared/schemas/` — not just the Lambda's local code.

### Dual-mode credentials
`config.py` uses `pydantic-settings` (`BaseSettings`). Locally, env vars hold token values directly. In Lambda (detected via `AWS_LAMBDA_FUNCTION_NAME`), env vars hold Secrets Manager secret *names*, and a `@model_validator` fetches the actual secret at startup. Auth0 credentials are at `shared/offboarding-automation/{tenant_name}/auth0_management_credentials`.

### `dry_run` flag
All write actions (`delete-user-by-id`, `offboard-user-with-copilot`, etc.) accept `dry_run: true` to skip side effects. Always wire this up when adding new write actions.

### Ruff style
Single quotes (`quote-style = "single"`), line length 88, rulesets A/D/E/F/I/Q/W (docstrings required). D203, D213, E501 are suppressed.

### Test layout
`jira_cli`: flat under `tests/`. `auth0_cli` and `github_cli`: split into `tests/unit/` and `tests/integration/`. Integration tests run against a live Lambda container via `docker-compose` and only execute on `master` in CI.

### Dockerfile pattern
Each Dockerfile: `base` → `dev` → `unit-lint` (CI test target), `builder` → `local` / `deploy`. `shared/schemas/` is injected via `--from=shared` build context (see Jenkinsfile `additionalContexts`).

### CI (Jenkinsfile)
Uses `withModifiedFunctions` to only run stages for changed Lambdas. To force all Lambdas, set `LAMBDA_FUNCTION_NAMES` parameter (comma-separated). `DEPLOY_TO_PROD=true` required for production.
