Skip to content

Commit 629ce1f

Browse files
committed
Format source
1 parent c3ab628 commit 629ce1f

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

+1200
-798
lines changed

backend/app/admin_auth.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ async def create_admin_session(
2323
) -> str:
2424
"""Create a new admin session for a GitHub user."""
2525
session_token = secrets.token_urlsafe(48)
26-
expires_at = datetime.now(UTC).replace(tzinfo=None) + timedelta(hours=duration_hours)
27-
26+
expires_at = datetime.now(UTC).replace(tzinfo=None) + timedelta(
27+
hours=duration_hours
28+
)
29+
2830
admin_session = AdminSession(
2931
session_token=session_token,
3032
github_user_id=github_user.id,
@@ -34,11 +36,11 @@ async def create_admin_session(
3436
github_avatar_url=github_user.avatar_url,
3537
expires_at=expires_at,
3638
)
37-
39+
3840
db.add(admin_session)
3941
await db.commit()
4042
await db.refresh(admin_session)
41-
43+
4244
return session_token
4345

4446

@@ -80,10 +82,10 @@ async def cleanup_expired_sessions(db: AsyncSession) -> None:
8082
)
8183
)
8284
expired_sessions = result.scalars().all()
83-
85+
8486
for session in expired_sessions:
8587
session.is_active = False
86-
88+
8789
if expired_sessions:
8890
await db.commit()
8991

