refactor: rename require_admin_auth/require_admin_or_agent to require_user_auth/require_user_or_agent

These dependencies check actor type (human user vs agent), not admin
privilege. The old names were misleading and could cause authorization
mistakes when wiring new endpoints. Renamed across all 10 consumer
files along with their local ADMIN_AUTH_DEP / ADMIN_OR_AGENT_DEP
aliases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hugh Brown
2026-03-03 21:41:56 -07:00
committed by Abhimanyu Saharan
parent ea78b41a36
commit cc50877131
10 changed files with 32 additions and 32 deletions

View File

@@ -14,7 +14,7 @@ from sqlalchemy import and_, asc, desc, func, or_
from sqlmodel import col, select
from sse_starlette.sse import EventSourceResponse
from app.api.deps import ActorContext, require_admin_or_agent, require_org_member
from app.api.deps import ActorContext, require_user_or_agent, require_org_member
from app.core.time import utcnow
from app.db.pagination import paginate
from app.db.session import async_session_maker, get_session
@@ -42,7 +42,7 @@ SSE_SEEN_MAX = 2000
STREAM_POLL_SECONDS = 2
TASK_COMMENT_ROW_LEN = 4
SESSION_DEP = Depends(get_session)
ACTOR_DEP = Depends(require_admin_or_agent)
ACTOR_DEP = Depends(require_user_or_agent)
ORG_MEMBER_DEP = Depends(require_org_member)
BOARD_ID_QUERY = Query(default=None)
SINCE_QUERY = Query(default=None)

View File

