feat(infra): auto-commit con 8 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
---
|
||||
name: sign_metabase_embed_jwt
|
||||
kind: function
|
||||
lang: py
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def sign_metabase_embed_jwt(secret: str, resource_type: str, resource_id: int, base_url: str, params: dict | None = None, exp_seconds: int = 3600, theme: str | None = None, bordered: bool = True, titled: bool = True) -> dict"
|
||||
description: "Firma un JWT de static-embedding de Metabase (HS256 con PyJWT) y construye la URL del iframe (/embed/<type>/<token>#opciones). Soporta question y dashboard, params locked/enabled, TTL configurable y tema opcional."
|
||||
tags: [metabase, embed, jwt]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: ["jwt", "time"]
|
||||
tested: true
|
||||
tests: ["test_firma_y_decodifica_round_trip", "test_resource_type_invalido_lanza_valueerror", "test_embed_url_dashboard"]
|
||||
test_file_path: "python/functions/infra/sign_metabase_embed_jwt_test.py"
|
||||
file_path: "python/functions/infra/sign_metabase_embed_jwt.py"
|
||||
params:
|
||||
- name: secret
|
||||
desc: "Secret de embedding de Metabase (Settings > Embedding). NUNCA va al cliente."
|
||||
- name: resource_type
|
||||
desc: '"question" o "dashboard" — tipo del recurso a embeber.'
|
||||
- name: resource_id
|
||||
desc: "Id numerico de la card o dashboard en Metabase."
|
||||
- name: base_url
|
||||
desc: 'URL base de la instancia, ej. "https://reports.autingo.es".'
|
||||
- name: params
|
||||
desc: "Parametros de embedding locked/enabled (dict). Default {}."
|
||||
- name: exp_seconds
|
||||
desc: "TTL del token en segundos desde ahora. Default 3600 (1h)."
|
||||
- name: theme
|
||||
desc: 'Tema opcional: "night" | "transparent" | None.'
|
||||
- name: bordered
|
||||
desc: "Si el iframe muestra borde. Default True."
|
||||
- name: titled
|
||||
desc: "Si el iframe muestra titulo. Default True."
|
||||
output: 'dict con {"token": jwt str, "embed_url": url completa /embed/<type>/<token>#opciones, "exp": unix int}.'
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join("python", "functions"))
|
||||
from infra import sign_metabase_embed_jwt
|
||||
|
||||
# El secret lo pasa el caller (p.ej. desde pass: metabase/aurgi-embed-secret)
|
||||
result = sign_metabase_embed_jwt(
|
||||
secret=os.environ["MB_EMBED_SECRET"],
|
||||
resource_type="question",
|
||||
resource_id=8048,
|
||||
base_url="https://reports.autingo.es",
|
||||
)
|
||||
print(result["embed_url"])
|
||||
# https://reports.autingo.es/embed/question/<jwt>#bordered=true&titled=true
|
||||
print(result["exp"]) # unix timestamp de expiracion
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando necesites embeder una card/dashboard de Metabase en un iframe sin exponerla publicamente: firma server-side en cada carga, nunca hardcodees el token.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- El `secret` NUNCA va al cliente — la firma se hace server-side y solo viaja el token al iframe.
|
||||
- El token expira (`exp_seconds`, default 1h). Refirma en cada carga; no caches el token.
|
||||
- La card/dashboard necesita `enable_embedding=true` en Metabase, o el endpoint de embed devuelve error.
|
||||
- Los `params` deben estar registrados en `embedding_params` como `locked` o `enabled` en Metabase, o se ignoran silenciosamente.
|
||||
- Verificado contra reports.autingo.es: el endpoint `/api/embed/card/<token>/query` devuelve 202 + filas con token valido, 400 con token manipulado.
|
||||
Reference in New Issue
Block a user