From a21026ac09e85dc53b525a27140f3a219995ba10 Mon Sep 17 00:00:00 2001 From: zhi Date: Wed, 11 Mar 2026 10:43:31 +0000 Subject: [PATCH] fix: enforce missing RBAC checks on issue/comment updates and deletes --- app/api/routers/comments.py | 6 +++++- app/api/routers/issues.py | 4 ++++ app/api/routers/projects.py | 1 - 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/api/routers/comments.py b/app/api/routers/comments.py index 7ea3bd6..59d71a5 100644 --- a/app/api/routers/comments.py +++ b/app/api/routers/comments.py @@ -56,10 +56,14 @@ def list_comments(issue_id: int, db: Session = Depends(get_db)): @router.patch("/comments/{comment_id}", response_model=schemas.CommentResponse) -def update_comment(comment_id: int, comment_update: schemas.CommentUpdate, db: Session = Depends(get_db)): +def update_comment(comment_id: int, comment_update: schemas.CommentUpdate, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user_or_apikey)): comment = db.query(models.Comment).filter(models.Comment.id == comment_id).first() if not comment: raise HTTPException(status_code=404, detail="Comment not found") + issue = db.query(models.Issue).filter(models.Issue.id == comment.issue_id).first() + if not issue: + raise HTTPException(status_code=404, detail="Issue not found") + check_project_role(db, current_user.id, issue.project_id, min_role="viewer") for field, value in comment_update.model_dump(exclude_unset=True).items(): setattr(comment, field, value) db.commit() diff --git a/app/api/routers/issues.py b/app/api/routers/issues.py index 7369dd0..deaca01 100644 --- a/app/api/routers/issues.py +++ b/app/api/routers/issues.py @@ -104,6 +104,8 @@ def get_issue(issue_id: int, db: Session = Depends(get_db)): @router.patch("/issues/{issue_id}", response_model=schemas.IssueResponse) def update_issue(issue_id: int, issue_update: schemas.IssueUpdate, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user_or_apikey)): issue = db.query(models.Issue).filter(models.Issue.id == issue_id).first() + if issue: + check_project_role(db, current_user.id, issue.project_id, min_role="dev") if not issue: raise HTTPException(status_code=404, detail="Issue not found") for field, value in issue_update.model_dump(exclude_unset=True).items(): @@ -116,6 +118,8 @@ def update_issue(issue_id: int, issue_update: schemas.IssueUpdate, db: Session = @router.delete("/issues/{issue_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_issue(issue_id: int, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user_or_apikey)): issue = db.query(models.Issue).filter(models.Issue.id == issue_id).first() + if issue: + check_project_role(db, current_user.id, issue.project_id, min_role="mgr") if not issue: raise HTTPException(status_code=404, detail="Issue not found") log_activity(db, "issue.deleted", "issue", issue.id, current_user.id, {"title": issue.title}) diff --git a/app/api/routers/projects.py b/app/api/routers/projects.py index f07af99..4ca9ab1 100644 --- a/app/api/routers/projects.py +++ b/app/api/routers/projects.py @@ -8,7 +8,6 @@ from app.models import models from app.schemas import schemas from app.api.deps import get_current_user_or_apikey from app.api.rbac import check_project_role -from app.services.activity import log_activity router = APIRouter(prefix="/projects", tags=["Projects"])