Un respaldo de búsqueda sin credencial se omite en vez de romper la carga
El CI, apenas empezó a ejecutarse de verdad, hizo fallar dos de sus tres trabajos. La causa es un defecto de diseño, no del CI: la config del agente declara a Brave como respaldo, y la validación exigía la credencial para poder *leer* el archivo. Como la config vive en el repositorio y la credencial no, un clon limpio quedaba sin poder cargar su propia configuración. Mis pruebas en Gigastar no lo veían porque acá el archivo .env existe. Ahora se distingue por rol, que es lo que corresponde: - El primario sin credencial sigue siendo error fatal. Sin él no queda ninguna búsqueda en pie, y descubrirlo en la primera consulta real es tarde. - Un respaldo sin credencial se cae de la cadena y el primario sigue andando. Degradarse es la respuesta correcta: tener red de seguridad es mejor que no tenerla, pero no tenerla es mejor que no arrancar. Omitir no es esconder. La propiedad respaldos_omitidos deja el motivo a la vista, y build_backend emite un aviso al construir la cadena, que es el punto por el que pasa cualquier entrypoint que use búsqueda. Verificado escondiendo .env y corriendo la suite y el validador como lo haría un clon limpio: 124 tests en verde con credencial y sin ella. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+41
-10
@@ -193,7 +193,7 @@ def test_el_primario_no_necesita_credenciales():
|
||||
assert isinstance(primero, DuckDuckGoBackend)
|
||||
|
||||
|
||||
def test_searxng_exige_url():
|
||||
def test_searxng_como_primario_exige_url():
|
||||
with pytest.raises(ValueError, match="searxng_url"):
|
||||
SearchConfig(backend="searxng")
|
||||
|
||||
@@ -307,22 +307,53 @@ def test_el_fallback_repetido_no_se_duplica():
|
||||
assert cfg.cadena == ["duckduckgo", "brave"]
|
||||
|
||||
|
||||
def test_un_fallback_sin_credencial_falla_al_arrancar():
|
||||
"""No en la primera consulta real — que es justo cuando el primario ya
|
||||
falló y el respaldo tiene que funcionar."""
|
||||
with pytest.raises(ValueError, match="fallback 'brave'"):
|
||||
SearchConfig(backend="duckduckgo", fallbacks=["brave"])
|
||||
def test_un_respaldo_sin_credencial_se_omite_en_vez_de_romper():
|
||||
"""La config vive en el repositorio y las credenciales no.
|
||||
|
||||
Exigir la clave para poder *leer* la config dejaba el proyecto sin poder
|
||||
clonarse: el CI y cualquier máquina nueva fallaban antes de empezar. El
|
||||
respaldo se cae de la cadena; el primario sigue funcionando.
|
||||
"""
|
||||
cfg = SearchConfig(backend="duckduckgo", fallbacks=["brave"])
|
||||
assert cfg.cadena == ["duckduckgo"]
|
||||
|
||||
|
||||
def test_brave_como_primario_tambien_exige_credencial():
|
||||
with pytest.raises(ValueError, match="backend 'brave'"):
|
||||
def test_el_respaldo_omitido_queda_a_la_vista():
|
||||
"""Omitir no es esconder: quedarse sin red de seguridad tiene que verse."""
|
||||
cfg = SearchConfig(backend="duckduckgo", fallbacks=["brave"])
|
||||
assert cfg.respaldos_omitidos == [("brave", "ENLACE_BRAVE_API_KEY")]
|
||||
|
||||
|
||||
def test_construir_la_cadena_avisa_del_respaldo_faltante():
|
||||
cfg = SearchConfig(backend="duckduckgo", fallbacks=["brave"])
|
||||
with pytest.warns(RuntimeWarning, match="ENLACE_BRAVE_API_KEY"):
|
||||
build_backend(cfg)
|
||||
|
||||
|
||||
def test_con_credencial_el_respaldo_si_entra():
|
||||
cfg = SearchConfig(backend="duckduckgo", fallbacks=["brave"], brave_api_key="x")
|
||||
assert cfg.cadena == ["duckduckgo", "brave"]
|
||||
assert cfg.respaldos_omitidos == []
|
||||
|
||||
|
||||
def test_el_primario_sin_credencial_si_es_fatal():
|
||||
"""Sin primario no queda ninguna búsqueda en pie: eso no se degrada."""
|
||||
with pytest.raises(ValueError, match="primario 'brave'"):
|
||||
SearchConfig(backend="brave")
|
||||
|
||||
|
||||
def test_la_config_del_repo_declara_brave_de_respaldo():
|
||||
def test_la_config_del_repo_carga_sin_credenciales(monkeypatch):
|
||||
"""Un clon limpio, sin .env, tiene que poder leer la config del repositorio.
|
||||
|
||||
Es exactamente lo que rompió en el CI: la validación exigía la clave de
|
||||
Brave para poder cargar el archivo.
|
||||
"""
|
||||
monkeypatch.delenv("ENLACE_BRAVE_API_KEY", raising=False)
|
||||
monkeypatch.setattr("enlace.config.load.load_dotenv", lambda *a, **k: [])
|
||||
cfg = load_agent_config()
|
||||
assert cfg.search.backend == "duckduckgo"
|
||||
assert "brave" in cfg.search.fallbacks
|
||||
assert "brave" in cfg.search.fallbacks # la intención queda declarada
|
||||
assert cfg.search.cadena == ["duckduckgo"] # pero no se usa sin credencial
|
||||
|
||||
|
||||
# --- parser de Brave -------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user