# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.9.0] - 2026-03-06

### Added

- **Federal Compliance & Hardened Audit (Phase 9)**
- `AuditEvent` expanded with optional `source_ip`, `request_id`, `service_id` fields (NIST 800-53 AU-3)
- `MutationEvent` and `MutationAction` models for tracking configuration changes
- Engine mutation audit hooks — `add_role()`, `remove_role()`, `replace_roles()`, `add_policy()`, `remove_policy()`, `replace_policies()` all emit `MutationEvent` records (AC-2, CM-3)
- `TemporalRoleStore` and `DelegationStore` accept optional `audit_logger` for temporal/delegation audit events (AC-2)
- `ComplianceExporter` — enriches events with NIST 800-53 control mappings and event categories
- `HmacExporter` — HMAC-SHA256 signed log entries with `verify()` for tamper detection (AU-9)
- `pyauthz.contrib.x509` — X.509 Distinguished Name parsing: `parse_dn()`, `extract_dod_id()`, `subject_from_dn()`
- `Denied` exception now carries `.suggestions` populated automatically by `explain_denial()`
- Django integration tests (9 tests)
- Strawberry GraphQL integration tests (7 tests)
- 42 new compliance tests (404 total across all suites)
- `docs/FEDRAMP_GUIDE.md` — authorization patterns for FedRAMP compliance

### Changed

- `Denied.__init__` accepts optional `suggestions` parameter
- Strawberry `PyAuthzExtension` now inherits from `SchemaExtension` (compatible with Strawberry v0.300+)
- `AuditLogger` gains `log_mutation()` method for configuration change events

## [0.8.0] - 2026-03-06

### Added

- `diff_policies()` — compare two policy sets and report authorization outcome changes (allow→deny, deny→allow)
- `lint_policies()` — detect common policy mistakes: undefined roles (L001), overly broad (L002), contradictory (L003), disabled (L004), orphan roles (L005), undefined parents (L006)
- `pyauthz lint` CLI command for linting policy files
- `explain_denial()` — generate actionable suggestions for denied access (which roles would help, which conditions failed)
- `BreakGlassManager` — emergency access bypass with required justification, audit logging, and authorized subject list (maps to NIST 800-53 AC-2(2))
- 29 new tests (346 total) covering diff, lint, explain, and break-glass

## [0.7.0] - 2026-03-06

### Added

- `pyauthz.testing` module with `AuthScenario`, `must_allow`, `must_deny` for pytest-friendly authorization testing
- `pyauthz` CLI tool with `check`, `simulate`, `roles`, and `policies` commands
- `CONTRIBUTING.md` contributor guide
- `ARCHITECTURE.md` internal architecture documentation
- 23 new tests (317 total) for testing utilities and CLI

## [0.6.0] - 2026-03-06

### Added

- `DecisionCache` — TTL-based LRU decision cache with automatic invalidation on policy/role changes
- `PyAuthz.set_cache()` — attach a cache to the engine for automatic caching of authorization decisions
- `TenantManager` — multi-tenancy support with per-tenant isolated roles and policies
- `TemporalRole` + `TemporalRoleStore` — time-bounded role assignments with `effective_from` and `expires_at`
- `Delegation` + `DelegationStore` — controlled permission delegation between users with expiration
- `simulate()` + `SimulationResult` — policy simulation ("what would happen if...") without modifying the live engine
- All new types exported from `pyauthz.__init__`
- 50 new tests (294 total) covering cache, multi-tenancy, temporal permissions, delegation, and simulation

## [0.5.0] - 2026-03-06

### Added

- `pyauthz_flask` package — Flask extension with before_request subject resolution, `@requires()` decorator, `get_subject()` helper, and Denied -> 403 JSON handler
- `pyauthz_django` package — Django middleware with subject resolution, `@requires()` view decorator, and Denied -> 403 JSON response
- `pyauthz_strawberry` package — Strawberry GraphQL extension with context-based subject resolution and `@requires()` resolver decorator (sync + async)
- 7 Flask integration tests (244 total)

