feat: add favicon.ico and gate model write APIs by env flag

- Generate and serve real /favicon.ico from static assets
- Update HTML to use /favicon.ico
- Add ENABLE_MODEL_RW_API setting (default: false)
- Disable POST/DELETE model endpoints by default
- Hide write endpoints from OpenAPI when disabled
- Return 404 for write endpoints when disabled
- Update env.example with ENABLE_MODEL_RW_API documentation
- Update README and PRD with R/W API policy and remote compose notes
- Add tests to verify write endpoints are disabled by default
This commit is contained in:
Luca Sacchi Ricciardi
2026-04-24 19:35:24 +02:00
parent 893376dc14
commit 32b1130632
9 changed files with 69 additions and 9 deletions
+19 -2
View File
@@ -13,6 +13,15 @@ from app.config import settings
logger = logging.getLogger(__name__)
router = APIRouter()
def ensure_rw_api_enabled() -> None:
"""Blocca le API di scrittura se non abilitate esplicitamente."""
if not settings.ENABLE_MODEL_RW_API:
raise HTTPException(
status_code=404,
detail="Endpoint non disponibile"
)
class ModelInfo(BaseModel):
"""Informazioni su un modello"""
name: str
@@ -165,7 +174,10 @@ async def get_model(model_name: str):
detail="Errore nel recupero del modello"
)
@router.post("/models/{model_name}/pull")
@router.post(
"/models/{model_name}/pull",
include_in_schema=settings.ENABLE_MODEL_RW_API
)
async def pull_model(model_name: str):
"""
Scarica/carica un modello in Ollama
@@ -176,6 +188,7 @@ async def pull_model(model_name: str):
Returns:
dict: Status del download
"""
ensure_rw_api_enabled()
try:
response = requests.post(
f"{settings.OLLAMA_HOST}/api/pull",
@@ -198,7 +211,10 @@ async def pull_model(model_name: str):
detail="Errore nel pull del modello"
)
@router.delete("/models/{model_name}")
@router.delete(
"/models/{model_name}",
include_in_schema=settings.ENABLE_MODEL_RW_API
)
async def delete_model(model_name: str):
"""
Elimina un modello da Ollama
@@ -209,6 +225,7 @@ async def delete_model(model_name: str):
Returns:
dict: Confirmazione eliminazione
"""
ensure_rw_api_enabled()
try:
response = requests.delete(
f"{settings.OLLAMA_HOST}/api/delete",
+1
View File
@@ -16,6 +16,7 @@ class Settings(BaseSettings):
API_HOST: str = "0.0.0.0"
API_PORT: int = 8000
API_WORKERS: int = 4
ENABLE_MODEL_RW_API: bool = False
# CORS
CORS_ORIGINS: str = "http://localhost:3000,http://localhost:5173,http://localhost:8000"
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+1 -1
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LLM Monitor - Dashboard Ollama</title>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🦙</text></svg>">
<link rel="icon" href="/favicon.ico" sizes="any">
<!-- Tailwind CSS (compiled for production) -->
<link rel="stylesheet" href="/static/css/output.css">
<!-- Fallback CDN for development (if output.css not available) -->