Commit 836ff0

2026-03-13 19:41:59 Claude (MCP): [mcp] Add P2-3 ACL enforcement summary
/dev/null .. Dev/P2-3_Summary.md
@@ 0,0 1,44 @@
+ ---
+ category: reference
+ tags:
+ - phase-2
+ - acl
+ - middleware
+ last_updated: 2026-03-13
+ ---
+
+ # P2-3: ACL Enforcement Middleware
+
+ **Branch:** `feat/P2-3-acl-enforcement` (from `phase-2`)
+ **Status:** Complete — 21/21 tests passing
+
+ ## Deliverables
+
+ ### `app/auth/permissions.py`
+ - String constants: `READ`, `WRITE`, `UPLOAD`, `ADMIN`
+ - `ROLE_PERMISSIONS` dict mapping owner/editor/viewer to permission tuples
+ - `permissions_for_role(role)` — returns tuple or raises `ValueError`
+ - `format_permission_header(permissions)` — comma-separated string
+
+ ### `app/auth/acl.py`
+ - `AclEnforcer` class with constructor injection (`acl_model`, `wiki_model`)
+ - `check_access(user_id, wiki_id)` — looks up ACL entry, returns `{role, permissions}` or raises `AuthError(403)`
+ - `check_public_access(wiki_id)` — parses `owner_id:wiki_slug`, checks `is_public` flag, returns READ or raises
+ - `check_bearer_token(token)` — delegates to `WikiModel.scan_by_token()`, returns editor-level permissions or raises `AuthError(401)`
+
+ ### `app/auth/headers.py`
+ - `build_proxy_headers(email, name, permissions)` — returns dict with `x-otterwiki-name`, `x-otterwiki-email`, `x-otterwiki-permissions`
+
+ ### `app/models/wiki.py` (modified)
+ - Added `scan_by_token(plaintext_token)` — scans all wikis with `mcp_token_hash`, checks each with `bcrypt.checkpw()`, handles pagination
+ - Added `bcrypt` and `Attr` imports
+
+ ### `tests/test_acl.py`
+ - 21 tests using moto for DynamoDB mocking
+ - Covers: role mapping (4), format_permission_header (4), check_access (4), check_public_access (3), check_bearer_token (3), build_proxy_headers (3)
+
+ ## Design Decisions
+ - Bearer token validation scans all wikis then bcrypt-checks each (bcrypt salts are non-deterministic)
+ - `wiki_id` format: `{owner_id}:{wiki_slug}` — parsed by `_parse_wiki_id()` helper
+ - Token-authenticated requests get editor-level permissions (READ, WRITE, UPLOAD)
+ - No new dependencies beyond `bcrypt` (already needed for token hashing)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9