fix(projects): perm-gate create + apikey-via-Bearer + introspect with apikey
Three coupled fixes so non-admin agents (e.g. nav, role=mgr) can actually create projects through hf-cli with their API key: 1. POST /projects no longer hardcodes is_admin. It checks the global `project.create` perm via role_permissions (admin still wins via is_admin short-circuit). Permission-denied 403 message names the exact perm. 2. /auth/me/permissions now uses get_current_user_or_apikey (was get_current_user JWT-only). This is what hf-cli hits to populate its local permission cache that drives the "not permitted" gate; previously every API-key-authed agent saw all commands as gated. 3. get_current_user_or_apikey now also accepts an API key delivered via Authorization: Bearer (in addition to X-API-Key). hf-cli only knows Bearer; trying to JWT-decode an API key string would fail — so on decode failure, fall through to the API key lookup. Keeps X-API-Key behavior unchanged. 4. init_bootstrap: add `project.create` to DEFAULT_PERMISSIONS and to _MGR_PERMISSIONS so admin (auto-all) + mgr both get it on seed. Bug came to light when manager-agent reported `hf project list`/`create` returned `not permitted`. Root cause: hf-cli calls /auth/me/permissions with the API key via Bearer header → 401 → state.Known=false → every command in the surface is gated false locally. Even after the local gate, POST /projects would still 403 due to the hardcoded admin check. All four steps above are required end-to-end. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ from app.core.config import get_db, settings
|
||||
from app.models import models
|
||||
from app.models.role_permission import Permission, Role, RolePermission
|
||||
from app.schemas import schemas
|
||||
from app.api.deps import Token, verify_password, create_access_token, get_current_user
|
||||
from app.api.deps import Token, verify_password, create_access_token, get_current_user, get_current_user_or_apikey
|
||||
|
||||
router = APIRouter(prefix="/auth", tags=["Auth"])
|
||||
|
||||
@@ -80,7 +80,7 @@ class PermissionIntrospectionResponse(BaseModel):
|
||||
|
||||
@router.get("/me/permissions", response_model=PermissionIntrospectionResponse)
|
||||
async def get_my_permissions(
|
||||
current_user: models.User = Depends(get_current_user),
|
||||
current_user: models.User = Depends(get_current_user_or_apikey),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""Return the current user's effective permissions for CLI help introspection."""
|
||||
|
||||
Reference in New Issue
Block a user