--- name: fetch_iab_gvl kind: function lang: py domain: cybersecurity version: "1.0.0" purity: impure signature: "def fetch_iab_gvl(out_path: str = \"\", url: str = \"\", lang: str = \"\") -> dict" description: "Descarga y parsea la Global Vendor List (GVL) de IAB Europe TCF: el catalogo maestro de data brokers (vendors) con sus propositos de tratamiento, intereses legitimos, special purposes, features y categorias de datos. Recon de privacidad/tracking." tags: [consent, tcf, gvl, iab, privacy, data-brokers, vendor-list, recon, cmp] params: - name: out_path desc: "Ruta de archivo donde guardar el JSON crudo descargado. Si vacio no guarda nada. Crea los directorios padre si no existen." - name: url desc: "Endpoint de la GVL. Si vacio usa el endpoint TCF v3.2 por defecto (vendor-list.consensu.org/v3/vendor-list.json) y, si falla, hace fallback al v2." - name: lang desc: "Codigo de idioma ISO opcional (ej. es). NO cambia el endpoint principal: las traducciones de propositos viven en endpoints aparte (purposes-.json). Hoy solo se acepta el parametro; no se descargan traducciones." output: "dict resumen de la GVL. En exito status=ok con versiones (gvlSpecificationVersion, vendorListVersion, tcfPolicyVersion), lastUpdated, contadores (n_vendors, n_purposes, n_specialPurposes, n_features, n_dataCategories) y los mapas vendors / purposes / dataCategories indexados por id (string). En fallo de red o parseo status=error con el mensaje; nunca lanza excepcion." uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_py_core" imports: [] tested: false tests: [] test_file_path: "" file_path: "python/functions/cybersecurity/fetch_iab_gvl.py" --- ## Ejemplo ```python import sys, os sys.path.insert(0, os.path.join("python", "functions")) from cybersecurity.fetch_iab_gvl import fetch_iab_gvl # Descarga real del endpoint v3 (fallback automatico a v2 si falla) y guarda # el JSON crudo para inspeccion posterior. gvl = fetch_iab_gvl(out_path="/tmp/gvl.json") print(gvl["status"]) # ok print(gvl["vendorListVersion"]) # ej. 163 print(gvl["n_vendors"]) # > 1000 # Mirar un vendor concreto (Google = id 755 en TCF v3) print(gvl["vendors"].get("755", {}).get("name")) ``` Lanzable directo desde la raiz del registry: ```bash python/.venv/bin/python3 python/functions/cybersecurity/fetch_iab_gvl.py /tmp/gvl.json ``` ## Cuando usarla Usala cuando hagas recon de privacidad/tracking de un sitio web y necesites mapear los `vendorId` que aparecen en una cookie de consentimiento (TC String / __tcfapi) a nombres reales de empresas, sus propositos de tratamiento y sus politicas de privacidad. Es el primer paso para auditar quien recibe los datos del usuario via un CMP que implementa el IAB Europe TCF. Tambien para construir un dataset local de data brokers (los `vendors`) y sus declaraciones de datos. ## Gotchas - **Impura, hace HTTP.** Depende de que `vendor-list.consensu.org` este accesible. En fallo de red o JSON corrupto devuelve `{"status": "error", "error": "..."}` y NO lanza — el caller DEBE comprobar `status` antes de usar el resultado. - **Fallback v3 -> v2.** Si no pasas `url`, intenta v3 y luego v2. Si pasas `url` explicito, solo se intenta esa (sin fallback). - **`policyUrl` derivado.** En GVL v3 los vendors NO tienen un campo `policyUrl` directo; la URL de privacidad vive en `urls[].privacy` (lista por idioma). La funcion la deriva tolerando ambos formatos (v2/v3) y devuelve `""` si no hay. - **`dataCategories` puede faltar** en versiones antiguas (v2). Se tolera la ausencia: `n_dataCategories` sera 0 y el mapa estara vacio. - **`lang` no descarga traducciones.** El parametro existe para la firma futura, pero hoy el resumen siempre viene del endpoint principal (textos en ingles). Las traducciones de propositos estan en endpoints separados (`.../purposes-es.json`) que esta funcion no consulta todavia. - **Payload grande** (~varios MB, >1000 vendors). El dict resumido recorta cada vendor a los campos utiles, pero sigue siendo grande: no lo imprimas entero.