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",