feat(browser): clean_chrome_profile_extensions + fix policy backup en managed/

Rediseño de apply_chromium_extension_policy y nueva función de purga in-place,
tras resolver por qué las extensiones bloqueadas reaparecían en Chromium 148.

- apply_chromium_extension_policy: añade --block (ExtensionInstallBlocklist).
  Reemplaza el modo ExtensionSettings "*": blocked (que rompía las extensiones
  unpacked vía --load-extension, p.ej. la de captura de web_proxy con el error
  'Loading of unpacked extensions is disabled by the administrator') por una
  blocklist específica. FIX RAÍZ: los backups se guardan fuera de policies/managed/
  (en policy-backups/), porque Chromium lee TODOS los archivos del directorio
  managed/ sin filtrar extensión de nombre — un extensions.json.bak ahí se mergea
  con la policy y reinyecta las extensiones del backup (location=7).
- clean_chrome_profile_extensions (nueva): purga in-place de un perfil existente
  (borra carpetas de Extensions/ + refs en Preferences/Secure Preferences) dejando
  solo la whitelist. Complementa la policy: la policy evita reinstalación, esta
  desinstala lo ya presente. Requiere chromium cerrado.

Ambas: dominio browser, grupo navegator, guard de auto-ejecución, dry-run.
This commit is contained in:
Egutierrez
2026-06-05 17:13:49 +02:00
parent 830f2d34de
commit e0fad0e82f
4 changed files with 450 additions and 50 deletions
@@ -3,10 +3,10 @@ name: apply_chromium_extension_policy
kind: function
lang: bash
domain: browser
version: "1.0.0"
version: "1.1.0"
purity: impure
signature: "apply_chromium_extension_policy --keep <ext_id> [--keep <ext_id>]... [--policy-path <path>] [--update-url <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."
signature: "apply_chromium_extension_policy [--keep <ext_id>]... [--block <ext_id>]... [--policy-path <path>] [--update-url <url>] [--dry-run]"
description: "Escribe de forma idempotente la política managed de Chromium combinando ExtensionInstallForcelist (force-instala la whitelist --keep) y ExtensionInstallBlocklist (bloquea y desinstala la blocklist --block). No usa el comodín \"*\" blocked, por lo que NO afecta a las extensiones unpacked cargadas con --load-extension. Guarda backup fuera del directorio managed/ (que Chromium lee entero). Requiere sudo para escribir en /etc; en --dry-run no toca el sistema."
tags: [chromium, extensions, policy, browser, navegator, managed-policy, idempotent]
uses_functions: []
uses_types: []
@@ -16,14 +16,16 @@ error_type: "error_go_core"
imports: []
params:
- name: "--keep <ext_id>"
desc: "ID de extensión de Chrome Web Store a force-instalar (repetible, al menos uno obligatorio). Ejemplo: ddkjiahejlhfcafbddmgiahcphecmpfh (uBlock Origin Lite)."
desc: "ID de extensión de Chrome Web Store a force-instalar (repetible). Va a ExtensionInstallForcelist. Ejemplo: ddkjiahejlhfcafbddmgiahcphecmpfh (uBlock Origin Lite)."
- name: "--block <ext_id>"
desc: "ID de extensión a bloquear y desinstalar en cualquier perfil (repetible). Va a ExtensionInstallBlocklist. Solo afecta a los IDs listados; el resto de extensiones no se toca."
- name: "--policy-path <path>"
desc: "Ruta del JSON de managed policy. Default: /etc/chromium/policies/managed/extensions.json."
- name: "--update-url <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."
output: "Escribe el JSON de política en policy-path y emite a stdout un resumen: extensiones forzadas, bloqueadas, 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. Requiere al menos un --keep o --block."
tested: false
tests: []
test_file_path: ""
@@ -33,34 +35,55 @@ 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)
# Dejar el perfil con solo uBlock Origin Lite: forzar uBlock + bloquear las 3 que estorban
# al scraping (Dark Reader, NoScript, OneTab). Proyecto web_scraping, regla 9.
source bash/functions/browser/apply_chromium_extension_policy.sh
apply_chromium_extension_policy --keep ddkjiahejlhfcafbddmgiahcphecmpfh
apply_chromium_extension_policy \
--keep ddkjiahejlhfcafbddmgiahcphecmpfh \
--block eimadpbcbfnmbkopoojfekhnkhdbieeh \
--block doojmbjmlfjjnbmnoijecmcbfeoakpjm \
--block chphlpgkkbolifaimnlloiipkdnihall
# 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.
# Ejecutar como root para el sudo no interactivo de este equipo
pass show claude/sudo | sudo -S bash bash/functions/browser/apply_chromium_extension_policy.sh \
--keep ddkjiahejlhfcafbddmgiahcphecmpfh --block eimadpbcbfnmbkopoojfekhnkhdbieeh
```
La policy por sí sola evita la reinstalación pero NO desinstala lo ya presente en un perfil concreto:
combínala con `clean_chrome_profile_extensions_bash_browser` (con Chromium cerrado) para purgar del
disco las extensiones ya instaladas.
## 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`.
Al preparar un PC nuevo o cambiar qué extensiones de Chrome Web Store deben estar (o no estar) en
cualquier perfil de Chromium del equipo. Reemplaza el paso manual de editar el JSON de policy con
sudo. `--keep` fuerza y fija las imprescindibles; `--block` elimina las molestas sin tocar el resto.
## Gotchas
- **Requiere sudo** para escribir en `/etc/chromium/policies/managed/`. En este equipo se alimenta con `pass show claude/sudo | sudo -S <cmd>` 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 `<policy-path>.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`.
- **El backup NUNCA va dentro de `managed/`** (lo gestiona la función, pero es la lección clave): Chromium
lee **todos** los archivos del directorio `policies/managed/` sin filtrar por extensión de nombre. Un
`extensions.json.bak.YYYYMMDD` dentro de `managed/` se mergea con la policy efectiva y **reinyecta** las
extensiones del backup (se ven como `location=7` external_policy_download y vuelven aunque las borres).
Por eso la función guarda los backups en `policies/policy-backups/`, fuera de `managed/`. Si encuentras
backups antiguos dentro de `managed/`, muévelos fuera.
- **No usa el comodín `"*": blocked`**: ese modo desinstala todo lo no-whitelist pero también **bloquea las
extensiones unpacked** (`--load-extension`), rompiendo cosas como la extensión de captura de `web_proxy`
con el error "Loading of unpacked extensions is disabled by the administrator". Esta función bloquea solo
los IDs de `--block`.
- **`--load-extension` y managed policy son incompatibles en Chromium 137+**: con CUALQUIER managed policy
presente, Chromium desactiva `--load-extension` ("disabled by the administrator"). Para cargar una
extensión local junto a una managed policy hay que empaquetarla (.crx + update_url) o usar `--proxy-server`
directo en el caso de `web_proxy`.
- **Requiere sudo** para escribir en `/etc/chromium/policies/managed/`. En este equipo: `pass show claude/sudo | sudo -S <cmd>`.
- **Chrome cachea la política en memoria**: cerrar TODOS los Chromium (`pkill -9 chromium`) y relanzar, o `chrome://policy` → "Reload policies".
- **Idempotente**: si el archivo ya tiene el mismo contenido, no-op y sale 0.
- Referencia del sistema completo: `projects/web_scraping/CHROMIUM_SYSTEM.md`.
## Capability growth log
- v1.1.0 (2026-06-05) — añade `--block` (ExtensionInstallBlocklist); reemplaza el modo `ExtensionSettings "*": blocked` (rompía extensiones unpacked) por blocklist específica; mueve los backups fuera de `managed/` (Chromium lee todo el directorio y un `.bak` ahí reinyectaba extensiones).
- v1.0.0 (2026-06-05) — baseline: ExtensionInstallForcelist con whitelist `--keep`.