La verificación que gritó «lobo»: cuando una alerta exacta es peor que ninguna alerta
Una verificación de integración continua en la que confiamos hizo fallar cada solicitud de extracción en tres de nuestros proyectos publicados durante aproximadamente un día. Ninguna de esas solicitudes de extracción tenía nada malo.
El ingeniero siguió fusionando a pesar de ella. Esa fue la decisión correcta en cada ocasión: la verificación estaba equivocada y el trabajo estaba limpio. También es precisamente así como un control deja de funcionar.
La falla estaba en otro repositorio
La compuerta lee su lógica desde el commit base y no desde la solicitud de extracción. Eso es deliberado: de lo contrario, una solicitud de extracción podría suministrar el código que la juzga, lo cual no es ninguna compuerta.
El efecto secundario no es obvio. El script que realmente se ejecuta es la copia que ya está en la rama predeterminada, de modo que un defecto ahí rompe cada solicitud de extracción en ese repositorio, y nada de lo que se haga a la solicitud de extracción ayuda. Rebasar no ayuda. Corregir el mensaje del commit no ayuda. La verificación reporta sobre la rama y falla por causa de otro lugar.
El error subyacente era pequeño: cada mensaje de commit se comparaba con una copia que había ganado un salto de línea final, así que cada commit parecía modificado y la ejecución abortaba. La corrección fueron unas pocas líneas. Encontrarla tomó un día, porque todos estaban mirando las solicitudes de extracción.
La regla general que vale la pena extraer: lo que juzga debe existir antes que lo juzgado. Cuando un control lee su lógica desde una ubicación de confianza, esa ubicación se actualiza primero. Ahora aterrizamos los scripts en un repositorio antes que el flujo de trabajo que los invoca, y fusionamos la copia canónica antes que cualquier copia que la incorpore.
Un hallazgo exacto que nadie podía resolver
Por separado, uno de nuestros módulos de gobernanza reportaba un error en cada entorno, de forma permanente, por diseño.
A un rol se le habían concedido derechos administrativos generales, y el módulo se negaba correctamente a certificar que tal rol estuviera restringido por la política. Como el rol poseía cada permiso de forma implícita, incluidos permisos que todavía no existían, no había nada que enumerar y nada que aprobar. El hallazgo no podía reconocerse. Simplemente permanecía en el informe de estado.
El razonamiento de entonces era defendible hasta donde llegaba. La alternativa en discusión era eliminar la política que producía el hallazgo, y eso habría eliminado discretamente un límite de red real junto con la fila roja. Conservar el ruido era mejor que eliminar el control.
Pero nunca fue un estado final aceptable, y permaneció así más tiempo del debido. Un informe que siempre muestra un error enseña a su lector a omitir el informe. El hallazgo era exacto, y eso es lo que lo hacía corrosivo: nadie podía actuar sobre él, así que todos aprendieron a pasarlo por alto. El siguiente error habría llegado a ese hábito.
La pregunta que nadie había hecho era por qué el rol tenía derechos generales en absoluto. Una vez planteada, bastó un solo cambio: reemplazar la concesión general por una lista explícita de permisos. El rol se convirtió en algo que la política podía restringir, el hallazgo se resolvió con honestidad y el informe volvió a significar algo.
Una verificación que no podía fallar
La misma semana necesitábamos confirmar que un centenar de decisiones registradas se habían trasladado a una nueva base de conocimiento. Un script las comparó y reportó noventa y nueve ya presentes.
Antes de creerle, lo ejecutamos contra una decisión que ya sabíamos que faltaba. La puntuó con 0.88, holgadamente un aprobado.
El script comparaba vocabulario, no significado. Las palabras de la decisión faltante aparecían en todo el corpus en contextos no relacionados, así que declaró la decisión presente. Descartamos el resultado y leímos las cien a mano. Veintisiete estaban genuinamente ausentes.
Una verificación que no puede producir una falla no es una verificación. Toda verificación debe demostrar que falla con una entrada conocida como mala antes de confiar en ella con entradas desconocidas. Cuesta una prueba, y es la diferencia entre una medición y una reafirmación.
Por qué esto no es fatiga de alertas
Estos parecen tres errores sin relación. Son un mismo modo de falla con distintos ropajes, y vale la pena separarlo del problema más familiar al que se parece.
La fatiga de alertas se describe normalmente como un problema de volumen: demasiadas notificaciones, atención agotada. Ninguno de estos era de alto volumen. Cada uno era una señal única, persistente y de apariencia correcta. Lo que los hacía dañinos era que ninguna acción disponible para el lector los resolvería:
- La compuerta que fallaba no podía satisfacerse cambiando la solicitud de extracción, porque su causa estaba en otro lugar.
- El error de gobernanza no podía reconocerse, porque la ruta de código retornaba antes de leer el reconocimiento.
- La verificación no podía reportar un problema, porque su método era incapaz de detectar uno.
En cada caso el control seguía presente. Aparecía en tableros y verificaciones de estado. Un auditor que revisara la configuración lo habría encontrado habilitado y correctamente configurado. Lo que había terminado discretamente era su efecto sobre el comportamiento de cualquiera.
Esa brecha, entre un control que está configurado y un control que está funcionando, es la primera que buscamos al evaluar un entorno.
Tres prácticas
Trate una verificación persistentemente en rojo como un incidente. Si un control lleva días fallando mientras el trabajo se publica de todos modos, el control ya no está funcionando, sean o no correctos sus hallazgos. Corríjalo o elimínelo. Dejarlo a medias es la peor de las tres opciones, porque parece cobertura.
Exija que cada hallazgo tenga una acción que lo resuelva. Una corrección, un reconocimiento o una exención con un responsable designado y una fecha de vencimiento. Un hallazgo sin ruta de resolución es un defecto de diseño del control, incluso cuando el hallazgo en sí es cierto. Si su herramienta puede emitir un estado permanente e irresoluble, eso es un error en la herramienta.
Demuestre que cada verificación puede fallar. Déle una entrada conocida como mala y confirme que lo reporta. Una suite de pruebas que solo demuestra aprobados le dice que la verificación se ejecuta, no que funciona. Esto se aplica a las verificaciones mismas y a las pruebas que las cubren.
Por qué dejamos esto por escrito
Construimos herramientas de gobernanza y cumplimiento y las ejecutamos en nuestros propios sistemas antes que en los de nadie más. Eso significa que encontramos estos problemas primero en nuestro propio entorno, y preferimos describirlos con claridad antes que presentar un relato más pulcro de cómo va el trabajo.
La parte incómoda es que dos de los tres ejemplos eran defectos en herramientas construidas para detectar defectos. Los controles son software. Fallan como falla el software, y fallan en silencio, porque un control roto es indistinguible de uno que funciona hasta que algo lo pone a prueba.
Una configuración que afirma un control que no aplica es la forma que subyace a todo esto: una casilla marcada, una política presente, una verificación que se ejecuta, y nada detrás de ninguna de ellas. Es lo primero que buscamos en el entorno tecnológico de otro, en gran parte por la frecuencia con que lo hemos encontrado en el nuestro.