From cc50877131a4d437fa0fdcf3a2a1dbb10b703fbc Mon Sep 17 00:00:00 2001 From: Hugh Brown Date: Tue, 3 Mar 2026 21:41:56 -0700 Subject: [PATCH] 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 --- backend/app/api/activity.py | 4 ++-- backend/app/api/agents.py | 4 ++-- backend/app/api/approvals.py | 4 ++-- backend/app/api/board_group_memory.py | 4 ++-- backend/app/api/board_groups.py | 4 ++-- backend/app/api/board_memory.py | 4 ++-- backend/app/api/board_onboarding.py | 10 +++++----- backend/app/api/deps.py | 10 +++++----- backend/app/api/souls_directory.py | 8 ++++---- backend/app/api/tasks.py | 12 ++++++------ 10 files changed, 32 insertions(+), 32 deletions(-) diff --git a/backend/app/api/activity.py b/backend/app/api/activity.py index fb68ed40..72ddc4b6 100644 --- a/backend/app/api/activity.py +++ b/backend/app/api/activity.py @@ -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) diff --git a/backend/app/api/agents.py b/backend/app/api/agents.py index 4400beb7..732e241c 100644 --- a/backend/app/api/agents.py +++ b/backend/app/api/agents.py @@ -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) diff --git a/backend/app/api/approvals.py b/backend/app/api/approvals.py index 43a37f0c..ecb13a3a 100644 --- a/backend/app/api/approvals.py +++ b/backend/app/api/approvals.py @@ -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: diff --git a/backend/app/api/board_group_memory.py b/backend/app/api/board_group_memory.py index b9b1fd63..d87a6846 100644 --- a/backend/app/api/board_group_memory.py +++ b/backend/app/api/board_group_memory.py @@ -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,) diff --git a/backend/app/api/board_groups.py b/backend/app/api/board_groups.py index d718d777..b8ac3744 100644 --- a/backend/app/api/board_groups.py +++ b/backend/app/api/board_groups.py @@ -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: diff --git a/backend/app/api/board_memory.py b/backend/app/api/board_memory.py index d04ea3f5..5db1fa74 100644 --- a/backend/app/api/board_memory.py +++ b/backend/app/api/board_memory.py @@ -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,) diff --git a/backend/app/api/board_onboarding.py b/backend/app/api/board_onboarding.py index 51be333e..759d0ef0 100644 --- a/backend/app/api/board_onboarding.py +++ b/backend/app/api/board_onboarding.py @@ -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 = ( diff --git a/backend/app/api/deps.py b/backend/app/api/deps.py index 449e1731..5b703301 100644 --- a/backend/app/api/deps.py +++ b/backend/app/api/deps.py @@ -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( diff --git a/backend/app/api/souls_directory.py b/backend/app/api/souls_directory.py index 69afe1fa..a6a8f61e 100644 --- a/backend/app/api/souls_directory.py +++ b/backend/app/api/souls_directory.py @@ -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") diff --git a/backend/app/api/tasks.py b/backend/app/api/tasks.py index d7469a1b..41fab5ea 100644 --- a/backend/app/api/tasks.py +++ b/backend/app/api/tasks.py @@ -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: