Enforce http(s) schema on service base_url fields

Add a shared ServiceBaseUrl type (BeforeValidator + Field description) in
integrations/base.py and apply it to base_url across all six service configs
(grafana, prometheus, alertmanager, jellyfin, jellyseerr, nextcloud). Missing
http:// or https:// schema now fails fast with a clear 422 instead of breaking
HTTP clients silently. Tests cover reject/accept cases; REQUIREMENTS updated.
This commit is contained in:
Developer
2026-06-26 09:52:20 +00:00
parent 56b919ea1f
commit eebc86a52b
9 changed files with 71 additions and 9 deletions
+22 -1
View File
@@ -8,6 +8,7 @@ from unittest.mock import patch
import pytest
from cryptography.fernet import Fernet
from fastapi.testclient import TestClient
from pydantic import ValidationError
from media_library_viewer_api.dependencies import get_settings_store
from media_library_viewer_api.integrations.registry import (
@@ -244,7 +245,8 @@ def test_invalid_config_rejected(client):
"/api/services/instances",
json={"service_type": "grafana", "name": "x", "config": {"base_url": ""}},
)
# Pydantic accepts empty string; force a real validation error via bad type.
assert response.status_code == 422
# Force a real validation error via bad type.
response = client.post(
"/api/services/instances",
json={"service_type": "grafana", "name": "x", "config": {"timeout_seconds": "fast"}},
@@ -252,6 +254,25 @@ def test_invalid_config_rejected(client):
assert response.status_code == 422
@pytest.mark.parametrize(
"bad_url", ["grafana.example.com", "localhost:3000", "//grafana.example.com", "ftp://grafana.example.com"]
)
def test_service_base_url_requires_http_schema(bad_url):
"""Every service base_url must include an http:// or https:// schema."""
model = get_service_definition("grafana").config_model
with pytest.raises(ValidationError):
model.model_validate({"base_url": bad_url, "timeout_seconds": 5})
@pytest.mark.parametrize(
"service_type", ["grafana", "prometheus", "alertmanager", "jellyfin", "jellyseerr", "nextcloud"]
)
def test_service_base_url_accepts_absolute_urls(service_type):
model = get_service_definition(service_type).config_model
instance = model.model_validate({"base_url": "https://example.com"})
assert instance.base_url == "https://example.com"
def test_unknown_secret_field_rejected(client):
response = client.post(
"/api/services/instances",