@@ -103,7 +105,7 @@ async def require_admin_auth(
103105
detail="Admin authentication required",
104106
headers={"WWW-Authenticate": "Bearer"},
105107
)
106-
108+
107109
try:
108110
session = await get_admin_session(db, admin_session_token)
109111
except Exception as e:
@@ -114,14 +116,14 @@ async def require_admin_auth(
114116
detail="Authentication service unavailable",
115117
headers={"WWW-Authenticate": "Bearer"},
116118
)
117-
119+
118120
if not session:
119121
raise HTTPException(
120122
status_code=status.HTTP_401_UNAUTHORIZED,
121123
detail="Invalid or expired admin session",
122124
headers={"WWW-Authenticate": "Bearer"},
123125
)
124-
126+
125127
# Check if user is still an admin (for existing sessions, we need a valid token)
126128
# Note: This check is disabled for existing sessions as we don't store the access token
127129
# Team membership is verified during initial login only
@@ -131,7 +133,7 @@ async def require_admin_auth(
131133
# status_code=status.HTTP_403_FORBIDDEN,
132134
# detail="Admin privileges revoked",
133135
# )
134-
136+
135137
return session
136138

137139

@@ -146,7 +148,7 @@ async def optional_admin_auth(
146148
"""
147149
if not admin_session_token:
148150
return None
149-
151+
150152
try:
151153
return await require_admin_auth(request, admin_session_token, db)
152154
except HTTPException:

backend/app/auth.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ async def get_current_token(
4848
if not auth_token:
4949
# Only log token length and first/last 4 characters for security
5050
masked_token = f"{token[:4]}...{token[-4:]}" if len(token) > 8 else "***"
51-
logger.warning(f"Authentication failed: Invalid token {masked_token} (length: {len(token)})")
51+
logger.warning(
52+
f"Authentication failed: Invalid token {masked_token} (length: {len(token)})"
53+
)
5254
raise authentication_failed("Invalid or expired token")
5355

5456
# Set user context for logging
@@ -58,4 +60,4 @@ async def get_current_token(
5860
await crud.update_token_last_used(db, token)
5961

6062
logger.info(f"Authentication successful for token: {auth_token.name}")
61-
return auth_token
63+
return auth_token

backend/app/config.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,17 @@ class Settings(BaseSettings):
2626
database_pool_recycle: int = 3600
2727
database_echo: bool = False
2828

29-
# CORS Configuration
29+
# CORS Configuration
3030
cors_origins: str = "" # Comma-separated string, will be parsed to list
3131
cors_allow_credentials: bool = True
3232
cors_allow_methods: List[str] = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
33-
cors_allow_headers: List[str] = ["Authorization", "Content-Type", "Accept", "Origin", "X-Requested-With"]
33+
cors_allow_headers: List[str] = [
34+
"Authorization",
35+
"Content-Type",
36+
"Accept",
37+
"Origin",
38+
"X-Requested-With",
39+
]
3440

3541
# Pagination Configuration
3642
default_page_size: int = 100
@@ -41,18 +47,20 @@ class Settings(BaseSettings):
4147
# Authentication Configuration
4248
token_length: int = 32 # in bytes, results in 64 hex characters
4349
token_cleanup_days: int = 90
44-
50+
4551
# GitHub OAuth Configuration
4652
github_client_id: str = ""
4753
github_client_secret: str = ""
4854
oauth_redirect_uri: str = "http://localhost:3000/admin/auth/callback"
4955
oauth_state_secret: str = "your-secret-key-change-me"
50-
56+
5157
# Admin authorization via GitHub usernames
5258
admin_initial_username: str = "" # Initial admin username (e.g., "pablogsal")
5359
# Legacy team-based auth (deprecated)
54-
admin_github_org: str = "" # GitHub organization name (e.g., "python")
55-
admin_github_teams: str = "" # Comma-separated list of team slugs (e.g., "memory-python-org")
60+
admin_github_org: str = "" # GitHub organization name (e.g., "python")
61+
admin_github_teams: str = (
62+
"" # Comma-separated list of team slugs (e.g., "memory-python-org")
63+
)
5664

5765
# Performance Configuration
5866
top_functions_limit: int = 10
@@ -78,14 +86,18 @@ def cors_origins_list(self) -> List[str]:
7886
"""Parse CORS origins string into a list."""
7987
if not self.cors_origins.strip():
8088
return []
81-
return [origin.strip() for origin in self.cors_origins.split(",") if origin.strip()]
82-
89+
return [
90+
origin.strip() for origin in self.cors_origins.split(",") if origin.strip()
91+
]
92+
8393
@property
8494
def admin_github_teams_list(self) -> List[str]:
8595
"""Parse admin GitHub teams string into a list."""
8696
if not self.admin_github_teams.strip():
8797
return []
88-
return [team.strip() for team in self.admin_github_teams.split(",") if team.strip()]
98+
return [
99+
team.strip() for team in self.admin_github_teams.split(",") if team.strip()
100+
]
89101

90102

91103
@lru_cache()

backend/app/crud.py

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ async def create_commit(
9999
timestamp = commit.timestamp
100100
if timestamp.tzinfo is not None:
101101
timestamp = timestamp.replace(tzinfo=None)
102-
102+
103103
db_commit = models.Commit(
104104
sha=commit.sha,
105105
timestamp=timestamp,
@@ -118,8 +118,7 @@ async def create_commit(
118118
async def get_binaries(db: AsyncSession) -> List[models.Binary]:
119119
result = await db.execute(
120120
select(models.Binary).order_by(
121-
models.Binary.display_order.asc(),
122-
models.Binary.name.asc()
121+
models.Binary.display_order.asc(), models.Binary.name.asc()
123122
)
124123
)
125124
return result.scalars().all()
@@ -217,7 +216,7 @@ async def get_runs_with_commits(
217216

218217
if commit_sha:
219218
# Use prefix matching (starts with) for commit SHA
220-
query = query.where(models.Run.commit_sha.ilike(f'{commit_sha}%'))
219+
query = query.where(models.Run.commit_sha.ilike(f"{commit_sha}%"))
221220
if binary_id:
222221
query = query.where(models.Run.binary_id == binary_id)
223222
if environment_id:
@@ -239,7 +238,7 @@ async def count_runs(
239238

240239
if commit_sha:
241240
# Use prefix matching (starts with) for commit SHA
242-
query = query.where(models.Run.commit_sha.ilike(f'{commit_sha}%'))
241+
query = query.where(models.Run.commit_sha.ilike(f"{commit_sha}%"))
243242
if binary_id:
244243
query = query.where(models.Run.binary_id == binary_id)
245244
if environment_id:
@@ -254,7 +253,7 @@ async def create_run(db: AsyncSession, run: schemas.RunCreate) -> models.Run:
254253
timestamp = run.timestamp
255254
if timestamp.tzinfo is not None:
256255
timestamp = timestamp.replace(tzinfo=None)
257-
256+
258257
db_run = models.Run(
259258
run_id=run.run_id,
260259
commit_sha=run.commit_sha,
@@ -467,9 +466,7 @@ async def create_auth_token(
467466
db: AsyncSession, token: str, name: str, description: str = None
468467
) -> models.AuthToken:
469468
"""Create a new auth token."""
470-
db_token = models.AuthToken(
471-
token=token, name=name, description=description
472-
)
469+
db_token = models.AuthToken(token=token, name=name, description=description)
473470
db.add(db_token)
474471
await db.commit()
475472
await db.refresh(db_token)
@@ -512,30 +509,34 @@ async def deactivate_auth_token(db: AsyncSession, token_id: int) -> bool:
512509
async def get_admin_users(db: AsyncSession) -> List[models.AdminUser]:
513510
"""Get all admin users."""
514511
result = await db.execute(
515-
select(models.AdminUser).where(models.AdminUser.is_active == True).order_by(models.AdminUser.added_at)
512+
select(models.AdminUser)
513+
.where(models.AdminUser.is_active == True)
514+
.order_by(models.AdminUser.added_at)
516515
)
517516
return result.scalars().all()
518517

519518

520-
async def get_admin_user_by_username(db: AsyncSession, username: str) -> Optional[models.AdminUser]:
519+
async def get_admin_user_by_username(
520+
db: AsyncSession, username: str
521+
) -> Optional[models.AdminUser]:
521522
"""Get admin user by GitHub username."""
522523
result = await db.execute(
523524
select(models.AdminUser).where(
524525
and_(
525526
models.AdminUser.github_username == username,
526-
models.AdminUser.is_active == True
527+
models.AdminUser.is_active == True,
527528
)
528529
)
529530
)
530531
return result.scalars().first()
531532

532533

533-
async def create_admin_user(db: AsyncSession, username: str, added_by: str, notes: Optional[str] = None) -> models.AdminUser:
534+
async def create_admin_user(
535+
db: AsyncSession, username: str, added_by: str, notes: Optional[str] = None
536+
) -> models.AdminUser:
534537
"""Create a new admin user."""
535538
admin_user = models.AdminUser(
536-
github_username=username,
537-
added_by=added_by,
538-
notes=notes
539+
github_username=username, added_by=added_by, notes=notes
539540
)
540541
db.add(admin_user)
541542
await db.commit()
@@ -566,10 +567,12 @@ async def ensure_initial_admin(db: AsyncSession, username: str) -> None:
566567
"""Ensure the initial admin user exists."""
567568
if not username:
568569
return
569-
570+
570571
existing = await get_admin_user_by_username(db, username)
571572
if not existing:
572573
logger.info(f"Creating initial admin user: {username}")
573-
await create_admin_user(db, username, "system", "Initial admin from environment variable")
574+
await create_admin_user(
575+
db, username, "system", "Initial admin from environment variable"
576+
)
574577
else:
575578
logger.info(f"Initial admin user already exists: {username}")

backend/app/database.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77

88
logger = logging.getLogger(__name__)
99

10+
1011
def create_database_engine():
1112
"""Create database engine with proper configuration."""
1213
settings = get_settings()
13-
14+
1415
engine_kwargs = {
1516
"echo": settings.database_echo,
1617
"pool_size": settings.database_pool_size,
@@ -20,7 +21,7 @@ def create_database_engine():
2021
# Add connection timeout for production
2122
"connect_args": {"timeout": 30} if "sqlite" in settings.database_url else {},
2223
}
23-
24+
2425
# Add additional PostgreSQL/MySQL specific optimizations
2526
if "postgresql" in settings.database_url:
2627
engine_kwargs["connect_args"] = {
@@ -34,7 +35,7 @@ def create_database_engine():
3435
"charset": "utf8mb4",
3536
"autocommit": False,
3637
}
37-
38+
3839
logger.info(
3940
f"Creating database engine: {settings.database_url.split('@')[-1] if '@' in settings.database_url else settings.database_url}"
4041
)
@@ -43,9 +44,10 @@ def create_database_engine():
4344
f"max_overflow={settings.database_max_overflow}, "
4445
f"recycle={settings.database_pool_recycle}s"
4546
)
46-
47+
4748
return create_async_engine(settings.database_url, **engine_kwargs)
4849

50+
4951
# Create engine using factory function
5052
engine = create_database_engine()
5153
AsyncSessionLocal = async_sessionmaker(
@@ -87,6 +89,7 @@ async def drop_tables():
8789
from contextlib import asynccontextmanager
8890
from typing import AsyncGenerator
8991

92+
9093
@asynccontextmanager
9194
async def transaction_scope() -> AsyncGenerator[AsyncSession, None]:
9295
"""

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy