--- name: metabase_client_from_pass kind: function lang: py domain: infra version: "1.0.0" purity: impure signature: "def metabase_client_from_pass(pass_key: str, base_url: str, mode: str = 'auto') -> MetabaseClient | dict" description: "Lee las credenciales de Metabase desde pass y devuelve un MetabaseClient autenticado, en una sola llamada. Elimina el patron inline repetido de cargar la credencial del password store y montar el cliente. Soporta dos instancias: API-key (metabase/aurgi-api-key -> header X-API-KEY) y usuario/password (captacion/metabase multi-linea -> login POST /api/session). mode='auto' detecta el formato. Compone pass_get_secret + parse_metabase_secret + metabase_auth/MetabaseClient sin reimplementarlos. Devuelve el cliente o {status:error, error} sin lanzar." tags: [metabase, pass, secret, credential, auth, client] uses_functions: ["pass_get_secret_py_infra", "parse_metabase_secret_py_infra", "metabase_auth_py_infra"] uses_types: [] params: - name: pass_key desc: "Ruta del secreto en el password store (p.ej. 'metabase/aurgi-api-key' o 'captacion/metabase')." - name: base_url desc: "URL base de la instancia Metabase (p.ej. 'https://reports.autingo.es' o 'http://localhost:3030')." - name: mode desc: "'api_key', 'session' o 'auto' (default). En auto se detecta el formato del secreto: una sola linea de clave -> api_key; multi-linea con email/usuario -> session." output: "MetabaseClient autenticado en exito. En fallo (sin lanzar): {status:'error', error:str} para secreto inexistente en pass, formato no parseable, o fallo de autenticacion contra Metabase." returns: [] returns_optional: true error_type: "error_go_core" imports: [subprocess, httpx] tested: true tests: ["test_api_key_builds_client_with_x_api_key", "test_session_secret_parsed_and_auth_called", "test_auto_mode_detects_session", "test_missing_secret_returns_error_dict", "test_session_without_email_returns_error_dict"] test_file_path: "python/functions/metabase/metabase_client_from_pass_test.py" file_path: "python/functions/metabase/metabase_client_from_pass.py" --- ## Ejemplo ```python import sys sys.path.insert(0, "python/functions") from metabase.metabase_client_from_pass import metabase_client_from_pass # Aurgi (API-key en pass, header X-API-KEY): client = metabase_client_from_pass( "metabase/aurgi-api-key", "https://reports.autingo.es", mode="api_key") # client.request("GET", "/api/user/current") # Captacion (usuario/password multi-linea en pass, login /api/session): client = metabase_client_from_pass( "captacion/metabase", "http://localhost:3030", mode="session") # Sin especificar mode: se autodetecta por el formato del secreto. client = metabase_client_from_pass("metabase/aurgi-api-key", "https://reports.autingo.es") ``` ## Cuando usarla Cuando necesites un `MetabaseClient` autenticado y la credencial vive en `pass`: en vez de escribir a mano el `pass show ...` + parseo + `metabase_auth` / `MetabaseClient(...)`, llama a esta funcion con la ruta del secreto y la URL. Cubre tanto instancias con API-key (Aurgi) como con usuario/password (captacion). Es el punto de entrada unico para abrir un cliente desde el password store. ## Gotchas - **Impura**: lanza el subproceso `pass show` y abre conexion HTTP a Metabase. El secreto nunca se logea, pero el `MetabaseClient` retornado lleva el token en memoria. - En `mode='session'` el secreto debe tener una linea de usuario con prefijo `email:` / `login:` / `username:` / `user:`; si falta, devuelve error dict (no lanza). - La deteccion de API-key se basa en que la clave empieza por `mb_` (lo gestiona `MetabaseClient`). Una API-key con otro prefijo se enviaria como session token -> usa `mode='api_key'` explicito si tu key no empieza por `mb_`. - Cierra el cliente cuando termines: `client.close()` o usalo como context manager (`with metabase_client_from_pass(...) as client:`). - Los fallos de auth (401, instancia caida) se devuelven como `{status:'error', error}` — comprueba el tipo del retorno antes de usarlo.