Skip to content

Commit 666fa33

Browse files
committed
fix A01
1 parent 266042f commit 666fa33

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2399
-356
lines changed

.claude/settings.local.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@
3030
"Bash(npx @tanstack/router-cli generate)",
3131
"Bash(uv run:*)",
3232
"Bash(timeout:*)",
33-
"Bash(npm install:*)"
33+
"Bash(npm install:*)",
34+
"Bash(docker ps:*)",
35+
"Bash(npx tsc:*)",
36+
"Bash(git stash:*)",
37+
"Bash(npm run lint)"
3438
],
3539
"deny": [],
3640
"ask": []

backend/app/core/db.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
def init_db(session: Session) -> None:
1414
# Import models and repository here to avoid circular imports
1515
from app.modules.users.models import User
16-
from app.modules.users.schemas import UserCreate
1716
from app.modules.users.repository import UserRepository
17+
from app.modules.users.schemas import UserCreate
1818

1919
# Tables should be created with Alembic migrations
2020
# But if you don't want to use migrations, create

backend/app/modules/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# Application modules
22
# This package contains all domain modules organized by feature
33

4-
from app.modules.users.models import User
54
from app.modules.items.models import Item
65
from app.modules.shortener.models import ShortUrl
6+
from app.modules.users.models import User
77

88
# Export all models for SQLModel metadata registration
99
__all__ = ["User", "Item", "ShortUrl"]

backend/app/modules/auth/routes.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,19 @@
66
from fastapi.security import OAuth2PasswordRequestForm
77

88
from app.core.config import settings
9-
from app.modules.shared import CurrentUser, Message, SessionDep, get_current_active_superuser
109
from app.modules.auth.schemas import (
1110
GoogleCallbackRequest,
1211
GoogleLoginRequest,
1312
NewPassword,
1413
Token,
1514
)
1615
from app.modules.auth.service import AuthService
16+
from app.modules.shared import (
17+
CurrentUser,
18+
Message,
19+
SessionDep,
20+
get_current_active_superuser,
21+
)
1722
from app.modules.users.schemas import UserPublic
1823

1924
router = APIRouter(tags=["login"])

backend/app/modules/owasp_demo/routers/a05_injection.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import re
88
import subprocess
99
from pathlib import Path
10-
from typing import Any
1110
from urllib.parse import urlparse
1211

1312
from fastapi import APIRouter, HTTPException, Query
@@ -43,7 +42,8 @@ def sql_injection_vulnerable(
4342
- query: "'; DROP TABLE users; --" - Destroys data
4443
- query: "' UNION SELECT password FROM user --" - Data exfiltration
4544
"""
46-
raw_query = f"SELECT * FROM item WHERE title LIKE '%{search.query}%'"
45+
# Query the user table which always has data for demonstration
46+
raw_query = f"SELECT id, email, full_name FROM \"user\" WHERE email LIKE '%{search.query}%'"
4747

4848
try:
4949
result = session.exec(text(raw_query))

backend/app/modules/owasp_demo/routers/summary.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
)
2020

2121

22-
@router.post("/owasp-demo/seed")
22+
@router.post("/seed")
2323
def seed_demo_data(session: SessionDep) -> dict[str, Any]:
2424
"""
2525
Create sample data for OWASP demo endpoints.
@@ -109,7 +109,7 @@ def seed_demo_data(session: SessionDep) -> dict[str, Any]:
109109
}
110110

111111

112-
@router.get("/owasp-demo/summary")
112+
@router.get("/summary")
113113
def owasp_summary() -> dict[str, Any]:
114114
"""
115115
Get a summary of all OWASP Top 10 2025 demonstrations available.

backend/app/modules/private/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from fastapi import APIRouter
44

55
from app.core.security import get_password_hash
6+
from app.modules.private.schemas import PrivateUserCreate
67
from app.modules.shared import SessionDep
78
from app.modules.users.models import User
89
from app.modules.users.schemas import UserPublic
9-
from app.modules.private.schemas import PrivateUserCreate
1010

1111
router = APIRouter(tags=["private"], prefix="/private")
1212

backend/app/modules/rbac/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
)
1111
from app.modules.rbac.routes import router
1212

13+
# Note: require_permission is in deps.py but not exported here
14+
# to avoid circular imports. Import directly:
15+
# from app.modules.rbac.deps import require_permission
16+
1317
__all__ = [
1418
"Permission",
1519
"PermissionBase",

backend/app/modules/rbac/deps.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""RBAC dependencies for FastAPI."""
2+
3+
from fastapi import Depends, HTTPException
4+
5+
from app.modules.rbac.service import UserRoleService
6+
from app.modules.shared.dependencies import CurrentUser, SessionDep
7+
8+
9+
def require_permission(permission: str):
10+
"""
11+
Factory for permission-checking dependency.
12+
13+
Usage:
14+
@router.get("/", dependencies=[Depends(require_permission("users:read"))])
15+
def read_users(...):
16+
"""
17+
18+
def check_permission(current_user: CurrentUser, session: SessionDep):
19+
# Superusers bypass permission checks
20+
if current_user.is_superuser:
21+
return current_user
22+
23+
# Check user's permissions from their roles
24+
user_role_service = UserRoleService(session)
25+
if not user_role_service.user_has_permission(current_user.id, permission):
26+
raise HTTPException(
27+
status_code=403, detail=f"Permission '{permission}' required"
28+
)
29+
return current_user
30+
31+
return Depends(check_permission)

backend/app/modules/rbac/routes.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
@router.get("/permissions", response_model=PermissionsPublic)
3333
def read_permissions(
3434
session: SessionDep,
35-
current_user: CurrentUser,
35+
_current_user: CurrentUser,
3636
skip: int = 0,
3737
limit: int = 100,
3838
) -> Any:
@@ -46,7 +46,7 @@ def read_permissions(
4646
@router.get("/permissions/{permission_id}", response_model=PermissionPublic)
4747
def read_permission(
4848
session: SessionDep,
49-
current_user: CurrentUser,
49+
_current_user: CurrentUser,
5050
permission_id: uuid.UUID,
5151
) -> Any:
5252
"""Get a specific permission by ID."""
@@ -63,7 +63,7 @@ def read_permission(
6363
@router.get("/roles", response_model=RolesPublic)
6464
def read_roles(
6565
session: SessionDep,
66-
current_user: CurrentUser,
66+
_current_user: CurrentUser,
6767
skip: int = 0,
6868
limit: int = 100,
6969
) -> Any:
@@ -102,7 +102,7 @@ def create_role(
102102
@router.get("/roles/{role_id}", response_model=RoleWithPermissions)
103103
def read_role(
104104
session: SessionDep,
105-
current_user: CurrentUser,
105+
_current_user: CurrentUser,
106106
role_id: uuid.UUID,
107107
) -> Any:
108108
"""Get a specific role with its permissions."""

0 commit comments

Comments
 (0)