Files
bambuddy/backend/app/api/routes/bug_report.py
maziggy 5709282200 Add authentication to bug report debug logging endpoints
The bug report endpoints (start-logging, stop-logging, submit) had no
  authentication, allowing anyone on the network to enable debug logging,
  retrieve sanitized system logs, and trigger bug report submissions when
  auth was enabled. All three now require permission when auth is enabled:
  start-logging requires settings:update, stop-logging and submit require
  settings:read. Endpoints remain open when auth is disabled (default).
2026-04-04 12:54:31 +02:00

112 lines
3.4 KiB
Python

"""Bug report endpoint for submitting user bug reports to GitHub."""
import logging
from fastapi import APIRouter, Query
from pydantic import BaseModel
from backend.app.api.routes.support import (
_apply_log_level,
_collect_support_info,
_get_debug_setting,
_get_recent_sanitized_logs,
_set_debug_setting,
)
from backend.app.core.auth import RequirePermissionIfAuthEnabled
from backend.app.core.database import async_session
from backend.app.core.permissions import Permission
from backend.app.models.user import User
from backend.app.services.bug_report import submit_report
from backend.app.services.printer_manager import printer_manager
router = APIRouter(prefix="/bug-report", tags=["bug-report"])
logger = logging.getLogger(__name__)
class BugReportRequest(BaseModel):
description: str
email: str | None = None
screenshot_base64: str | None = None
include_support_info: bool = True
debug_logs: str | None = None
class BugReportResponse(BaseModel):
success: bool
message: str
issue_url: str | None = None
issue_number: int | None = None
class StartLoggingResponse(BaseModel):
started: bool
was_debug: bool
class StopLoggingResponse(BaseModel):
logs: str
@router.post("/start-logging", response_model=StartLoggingResponse)
async def start_logging(
_: User | None = RequirePermissionIfAuthEnabled(Permission.SETTINGS_UPDATE),
):
"""Enable debug logging and push all printers for fresh data."""
async with async_session() as db:
was_debug, _ = await _get_debug_setting(db)
if not was_debug:
async with async_session() as db:
await _set_debug_setting(db, True)
_apply_log_level(True)
logger.info("Bug report: enabled debug logging")
for printer_id in list(printer_manager._clients.keys()):
try:
printer_manager.request_status_update(printer_id)
except Exception:
logger.debug("Failed to push_all for printer %s", printer_id)
return StartLoggingResponse(started=True, was_debug=was_debug)
@router.post("/stop-logging", response_model=StopLoggingResponse)
async def stop_logging(
was_debug: bool = Query(default=False),
_: User | None = RequirePermissionIfAuthEnabled(Permission.SETTINGS_READ),
):
"""Collect logs and restore previous log level."""
logs = await _get_recent_sanitized_logs()
if not was_debug:
async with async_session() as db:
await _set_debug_setting(db, False)
_apply_log_level(False)
logger.info("Bug report: restored normal logging")
return StopLoggingResponse(logs=logs)
@router.post("/submit", response_model=BugReportResponse)
async def submit_bug_report(
report: BugReportRequest,
_: User | None = RequirePermissionIfAuthEnabled(Permission.SETTINGS_READ),
):
"""Submit a bug report. Requires auth when authentication is enabled."""
support_info = None
if report.include_support_info:
try:
support_info = await _collect_support_info()
if report.debug_logs:
support_info["recent_logs"] = report.debug_logs
except Exception:
logger.exception("Failed to collect support info for bug report")
result = await submit_report(
description=report.description,
reporter_email=report.email,
screenshot_base64=report.screenshot_base64,
support_info=support_info,
)
return BugReportResponse(**result)