Detenerme ante un aviso de "tap no confiable" de Homebrew para auditar antes de confiar
Estaba a mitad de la configuración de un nuevo servidor MCP para manejar un iPhone de repuesto en forma remota (mirroir-mcp, maneja la función iPhone Mirroring de Apple para que un agente pueda tomar capturas y tocar un dispositivo real sin que yo esté en la habitación), y me topé con un obstáculo que no esperaba: Homebrew se negó a instalarlo.
“Refusing to load formula jfarcand/tap/mirroir-mcp from untrusted tap.”
Mi primer instinto fue simplemente correr el comando de confianza que sugería y seguir adelante. Ya había mirado esta herramienta una vez, una sesión antes, licencia Apache-2.0, repositorio activo, cantidad razonable de estrellas, y había decidido que estaba bien. Pero “suficientemente bien para agregarlo al plan” y “suficientemente bien para correr sus scripts de instalación con los permisos de mi usuario” son dos estándares distintos, y en realidad no había superado el segundo.
Así que me detuve e hice una auditoría real antes de cruzar esa línea.
Por qué importó la pausa
Resultó que la barrera en sí era nueva y reactiva, no decorativa. Homebrew lanzó “tap trust” en la versión 6.0.0 casi un mes antes de que yo me topara con ella, en respuesta directa a un incidente real ese marzo: alguien usó credenciales comprometidas para publicar una versión maliciosa de una herramienta sin relación a través de un tap personalizado comprometido. La respuesta de Homebrew fue dejar de confiar en los taps de terceros por defecto, punto, hasta que se indique explícitamente lo contrario.
Ese contexto cambió cómo leí el aviso. No era “esta herramienta en particular se ve sospechosa.” Era “todo tap de terceros recibe este trato ahora, porque uno de ellos ya fue comprometido una vez.” Lo cual significaba que la decisión correcta no era descartar el aviso, sino realmente hacer la verificación hacia la que Homebrew me estaba empujando.
Cómo fue la auditoría
Unas cuantas cosas concretas, no una simple impresión general. ¿Qué hace realmente, a nivel mecánico? La herramienta usa CGEvent (la API estándar de simulación de entrada de Apple, no necesita root) y el framework Vision para OCR. Sin llamadas de red en su ruta principal. Tiene un modo opcional de visión con IA que pasa por herramientas de línea de comandos ya autenticadas en vez de hacer sus propias llamadas a API o incluir una clave propia, y degrada a un stub sin efecto si esa pieza no está instalada. ¿Qué permisos pide? Screen Recording y Accessibility, ambos permisos estándar de macOS, ambos necesitan un clic de aprobación explícito y único, ambos revocables en cualquier momento desde System Settings. Nada más amplio que eso. ¿Quién está detrás? La cuenta de GitHub del mantenedor data de 2009, nombre real, perfil vinculado, un largo historial en código abierto de Java. No es una cuenta recién creada, ni anónima. ¿Es un proyecto de una sola persona? Sí, esencialmente, 558 commits del mantenedor contra un puñado de bots de CI. Ese es un riesgo real de bus factor que vale la pena nombrar, aunque nada más del proyecto se viera preocupante. ¿Algún problema de seguridad conocido? Cero avisos publicados, ningún CVE. ¿Binario o código fuente? La fórmula de Homebrew compila desde el código fuente de Swift al momento de instalar, en vez de descargar un blob prearmado. Eso es auditable, al menos en principio, frente a algo opaco.
Nada de esto llevó mucho tiempo. Quizás veinte minutos leyendo el README, el archivo de fórmula real, y sacando estadísticas de contribuyentes vía gh api en vez de confiar en lo que fuera que dijera el resumen de alguna página.
Dónde terminé
Autorizarla, pero de forma más acotada que lo que sugería la opción por defecto. El propio mensaje de error de Homebrew empuja hacia brew trust jfarcand/tap, que confía en todo lo que el dueño de ese tap pueda publicar ahí, para siempre, sin otra revisión. Existe una versión acotada del mismo comando, brew trust --formula jfarcand/tap/mirroir-mcp, que confía solo en la fórmula que realmente revisé. También salté la instalación del componente opcional de visión con IA ya que mi caso de uso no lo necesita, un binario nativo menos vinculado a algo a lo que estoy a punto de darle permisos de Accessibility.
La lección real
Lo tentador acá era tratar el aviso de confianza como fricción a evitar. Habría tomado diez segundos simplemente correr el comando sugerido y volver a la tarea real. Pero “volver a la tarea” no es en realidad el objetivo cuando la tarea implica darle a un binario nuevo acceso a Accessibility y Screen Recording en una máquina que también aloja el resto de mi infraestructura. La fricción era justamente el punto. Solo tenía que usarla de verdad en vez de descartarla.
Lecturas relacionadas
Limpiar herramientas abandonadas me enseñó dos cosas que npm y git no dicen
Un npm uninstall que deja atrás un binario de 44MB, y un stash cuya etiqueta registra dónde apuntaba HEAD, no de qué trata el diff.
Una regla de formato que llevaba meses activa en producción
Un hook que actúa al momento de escribir es ciego a todo lo escrito antes de que existiera, y el propio sistema de tickets rechazó el ticket que reportaba el problema, porque el ticket reproducía el error.
Repaso de metadatos ASO, y la suposición sobre el tamaño de las capturas que resultó equivocada
Una descripción que sonaba a relleno generado por IA, una IAP todavía atascada en Prepare for Submission, y una nota de la base de conocimiento de hace tres semanas que convirtió un solo dato erróneo en una regla.