Compare commits
1 Commits
54feb9686c
...
595391b41b
| Author | SHA1 | Date | |
|---|---|---|---|
| 595391b41b |
@@ -68,11 +68,29 @@ def require_account_creator(
|
||||
raise HTTPException(status_code=403, detail="Account creation permission required")
|
||||
|
||||
|
||||
def _resolve_user_role(db: Session, role_id: int | None) -> Role:
|
||||
def _resolve_user_role(db: Session, role_id: int | None, *, is_agent: bool = False) -> Role:
|
||||
"""Resolve target role for user creation.
|
||||
|
||||
Default policy when caller didn't pin role_id:
|
||||
- is_agent (i.e. payload had agent_id/claw_identifier) → general-agent
|
||||
- human user → guest
|
||||
|
||||
general-agent ≈ guest + user.reset-self-apikey so agents can rotate
|
||||
their own API key without admin intervention. Created in
|
||||
init_bootstrap.py on every startup; falls back to guest if absent
|
||||
(e.g. very old DB that hasn't been re-seeded yet).
|
||||
"""
|
||||
if role_id is None:
|
||||
role = db.query(Role).filter(Role.name == "guest").first()
|
||||
default_name = "general-agent" if is_agent else "guest"
|
||||
role = db.query(Role).filter(Role.name == default_name).first()
|
||||
if not role and is_agent:
|
||||
# general-agent missing from this DB → fall back to guest, log warn
|
||||
role = db.query(Role).filter(Role.name == "guest").first()
|
||||
if not role:
|
||||
raise HTTPException(status_code=500, detail="Default guest role is missing")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Default role '{default_name}' is missing (DB not seeded)",
|
||||
)
|
||||
return role
|
||||
|
||||
role = db.query(Role).filter(Role.id == role_id).first()
|
||||
@@ -112,7 +130,7 @@ def create_user(
|
||||
if existing_agent:
|
||||
raise HTTPException(status_code=400, detail="agent_id already in use")
|
||||
|
||||
assigned_role = _resolve_user_role(db, user.role_id)
|
||||
assigned_role = _resolve_user_role(db, user.role_id, is_agent=has_agent_id)
|
||||
# In OIDC-only mode, ignore any supplied password: the user is created
|
||||
# passwordless (cannot password-login) and is expected to sign in via a
|
||||
# bound OIDC identity. API keys still work for such users.
|
||||
|
||||
@@ -124,11 +124,26 @@ _ACCOUNT_MANAGER_PERMISSIONS = {
|
||||
"user.reset-apikey",
|
||||
}
|
||||
|
||||
# Default role for agents (assigned automatically by POST /users when
|
||||
# the create-user payload carries agent_id/claw_identifier — see
|
||||
# app/api/routers/users.py:_resolve_user_role). Guest-tier reads +
|
||||
# self-service API-key rotation so agents can manage their own creds
|
||||
# without admin intervention.
|
||||
_GENERAL_AGENT_PERMISSIONS = {
|
||||
"project.read",
|
||||
"task.read",
|
||||
"milestone.read",
|
||||
"monitor.read",
|
||||
"calendar.read",
|
||||
"user.reset-self-apikey",
|
||||
}
|
||||
|
||||
_DEFAULT_ROLES = [
|
||||
("admin", "Administrator - full access to all features", None), # None ⇒ all perms
|
||||
("account-manager", "Account manager - can only create accounts", _ACCOUNT_MANAGER_PERMISSIONS),
|
||||
("mgr", "Manager - project & milestone management", _MGR_PERMISSIONS),
|
||||
("dev", "Developer - task execution & daily work", _DEV_PERMISSIONS),
|
||||
("general-agent", "General agent - read-only + self API key rotation", _GENERAL_AGENT_PERMISSIONS),
|
||||
("guest", "Guest - read-only access", None), # special: *.read only
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user