@@ -9,7 +9,7 @@ from uuid import UUID
from fastapi import APIRouter, Depends, Query, Request
from sse_starlette.sse import EventSourceResponse
from app.api.deps import ActorContext, require_admin_or_agent, require_org_admin
from app.api.deps import ActorContext, require_user_or_agent, require_org_admin
from app.core.auth import AuthContext, get_auth_context
from app.db.session import get_session
from app.schemas.agents import (
@@ -35,7 +35,7 @@ GATEWAY_ID_QUERY = Query(default=None)
SINCE_QUERY = Query(default=None)
SESSION_DEP = Depends(get_session)
ORG_ADMIN_DEP = Depends(require_org_admin)
ACTOR_DEP = Depends(require_admin_or_agent)
ACTOR_DEP = Depends(require_user_or_agent)
AUTH_DEP = Depends(get_auth_context)

View File

@@ -18,7 +18,7 @@ from app.api.deps import (
get_board_for_actor_read,
get_board_for_actor_write,
get_board_for_user_write,
require_admin_or_agent,
require_user_or_agent,
)
from app.core.logging import get_logger
from app.core.time import utcnow
@@ -58,7 +58,7 @@ BOARD_READ_DEP = Depends(get_board_for_actor_read)
BOARD_WRITE_DEP = Depends(get_board_for_actor_write)
BOARD_USER_WRITE_DEP = Depends(get_board_for_user_write)
SESSION_DEP = Depends(get_session)
ACTOR_DEP = Depends(require_admin_or_agent)
ACTOR_DEP = Depends(require_user_or_agent)
def _parse_since(value: str | None) -> datetime | None:

View File

@@ -19,7 +19,7 @@ from app.api.deps import (
ActorContext,
get_board_for_actor_read,
get_board_for_actor_write,
require_admin_or_agent,
require_user_or_agent,
require_org_member,
)
from app.core.config import settings
@@ -65,7 +65,7 @@ SESSION_DEP = Depends(get_session)
ORG_MEMBER_DEP = Depends(require_org_member)
BOARD_READ_DEP = Depends(get_board_for_actor_read)
BOARD_WRITE_DEP = Depends(get_board_for_actor_write)
ACTOR_DEP = Depends(require_admin_or_agent)
ACTOR_DEP = Depends(require_user_or_agent)
IS_CHAT_QUERY = Query(default=None)
SINCE_QUERY = Query(default=None)
_RUNTIME_TYPE_REFERENCES = (UUID,)

View File

@@ -10,7 +10,7 @@ from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import func
from sqlmodel import col, select
from app.api.deps import ActorContext, require_admin_or_agent, require_org_admin, require_org_member
from app.api.deps import ActorContext, require_user_or_agent, require_org_admin, require_org_member
from app.core.time import utcnow
from app.db import crud
from app.db.pagination import paginate
@@ -52,7 +52,7 @@ router = APIRouter(prefix="/board-groups", tags=["board-groups"])
SESSION_DEP = Depends(get_session)
ORG_MEMBER_DEP = Depends(require_org_member)
ORG_ADMIN_DEP = Depends(require_org_admin)
ACTOR_DEP = Depends(require_admin_or_agent)
ACTOR_DEP = Depends(require_user_or_agent)
def _slugify(value: str) -> str:

View File

@@ -17,7 +17,7 @@ from app.api.deps import (
ActorContext,
get_board_for_actor_read,
get_board_for_actor_write,
require_admin_or_agent,
require_user_or_agent,
)
from app.core.config import settings
from app.core.time import utcnow
@@ -47,7 +47,7 @@ SINCE_QUERY = Query(default=None)
BOARD_READ_DEP = Depends(get_board_for_actor_read)
BOARD_WRITE_DEP = Depends(get_board_for_actor_write)
SESSION_DEP = Depends(get_session)
ACTOR_DEP = Depends(require_admin_or_agent)
ACTOR_DEP = Depends(require_user_or_agent)
_RUNTIME_TYPE_REFERENCES = (UUID,)

View File

@@ -13,8 +13,8 @@ from app.api.deps import (
get_board_for_user_read,
get_board_for_user_write,
get_board_or_404,
require_admin_auth,
require_admin_or_agent,
require_user_auth,
require_user_or_agent,
)
from app.core.config import settings
from app.core.logging import get_logger
@@ -54,8 +54,8 @@ BOARD_USER_READ_DEP = Depends(get_board_for_user_read)
BOARD_USER_WRITE_DEP = Depends(get_board_for_user_write)
BOARD_OR_404_DEP = Depends(get_board_or_404)
SESSION_DEP = Depends(get_session)
ACTOR_DEP = Depends(require_admin_or_agent)
ADMIN_AUTH_DEP = Depends(require_admin_auth)
ACTOR_DEP = Depends(require_user_or_agent)
USER_AUTH_DEP = Depends(require_user_auth)
def _parse_draft_user_profile(
@@ -426,7 +426,7 @@ async def confirm_onboarding(
payload: BoardOnboardingConfirm,
board: Board = BOARD_USER_WRITE_DEP,
session: AsyncSession = SESSION_DEP,
auth: AuthContext = ADMIN_AUTH_DEP,
auth: AuthContext = USER_AUTH_DEP,
) -> Board:
"""Confirm onboarding results and provision the board lead agent."""
onboarding = (

View File

@@ -3,14 +3,14 @@
These dependencies are the main "policy wiring" layer for the API.
They:
- resolve the authenticated actor (admin user vs agent)
- resolve the authenticated actor (human user vs agent)
- enforce organization/board access rules
- provide common "load or 404" helpers (board/task)
Why this exists:
- Keeping authorization logic centralized makes it easier to reason about (and
audit) permissions as the API surface grows.
- Some routes allow either admin users or agents; others require user auth.
- Some routes allow either human users or agents; others require user auth.
If you're adding a new endpoint, prefer composing from these dependencies instead
of re-implementing permission checks in the router.
@@ -51,7 +51,7 @@ AGENT_AUTH_OPTIONAL_DEP = Depends(get_agent_auth_context_optional)
SESSION_DEP = Depends(get_session)
def require_admin_auth(auth: AuthContext = AUTH_DEP) -> AuthContext:
def require_user_auth(auth: AuthContext = AUTH_DEP) -> AuthContext:
"""Require an authenticated human user (not an agent)."""
require_user_actor(auth)
return auth
@@ -66,7 +66,7 @@ class ActorContext:
agent: Agent | None = None
def require_admin_or_agent(
def require_user_or_agent(
auth: AuthContext | None = AUTH_OPTIONAL_DEP,
agent_auth: AgentAuthContext | None = AGENT_AUTH_OPTIONAL_DEP,
) -> ActorContext:
@@ -79,7 +79,7 @@ def require_admin_or_agent(
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)
ACTOR_DEP = Depends(require_admin_or_agent)
ACTOR_DEP = Depends(require_user_or_agent)
async def require_org_member(

View File

@@ -6,7 +6,7 @@ import re
from fastapi import APIRouter, Depends, HTTPException, Query, status
from app.api.deps import ActorContext, require_admin_or_agent
from app.api.deps import ActorContext, require_user_or_agent
from app.schemas.souls_directory import (
SoulsDirectoryMarkdownResponse,
SoulsDirectorySearchResponse,
@@ -15,7 +15,7 @@ from app.schemas.souls_directory import (
from app.services import souls_directory
router = APIRouter(prefix="/souls-directory", tags=["souls-directory"])
ADMIN_OR_AGENT_DEP = Depends(require_admin_or_agent)
USER_OR_AGENT_DEP = Depends(require_user_or_agent)
_SAFE_SEGMENT_RE = re.compile(r"^[a-zA-Z0-9][a-zA-Z0-9_-]*$")
_SAFE_SLUG_RE = re.compile(r"^[a-zA-Z0-9][a-zA-Z0-9_-]*$")
@@ -44,7 +44,7 @@ def _validate_segment(value: str, *, field: str) -> str:
async def search(
q: str = Query(default="", min_length=0),
limit: int = Query(default=20, ge=1, le=100),
_actor: ActorContext = ADMIN_OR_AGENT_DEP,
_actor: ActorContext = USER_OR_AGENT_DEP,
) -> SoulsDirectorySearchResponse:
"""Search souls-directory entries by handle/slug query text."""
refs = await souls_directory.list_souls_directory_refs()
@@ -66,7 +66,7 @@ async def search(
async def get_markdown(
handle: str,
slug: str,
_actor: ActorContext = ADMIN_OR_AGENT_DEP,
_actor: ActorContext = USER_OR_AGENT_DEP,
) -> SoulsDirectoryMarkdownResponse:
"""Fetch markdown content for a validated souls-directory handle and slug."""
safe_handle = _validate_segment(handle, field="handle")

View File

@@ -20,8 +20,8 @@ from app.api.deps import (
get_board_for_actor_read,
get_board_for_user_write,
get_task_or_404,
require_admin_auth,
require_admin_or_agent,
require_user_auth,
require_user_or_agent,
)
from app.core.time import utcnow
from app.db import crud
@@ -100,12 +100,12 @@ TASK_SNIPPET_MAX_LEN = 500
TASK_SNIPPET_TRUNCATED_LEN = 497
TASK_EVENT_ROW_LEN = 2
BOARD_READ_DEP = Depends(get_board_for_actor_read)
ACTOR_DEP = Depends(require_admin_or_agent)
ACTOR_DEP = Depends(require_user_or_agent)
SINCE_QUERY = Query(default=None)
STATUS_QUERY = Query(default=None, alias="status")
BOARD_WRITE_DEP = Depends(get_board_for_user_write)
SESSION_DEP = Depends(get_session)
ADMIN_AUTH_DEP = Depends(require_admin_auth)
USER_AUTH_DEP = Depends(require_user_auth)
TASK_DEP = Depends(get_task_or_404)
@@ -1449,7 +1449,7 @@ async def create_task(
payload: TaskCreate,
board: Board = BOARD_WRITE_DEP,
session: AsyncSession = SESSION_DEP,
auth: AuthContext = ADMIN_AUTH_DEP,
auth: AuthContext = USER_AUTH_DEP,
) -> TaskRead:
"""Create a task and initialize dependency rows."""
data = payload.model_dump(exclude={"depends_on_task_ids", "tag_ids", "custom_field_values"})
@@ -1672,7 +1672,7 @@ async def delete_task_and_related_records(
async def delete_task(
session: AsyncSession = SESSION_DEP,
task: Task = TASK_DEP,
auth: AuthContext = ADMIN_AUTH_DEP,
auth: AuthContext = USER_AUTH_DEP,
) -> OkResponse:
"""Delete a task and related records."""
if task.board_id is None: