CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / integration (push) Successful in 24s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 56s
CI & Build / Build & push image (push) Successful in 26s
Reading the 16 tool modules against each other: the six-key applicable-rules block (applicable_rules, applicable_rules_truncated, subscribed_rulebooks, project_rules, suppressed_rules, suppressed_topics) was hand-built in five places — enter_project, get_project, get_task (legacy plans), get_milestone (three of the six) and services/planning.start_planning. rulebooks_svc. rules_payload() is now the one place that names them; get_milestone gains the three it lacked, so every rules-carrying payload reads the same. list_rules / list_always_on_rules share _rule_summary. mcp/auth.resolve_bearer_to_user_id duplicated resolve_bearer's parsing and had no product caller (only its own tests) — removed; the tests now exercise resolve_bearer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
24 lines
863 B
Python
24 lines
863 B
Python
"""MCP-side Bearer token resolution. Reuses the existing api_keys infrastructure."""
|
|
from __future__ import annotations
|
|
|
|
from scribe.services.api_keys import lookup_key
|
|
|
|
|
|
|
|
async def resolve_bearer(auth_header: str | None) -> tuple[int, str] | None:
|
|
"""Resolve a Bearer token to (user_id, scope).
|
|
|
|
scope is 'read' or 'write'. Returns None for a missing/malformed/invalid
|
|
token. The MCP dispatch layer uses scope to deny write-class tool calls
|
|
from read-only keys — the same read/write boundary the REST API enforces.
|
|
"""
|
|
if not auth_header or not auth_header.startswith("Bearer "):
|
|
return None
|
|
raw_token = auth_header[len("Bearer "):].strip()
|
|
if not raw_token:
|
|
return None
|
|
api_key = await lookup_key(raw_token)
|
|
if api_key is None:
|
|
return None
|
|
return api_key.user_id, (api_key.scope or "write")
|