Add JWT authentication with user/password login, role-based access control, and Bearer token support while maintaining legacy API key compatibility for transition; update README with comprehensive JWT security guidelines, installation instructions for Python/SSH, development startup scripts (.env, run_dev.sh/ps1), and migrate all API examples to JWT authentication; update Ansible inventory SSH key paths from Docker container paths to local user paths
This commit is contained in:
@@ -2,12 +2,18 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add project root to path
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
os.environ.setdefault(
|
||||
"DATABASE_URL",
|
||||
f"sqlite+aiosqlite:///{Path(__file__).resolve().parent / 'test_homelab.db'}",
|
||||
)
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
|
||||
@@ -17,6 +23,7 @@ from app.crud.bootstrap_status import BootstrapStatusRepository
|
||||
from app.crud.task import TaskRepository
|
||||
from app.crud.schedule import ScheduleRepository
|
||||
from app.crud.log import LogRepository
|
||||
from app.crud.app_setting import AppSettingRepository
|
||||
|
||||
# Configure pytest-asyncio
|
||||
pytestmark = pytest.mark.asyncio
|
||||
@@ -202,5 +209,20 @@ async def test_create_schedule_run(setup_db):
|
||||
assert run.status == "running"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_app_settings_set_get(setup_db):
|
||||
async with async_session_maker() as session:
|
||||
repo = AppSettingRepository(session)
|
||||
|
||||
row = await repo.set_value("metrics_collection_interval", "10m")
|
||||
await session.commit()
|
||||
|
||||
assert row.key == "metrics_collection_interval"
|
||||
assert row.value == "10m"
|
||||
|
||||
value = await repo.get_value("metrics_collection_interval")
|
||||
assert value == "10m"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-v"])
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
"""Tests for help documentation download endpoints helpers.
|
||||
|
||||
We keep this lightweight by validating that the help endpoints are registered
|
||||
and that the PDF generator returns a non-empty PDF payload.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
# Ensure project root on path
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_help_markdown_builder_exists_and_non_empty():
|
||||
from app import app_optimized # type: ignore
|
||||
|
||||
assert hasattr(app_optimized, "_build_help_markdown")
|
||||
md = app_optimized._build_help_markdown()
|
||||
assert isinstance(md, str)
|
||||
assert len(md) > 100
|
||||
assert "Guide d'Utilisation" in md or "Démarrage Rapide" in md
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_help_pdf_generator_returns_pdf_bytes():
|
||||
pytest.importorskip("reportlab")
|
||||
pytest.importorskip("PIL")
|
||||
from app import app_optimized # type: ignore
|
||||
|
||||
md = app_optimized._build_help_markdown()
|
||||
pdf_bytes = app_optimized._markdown_to_pdf_bytes(md)
|
||||
|
||||
assert isinstance(pdf_bytes, (bytes, bytearray))
|
||||
assert len(pdf_bytes) > 1000
|
||||
assert bytes(pdf_bytes[:4]) == b"%PDF"
|
||||
|
||||
|
||||
def test_help_routes_registered():
|
||||
from app.app_optimized import app # type: ignore
|
||||
|
||||
paths = {r.path for r in app.routes}
|
||||
assert "/api/help/documentation.md" in paths
|
||||
assert "/api/help/documentation.pdf" in paths
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user