From 830f2d34de2d3ea44f84f4896d389b8134dc336e Mon Sep 17 00:00:00 2001 From: Egutierrez Date: Fri, 5 Jun 2026 16:33:35 +0200 Subject: [PATCH] feat(browser): funciones idempotentes para config de sistema de chromium Cierra el gap de reproducibilidad entre PCs del proyecto web_scraping: la organizacion de extensiones y el CDP global dejaban de ser pasos manuales con sudo documentados en prosa. - apply_chromium_extension_policy: escribe ExtensionInstallForcelist (whitelist via --keep) en /etc/chromium/policies/managed/extensions.json de forma idempotente, con backup automatico y validacion JSON. --dry-run previsualiza sin tocar el sistema. - apply_chromium_cdp_flag: gestiona /etc/chromium.d/cdp (CDP global). Loopback por defecto, --network para bind 0.0.0.0 (con aviso), --remove para desactivar, --dry-run para previsualizar. Idempotente con backup. Ambas: dominio browser, grupo navegator, impuras (escriben en /etc via sudo), guard de auto-ejecucion (ejecutables con fn run y sourceables). Docs del proyecto (CONVENTIONS.md reglas 8/9, CHROMIUM_SYSTEM.md inventario + tabla accionable) ahora apuntan a 'fn run apply_chromium_*' como metodo canonico en vez de editar los archivos de /etc a mano. --- .../browser/apply_chromium_cdp_flag.md | 71 ++++++ .../browser/apply_chromium_cdp_flag.sh | 205 ++++++++++++++++++ .../apply_chromium_extension_policy.md | 66 ++++++ .../apply_chromium_extension_policy.sh | 205 ++++++++++++++++++ 4 files changed, 547 insertions(+) create mode 100644 bash/functions/browser/apply_chromium_cdp_flag.md create mode 100644 bash/functions/browser/apply_chromium_cdp_flag.sh create mode 100644 bash/functions/browser/apply_chromium_extension_policy.md create mode 100644 bash/functions/browser/apply_chromium_extension_policy.sh diff --git a/bash/functions/browser/apply_chromium_cdp_flag.md b/bash/functions/browser/apply_chromium_cdp_flag.md new file mode 100644 index 00000000..031e0357 --- /dev/null +++ b/bash/functions/browser/apply_chromium_cdp_flag.md @@ -0,0 +1,71 @@ +--- +name: apply_chromium_cdp_flag +kind: function +lang: bash +domain: browser +version: "1.0.0" +purity: impure +signature: "apply_chromium_cdp_flag [--port N] [--network] [--fragment-path ] [--remove] [--dry-run]" +description: "Gestiona de forma idempotente el fragmento /etc/chromium.d/cdp que activa Chrome DevTools Protocol global en todo chromium que el usuario lance en el equipo. Escribe, actualiza o borra el fragmento con backup automático." +tags: [navegator, chromium, cdp, devtools, browser, automation, infra] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +tested: false +tests: [] +test_file_path: "" +params: + - name: "--port N" + desc: "Puerto TCP donde Chromium escuchará conexiones CDP. Default 9222." + - name: "--network" + desc: "Si se pasa, añade --remote-debugging-address=0.0.0.0 (accesible desde la red local). Por defecto solo loopback (127.0.0.1). Imprime advertencia de seguridad." + - name: "--fragment-path " + desc: "Ruta del fragmento a escribir/borrar. Default /etc/chromium.d/cdp." + - name: "--remove" + desc: "Borra el fragmento (desactiva CDP global). Idempotente: si no existe, no-op." + - name: "--dry-run" + desc: "Imprime el fragmento que se escribiría sin tocar nada. No requiere sudo." +output: "Sale 0 en éxito (aplicado, ya-aplicado, o eliminado). Sale != 0 en error con mensaje a stderr. En caso de actualización imprime ruta del backup creado." +file_path: "bash/functions/browser/apply_chromium_cdp_flag.sh" +--- + +## Ejemplo + +```bash +# Activar CDP global en loopback puerto 9222 (proyecto web_scraping, regla 8) +source bash/functions/browser/apply_chromium_cdp_flag.sh +apply_chromium_cdp_flag + +# Previsualizar el fragmento sin escribir nada (no requiere sudo) +apply_chromium_cdp_flag --port 9222 --dry-run + +# Puerto alternativo (para correr en paralelo al navegador del usuario) +apply_chromium_cdp_flag --port 9333 + +# Activar expuesto a la red local (RIESGO: cualquier host de la LAN puede controlar el navegador) +apply_chromium_cdp_flag --port 9222 --network + +# Desactivar CDP global +apply_chromium_cdp_flag --remove + +# Ruta personalizada (útil en pruebas o entornos chroot) +apply_chromium_cdp_flag --port 9222 --fragment-path /tmp/test_cdp_fragment --dry-run +``` + +## Cuando usarla + +Al preparar un PC nuevo para controlar el chromium diario del usuario vía CDP (primer setup del proyecto `web_scraping`, regla 8). Al cambiar el puerto CDP del sistema. Al desactivar esa capacidad antes de prestar o formatear el equipo. Sustituye el paso manual "crear `/etc/chromium.d/cdp` con sudo" documentado en `CHROMIUM_SYSTEM.md`. + +## Gotchas + +- **Requiere sudo** para escribir bajo `/etc/`. En este equipo usar `pass show claude/sudo | sudo -S apply_chromium_cdp_flag` o ejecutar como root. +- **`--network` (0.0.0.0) es un riesgo de seguridad serio**: cualquier máquina en la red local puede conectarse al puerto CDP y controlar Chromium completamente (leer cookies, sesiones, inyectar JavaScript). Solo usar en entornos de red aislados o laboratorios. +- **El chromium ya abierto antes del cambio no hereda el flag** hasta que se reinicie. El fragmento solo se aplica en el próximo arranque de `/usr/bin/chromium`. +- **Dos procesos chromium no pueden compartir el mismo puerto**. Si el usuario ya tiene un chromium con CDP en 9222, la automatización dedicada debe arrancar con `chrome_launch_go_browser` en otro puerto (ej. 9333) o usar `--port 9333` en esta función. +- **Idempotente**: si el fragmento ya existe con contenido idéntico, la función sale 0 sin tocar nada ni crear backup. +- **Backup automático**: al sobreescribir, crea `.bak.YYYYMMDD`. Si ya existe un backup del mismo día, no lo sobreescribe (el primero del día se preserva). +- **Validación post-escritura**: tras escribir, verifica con `grep` que la línea `export CHROMIUM_FLAGS` con el puerto correcto quedó en el archivo. Si falla, restaura el backup y sale con error. +- Ver `projects/web_scraping/CHROMIUM_SYSTEM.md` para el contexto completo del sistema CDP de este equipo. diff --git a/bash/functions/browser/apply_chromium_cdp_flag.sh b/bash/functions/browser/apply_chromium_cdp_flag.sh new file mode 100644 index 00000000..270cf4a3 --- /dev/null +++ b/bash/functions/browser/apply_chromium_cdp_flag.sh @@ -0,0 +1,205 @@ +#!/usr/bin/env bash +# apply_chromium_cdp_flag — gestiona el fragmento /etc/chromium.d/cdp que activa CDP global. +# +# Uso: +# apply_chromium_cdp_flag [--port N] [--network] [--fragment-path ] [--remove] [--dry-run] + +apply_chromium_cdp_flag() { + local port=9222 + local network=0 + local fragment_path="/etc/chromium.d/cdp" + local remove=0 + local dry_run=0 + + # Parseo de argumentos + while [[ $# -gt 0 ]]; do + case "$1" in + --port) + port="$2" + shift 2 + ;; + --network) + network=1 + shift + ;; + --fragment-path) + fragment_path="$2" + shift 2 + ;; + --remove) + remove=1 + shift + ;; + --dry-run) + dry_run=1 + shift + ;; + *) + echo "apply_chromium_cdp_flag: argumento desconocido: $1" >&2 + return 1 + ;; + esac + done + + # Validación del puerto + if ! [[ "$port" =~ ^[0-9]+$ ]] || (( port < 1 || port > 65535 )); then + echo "apply_chromium_cdp_flag: puerto inválido: $port (debe ser 1-65535)" >&2 + return 1 + fi + + # Construcción del contenido del fragmento + local flags_line + if (( network )); then + echo "ADVERTENCIA DE SEGURIDAD: --network activa --remote-debugging-address=0.0.0.0." >&2 + echo "El navegador quedará expuesto a toda la red local. Cualquier host en la red" >&2 + echo "podrá controlar Chromium remotamente y leer todas las sesiones abiertas." >&2 + flags_line='export CHROMIUM_FLAGS="$CHROMIUM_FLAGS --remote-debugging-port='"${port}"' --remote-allow-origins=* --remote-debugging-address=0.0.0.0"' + else + flags_line='export CHROMIUM_FLAGS="$CHROMIUM_FLAGS --remote-debugging-port='"${port}"' --remote-allow-origins=*"' + fi + + local mode_label + if (( network )); then + mode_label="network (0.0.0.0)" + else + mode_label="loopback (127.0.0.1)" + fi + + local fragment_content + fragment_content="# CDP global para automatizacion del navegador del usuario (proyecto web_scraping, regla 8). +# Bind ${mode_label} por defecto: el puerto solo +# es accesible desde 127.0.0.1, no desde la red. +${flags_line}" + + # Modo --dry-run: solo mostrar y salir + if (( dry_run )); then + echo "--- dry-run: fragmento que se escribiría en ${fragment_path} ---" + echo "${fragment_content}" + echo "--- fin dry-run ---" + return 0 + fi + + # Modo --remove + if (( remove )); then + if [[ ! -e "$fragment_path" ]]; then + echo "apply_chromium_cdp_flag: ${fragment_path} no existe, nada que borrar." + return 0 + fi + + local backup_path="${fragment_path}.bak.$(date +%Y%m%d)" + if [[ ! -e "$backup_path" ]]; then + if [[ $EUID -eq 0 ]]; then + cp "$fragment_path" "$backup_path" + else + sudo cp "$fragment_path" "$backup_path" || { + echo "apply_chromium_cdp_flag: no se pudo crear backup en ${backup_path}" >&2 + return 1 + } + fi + fi + + if [[ $EUID -eq 0 ]]; then + rm "$fragment_path" + else + sudo rm "$fragment_path" || { + echo "apply_chromium_cdp_flag: no se pudo borrar ${fragment_path}" >&2 + return 1 + } + fi + + echo "apply_chromium_cdp_flag: fragmento eliminado (backup: ${backup_path})" + echo "Nota: el chromium ya abierto antes de este cambio no lo hereda hasta reiniciarlo." + return 0 + fi + + # Idempotencia: comparar con contenido actual + if [[ -f "$fragment_path" ]]; then + local current_content + current_content=$(cat "$fragment_path" 2>/dev/null) + if [[ "$current_content" == "$fragment_content" ]]; then + echo "apply_chromium_cdp_flag: ya aplicado, sin cambios (${fragment_path})." + return 0 + fi + fi + + # Crear directorio si falta + local fragment_dir + fragment_dir=$(dirname "$fragment_path") + if [[ ! -d "$fragment_dir" ]]; then + if [[ $EUID -eq 0 ]]; then + mkdir -p "$fragment_dir" + else + sudo mkdir -p "$fragment_dir" || { + echo "apply_chromium_cdp_flag: no se pudo crear ${fragment_dir}" >&2 + return 1 + } + fi + fi + + # Backup si ya existe y difiere + if [[ -e "$fragment_path" ]]; then + local backup_path="${fragment_path}.bak.$(date +%Y%m%d)" + if [[ ! -e "$backup_path" ]]; then + if [[ $EUID -eq 0 ]]; then + cp "$fragment_path" "$backup_path" + else + sudo cp "$fragment_path" "$backup_path" || { + echo "apply_chromium_cdp_flag: no se pudo crear backup en ${backup_path}" >&2 + return 1 + } + fi + echo "apply_chromium_cdp_flag: backup creado en ${backup_path}" + fi + fi + + # Escribir fragmento + local tmpfile + tmpfile=$(mktemp) + printf '%s\n' "$fragment_content" > "$tmpfile" + + if [[ $EUID -eq 0 ]]; then + cp "$tmpfile" "$fragment_path" + chmod 644 "$fragment_path" + else + sudo cp "$tmpfile" "$fragment_path" || { + rm -f "$tmpfile" + echo "apply_chromium_cdp_flag: no se pudo escribir ${fragment_path}" >&2 + return 1 + } + sudo chmod 644 "$fragment_path" 2>/dev/null || true + fi + rm -f "$tmpfile" + + # Validación post-escritura + local expected_line="--remote-debugging-port=${port}" + if ! grep -qF "$expected_line" "$fragment_path" 2>/dev/null; then + echo "apply_chromium_cdp_flag: validación fallida — la línea export no apareció en ${fragment_path}." >&2 + # Restaurar backup si existe + local backup_path="${fragment_path}.bak.$(date +%Y%m%d)" + if [[ -f "$backup_path" ]]; then + if [[ $EUID -eq 0 ]]; then + cp "$backup_path" "$fragment_path" + else + sudo cp "$backup_path" "$fragment_path" 2>/dev/null || true + fi + echo "apply_chromium_cdp_flag: backup restaurado desde ${backup_path}" >&2 + fi + return 1 + fi + + # Resumen final + echo "apply_chromium_cdp_flag: CDP global activado correctamente." + echo " Fragmento : ${fragment_path}" + echo " Puerto : ${port}" + echo " Modo : ${mode_label}" + echo "" + echo "Nota: el chromium ya abierto antes de este cambio no hereda el flag hasta reiniciarlo." + echo "Nota: dos procesos chromium no pueden compartir el mismo puerto; usa --port para" + echo " automatización dedicada que corra en paralelo al navegador del usuario." +} + +# Auto-ejecución al correr el archivo directo (bash file.sh / fn run). Si se hace `source`, +# solo se define la función y no se ejecuta nada. +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + apply_chromium_cdp_flag "$@" +fi diff --git a/bash/functions/browser/apply_chromium_extension_policy.md b/bash/functions/browser/apply_chromium_extension_policy.md new file mode 100644 index 00000000..84150cab --- /dev/null +++ b/bash/functions/browser/apply_chromium_extension_policy.md @@ -0,0 +1,66 @@ +--- +name: apply_chromium_extension_policy +kind: function +lang: bash +domain: browser +version: "1.0.0" +purity: impure +signature: "apply_chromium_extension_policy --keep [--keep ]... [--policy-path ] [--update-url ] [--dry-run]" +description: "Escribe de forma idempotente la política managed de Chromium (ExtensionInstallForcelist) que fuerza la instalación de un conjunto de extensiones en cualquier perfil del navegador. Crea backup con sufijo de fecha si el archivo preexiste y su contenido difiere. Requiere sudo para escribir en /etc; en modo --dry-run no toca el sistema." +tags: [chromium, extensions, policy, browser, navegator, managed-policy, idempotent] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: "--keep " + desc: "ID de extensión de Chrome Web Store a force-instalar (repetible, al menos uno obligatorio). Ejemplo: ddkjiahejlhfcafbddmgiahcphecmpfh (uBlock Origin Lite)." + - name: "--policy-path " + desc: "Ruta del JSON de managed policy. Default: /etc/chromium/policies/managed/extensions.json." + - name: "--update-url " + desc: "URL del servicio de actualización de extensiones. Default: https://clients2.google.com/service/update2/crx." + - name: "--dry-run" + desc: "Imprime el JSON que se escribiría sin tocar el sistema (no requiere sudo)." +output: "Escribe el JSON de política en policy-path y emite a stdout un resumen: extensiones aplicadas, ruta, backup creado y recordatorio de reinicio de Chromium. Sale 0 si la política se aplicó o ya estaba vigente. Sale != 0 en error." +tested: false +tests: [] +test_file_path: "" +file_path: "bash/functions/browser/apply_chromium_extension_policy.sh" +--- + +## Ejemplo + +```bash +# Forzar solo uBlock Origin Lite en todos los perfiles (proyecto web_scraping, regla 9) +source bash/functions/browser/apply_chromium_extension_policy.sh +apply_chromium_extension_policy --keep ddkjiahejlhfcafbddmgiahcphecmpfh + +# Previsualizar sin tocar el sistema (sin sudo) +apply_chromium_extension_policy --keep ddkjiahejlhfcafbddmgiahcphecmpfh --dry-run + +# Forzar varias extensiones a la vez +apply_chromium_extension_policy \ + --keep ddkjiahejlhfcafbddmgiahcphecmpfh \ + --keep cjpalhdlnbpafiamejdnhcphjbkeiagm \ + --policy-path /etc/chromium/policies/managed/extensions.json + +# Usando pass para el sudo no interactivo (setup de este equipo) +# apply_chromium_extension_policy ya usa sudo tee internamente; +# si el entorno requiere pass: ejecutar como root o con SUDO_ASKPASS configurado. +``` + +## Cuando usarla + +Al preparar un PC nuevo o cambiar qué extensiones de Chrome Web Store deben estar presentes en cualquier perfil de Chromium del equipo. Reemplaza el paso manual de editar el JSON de policy con sudo. Indispensable tras un fresh install o cuando se añade o retira una extensión del conjunto obligatorio del proyecto `web_scraping`. + +## Gotchas + +- **Requiere sudo** para escribir en `/etc/chromium/policies/managed/`. En este equipo se alimenta con `pass show claude/sudo | sudo -S ` para operaciones autónomas. +- **Chrome cachea la política en memoria**: hay que cerrar TODOS los procesos Chromium (`pkill -9 chromium`) y relanzar para que el cambio surta efecto en runtime. Alternativa sin cerrar: `chrome://policy` → botón "Reload policies". +- **Idempotente**: si el archivo de policy ya tiene el mismo contenido, la función detecta el no-op y sale 0 sin escribir nada. +- **Backup por día**: si el contenido difiere, crea `.bak.YYYYMMDD`. Si el backup del día ya existe, no lo sobreescribe. Los backups no se limpian automáticamente. +- **`ExtensionInstallForcelist` solo gestiona las extensiones listadas** — no elimina extensiones que el usuario haya instalado manualmente; solo garantiza que las listadas estén instaladas. +- **No aplica a Chrome stable 138+**: en Chrome estable la flag `--load-extension` está desactivada, pero las managed policies siguen siendo el mecanismo correcto para force-install desde Web Store. +- Para referencia del sistema completo: `projects/web_scraping/CHROMIUM_SYSTEM.md`. diff --git a/bash/functions/browser/apply_chromium_extension_policy.sh b/bash/functions/browser/apply_chromium_extension_policy.sh new file mode 100644 index 00000000..b2d05aed --- /dev/null +++ b/bash/functions/browser/apply_chromium_extension_policy.sh @@ -0,0 +1,205 @@ +#!/usr/bin/env bash +# apply_chromium_extension_policy — Escribe de forma idempotente la política managed de Chromium +# que fuerza la instalación de un conjunto de extensiones en CUALQUIER perfil del navegador. + +apply_chromium_extension_policy() { + local policy_path="/etc/chromium/policies/managed/extensions.json" + local update_url="https://clients2.google.com/service/update2/crx" + local dry_run=0 + local -a ext_ids=() + + # --- Parseo de argumentos --- + while [[ $# -gt 0 ]]; do + case "$1" in + --keep) + if [[ -z "${2:-}" ]]; then + echo "apply_chromium_extension_policy: --keep requiere un ID de extensión" >&2 + return 1 + fi + ext_ids+=("$2") + shift 2 + ;; + --policy-path) + if [[ -z "${2:-}" ]]; then + echo "apply_chromium_extension_policy: --policy-path requiere un valor" >&2 + return 1 + fi + policy_path="$2" + shift 2 + ;; + --update-url) + if [[ -z "${2:-}" ]]; then + echo "apply_chromium_extension_policy: --update-url requiere un valor" >&2 + return 1 + fi + update_url="$2" + shift 2 + ;; + --dry-run) + dry_run=1 + shift + ;; + *) + echo "apply_chromium_extension_policy: argumento desconocido: $1" >&2 + echo "Uso: apply_chromium_extension_policy --keep [--keep ]... [--policy-path ] [--update-url ] [--dry-run]" >&2 + return 1 + ;; + esac + done + + # --- Validar que hay al menos una extensión --- + if [[ ${#ext_ids[@]} -eq 0 ]]; then + echo "apply_chromium_extension_policy: se requiere al menos un --keep " >&2 + return 1 + fi + + # --- Construir el JSON --- + local forcelist_entries="" + local first=1 + for id in "${ext_ids[@]}"; do + if [[ $first -eq 0 ]]; then + forcelist_entries+=","$'\n' + fi + forcelist_entries+=" \"${id};${update_url}\"" + first=0 + done + + local new_json + new_json=$(printf '{\n "ExtensionInstallForcelist": [\n%s\n ]\n}\n' "$forcelist_entries") + + # --- Modo dry-run --- + if [[ $dry_run -eq 1 ]]; then + echo "[dry-run] JSON que se escribiría en: ${policy_path}" + echo "---" + echo "$new_json" + echo "---" + echo "[dry-run] No se ha modificado el sistema." + return 0 + fi + + # --- Idempotencia: comparar con contenido actual --- + if [[ -f "$policy_path" ]]; then + local current_content + current_content=$(cat "$policy_path" 2>/dev/null || true) + if [[ "$current_content" == "$new_json" ]]; then + echo "apply_chromium_extension_policy: política ya aplicada (sin cambios). Nada que hacer." + return 0 + fi + fi + + # --- Backup del archivo existente --- + local backup_path="" + if [[ -f "$policy_path" ]]; then + local date_suffix + date_suffix=$(date +%Y%m%d) + backup_path="${policy_path}.bak.${date_suffix}" + if [[ ! -f "$backup_path" ]]; then + echo "apply_chromium_extension_policy: creando backup → ${backup_path}" + if [[ $EUID -ne 0 ]]; then + sudo cp "$policy_path" "$backup_path" || { + echo "apply_chromium_extension_policy: no se pudo crear el backup en ${backup_path}" >&2 + return 1 + } + else + cp "$policy_path" "$backup_path" || { + echo "apply_chromium_extension_policy: no se pudo crear el backup en ${backup_path}" >&2 + return 1 + } + fi + else + echo "apply_chromium_extension_policy: backup del día ya existe (${backup_path}), se omite." + fi + fi + + # --- Crear directorio padre si no existe --- + local policy_dir + policy_dir=$(dirname "$policy_path") + if [[ ! -d "$policy_dir" ]]; then + echo "apply_chromium_extension_policy: creando directorio ${policy_dir}" + if [[ $EUID -ne 0 ]]; then + sudo mkdir -p "$policy_dir" || { + echo "apply_chromium_extension_policy: no se pudo crear el directorio ${policy_dir}" >&2 + return 1 + } + else + mkdir -p "$policy_dir" || { + echo "apply_chromium_extension_policy: no se pudo crear el directorio ${policy_dir}" >&2 + return 1 + } + fi + fi + + # --- Escribir el JSON vía tmpfile + sudo cp / tee --- + local tmpfile + tmpfile=$(mktemp /tmp/chromium_policy_XXXXXX.json) + echo "$new_json" > "$tmpfile" + + if [[ $EUID -ne 0 ]]; then + sudo cp "$tmpfile" "$policy_path" || { + echo "apply_chromium_extension_policy: no se pudo escribir ${policy_path}" >&2 + rm -f "$tmpfile" + # Restaurar backup si hubo + if [[ -n "$backup_path" && -f "$backup_path" ]]; then + echo "apply_chromium_extension_policy: restaurando backup tras error..." + sudo cp "$backup_path" "$policy_path" 2>/dev/null || true + fi + return 1 + } + else + cp "$tmpfile" "$policy_path" || { + echo "apply_chromium_extension_policy: no se pudo escribir ${policy_path}" >&2 + rm -f "$tmpfile" + if [[ -n "$backup_path" && -f "$backup_path" ]]; then + echo "apply_chromium_extension_policy: restaurando backup tras error..." + cp "$backup_path" "$policy_path" 2>/dev/null || true + fi + return 1 + } + fi + rm -f "$tmpfile" + + # --- Validar el JSON escrito --- + local validation_ok=0 + if command -v python3 &>/dev/null; then + python3 -c "import json,sys; json.load(open(sys.argv[1]))" "$policy_path" 2>/dev/null && validation_ok=1 + elif command -v jq &>/dev/null; then + jq . "$policy_path" &>/dev/null && validation_ok=1 + else + # Sin parser disponible, asumir OK (el JSON lo generamos nosotros) + validation_ok=1 + fi + + if [[ $validation_ok -eq 0 ]]; then + echo "apply_chromium_extension_policy: el JSON escrito no es válido — restaurando backup" >&2 + if [[ -n "$backup_path" && -f "$backup_path" ]]; then + if [[ $EUID -ne 0 ]]; then + sudo cp "$backup_path" "$policy_path" 2>/dev/null || true + else + cp "$backup_path" "$policy_path" 2>/dev/null || true + fi + fi + return 1 + fi + + # --- Resumen final --- + echo "apply_chromium_extension_policy: política aplicada correctamente." + echo " Ruta : ${policy_path}" + echo " Extensiones forzadas (${#ext_ids[@]}):" + for id in "${ext_ids[@]}"; do + echo " - ${id}" + done + if [[ -n "$backup_path" && -f "$backup_path" ]]; then + echo " Backup : ${backup_path}" + fi + echo "" + echo " AVISO: Chromium cachea la politica en memoria. Para que surta efecto:" + echo " pkill -9 chromium (cierra TODOS los procesos)" + echo " # Luego relanza Chromium. O desde un Chromium abierto:" + echo " # chrome://policy → 'Reload policies'" +} + +# Auto-ejecución al correr el archivo directo (bash file.sh / fn run). Si se hace `source`, +# solo se define la función y no se ejecuta nada. +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + apply_chromium_extension_policy "$@" +fi