## [0.4.0] - 2026-03-06

### Added

- `authorized_filter()` method on `PyAuthz` engine — produces `FilterResult` with AST
- `FilterExpression` AST: `AllowAll`, `DenyAll`, `Compare`, `And`, `Or`, `Not` nodes
- `to_sqlalchemy_filter()` — compile FilterExpression to SQLAlchemy WHERE clauses
- `to_django_q()` — compile FilterExpression to Django ORM Q objects
- `to_raw_sql()` — compile FilterExpression to parameterized raw SQL
- Environment conditions flagged as unpushable in `FilterResult.unpushable_conditions`
- Deny-override combiner produces `AND NOT` clauses for DENY policies
- Cross-reference conditions resolved to literal values at compile time
- Performance benchmarks: simple RBAC <500μs, ABAC <2000μs
- 44 new tests (237 total) covering filtering AST, compilers, and benchmarks

## [0.3.0] - 2026-03-06

### Added

- `pyauthz_fastapi` package — first-class FastAPI authorization integration
- `PyAuthzMiddleware` — ASGI middleware for request-level subject resolution
- `@requires()` decorator for route-level authorization checks
- `setup_pyauthz()` convenience function (adds middleware + Denied exception handler)
- `get_subject()`, `get_decision()`, `get_pyauthz()` FastAPI dependency injection helpers
- Subject resolver protocol: user-provided async callable `(Request) -> Subject`
- Resource resolver protocol: user-provided callable for custom resource resolution
- Denied exception automatically mapped to 403 JSON response with structured error body
- 9 FastAPI integration tests (193 total)

## [0.2.0] - 2026-03-06

### Added

- Role hierarchy with parent inheritance — roles can list `parents` to inherit permissions
- Cycle detection at `add_role()` time — circular role hierarchies are caught immediately, never at evaluation time
- Full ABAC condition evaluation with 10 operators: ==, !=, >, <, >=, <=, in, not_in, contains, matches (regex)
- Dot-notation field resolution for deep attribute access (`subject.attributes.department`, `resource.attributes.classification`)
- Cross-reference conditions: `Condition(field="resource.owner_id", op="==", value="subject.id")`
- Fail-safe condition evaluation: missing attributes produce DENY with descriptive reasoning, never crash
- `allow-override` combiner: any ALLOW wins over all DENYs
- `priority-first` combiner: highest-priority applicable policy wins
- `PolicyWatcher` for YAML hot-reload — polls for file changes and auto-reloads policies
- 75 new tests (184 total) covering ABAC conditions, role hierarchy, new combiners, and the file watcher

## [0.1.0] - 2026-03-06

### Added

- Core authorization engine (`PyAuthz`) with sync and async APIs
- Pydantic data models: `Subject`, `Resource`, `Role`, `Permission`, `Policy`, `Condition`, `Decision`, `AccessRequest`
- Permission string parsing with wildcard support (`*:*`, `documents:*`, `*:read`)
- Action shorthand: `"write"` auto-expands to `"documents:write"` via `resource.type`
- Flat RBAC: roles with permissions, subjects with roles
- Auto-default policy: allow if role has matching permission (no explicit policies needed)
- `authorize()` / `aauthorize()` — returns `Decision` on allow, raises `Denied` on deny
- `is_allowed()` / `ais_allowed()` — returns `bool`, never raises
- `authorize_bulk()` / `aauthorize_bulk()` — batch authorization checks
- Policy combination algorithms: deny-override (default), first-match
- In-memory storage backend with thread-safe locking
- YAML policy loading with `version: 1` schema validation
- Structured audit logging with `JsonExporter`
- Error hierarchy: `Denied`, `SchemaError`, `ConfigError`, `PolicyVersionError`
- Role and policy management: `add_role()`, `remove_role()`, `replace_roles()`, `add_policy()`, `remove_policy()`, `replace_policies()`
- Environment context: per-request kwargs and `set_environment()` defaults
- `py.typed` marker for PEP 561 compliance
- 109 tests with >95% coverage including Hypothesis property-based tests
