Refuerzo de código
Resumen
Un guarda se juzga por lo que rechaza cuando alguien intenta sortearlo, no por si pasa su camino feliz. Los dos modos de fallo que sobreviven a una revisión son un control que inspecciona una representación del valor peligroso en lugar del valor mismo, y un control que devuelve éxito porque no pudo ejecutarse. Ambos aparecen en verde en todas las pruebas escritas desde las suposiciones del autor.
Uso
Sigue los pasos a continuación al escribir o modificar un gancho, un guarda, un validador, una verificación de permisos, una regla de lint o una puerta de CI, antes de abrir el archivo, ya que el paso 1 a menudo cambia dónde debe ubicarse el código.
Casos típicos: "bloquear rm -rf fuera del repositorio" (el paso 1 mueve la decisión fuera de la cadena de comandos), "fallar CI cuando una migración no tiene rollback" (los pasos 3 y 4 evitan que la puerta pase cuando la lista de migraciones vuelve vacía), "rechazar un push sin un commit firmado" (el paso 5 enumera el alias, --no-verify y el segundo remoto).
Pasos
- Nombra el sumidero. Escribe el valor exacto que llega a lo que proteges: el argv expandido, el cuerpo de la solicitud, el parámetro SQL, la ruta resuelta. Valida ese valor.
- Comprueba si realmente puedes verlo. Si el código solo tiene una representación del valor (una cadena de comandos de shell, un diff, una línea de log, un mensaje de commit), la decisión es una heurística, no una verificación. Dilo en un comentario y en la nota de entrega, y etiqueta esa capa como consultiva. No dejes que una heurística sea la única barrera para una consecuencia que no puedas deshacer.
- Falla cerrado. Tiempo de ejecución faltante, entrada ilegible, excepción del analizador, variable no resuelta, resultado vacío: rechaza, y nombra lo que faltaba. Un guarda que sale con 0 porque no pudo ejecutarse es un guarda desactivado, y permanece desactivado silenciosamente durante meses.
- Mantén visible el fallo de la sonda. Nada de
2>/dev/nullen el comando que decide si el guarda puede ejecutarse, y ninguna rama que convierta un resultado vacío en éxito. Si se permite que la sonda falle silenciosamente, el paso 3 es inaplicable. - Enumera los bypass antes de escribir la corrección. Enumera cómo se puede satisfacer o saltar el control: comando compuesto, banderas duplicadas, una segunda invocación, un alias o una función, un intérprete faltante, otro host, un subshell, un archivo renombrado. Mantén la lista en el cuerpo del commit o en el archivo de prueba.
- Convierte cada entrada de esa lista en un caso de prueba integrado en las verificaciones automatizadas del proyecto. Una autoprueba manual no cuenta: desaparece con la sesión que la ejecutó.
- Cuando un bypass es barato y su consecuencia real, realiza una pasada adversarial. Despacha un subagente con contexto fresco cuyo mandato es romper el guarda, no revisarlo; su salida es la lista de intentos y sus resultados. Omite esto para un control cuyo peor caso es una advertencia.
Advertencias
- Analizar un comando de shell para decidir. Las comillas,
$(),&&, los alias y los prefijosenvcambian lo que finalmente se ejecuta. Esa capa es un reductor de velocidad; la verificación real pertenece donde aterriza el efecto del comando. - Guardas con
command -v.if command -v tool > /dev/null; then check; fisalta silenciosamente la verificación en cualquier máquina que no tenga la herramienta, exactamente la máquina que más la necesita. Inviértelo: rechaza cuando la herramienta esté ausente. - Un paso de descubrimiento que no encuentra nada.
git grep -Eno admite\b, por lo que un patrón así coincide con cero archivos sin error, y la puerta pasa sin haber leído nada. Protege el paso con un canario: un archivo que sepas que debe aparecer en su salida. - Probar solo el rechazo que implementaste. La prueba interesante es la entrada que no se te ocurrió; eso es lo que produce el paso 5.
- Un guarda probado solo a mano. Pasa en la máquina del autor, luego se pudre. Si el proyecto no tiene lugar para integrar la prueba, ese arnés faltante es parte del trabajo.
- El contexto que escribió el guarda no puede romperlo. Comparte los puntos ciegos que produjeron el agujero, y confirmará su propio diseño. Solo un contexto fresco es adversarial.
Restricciones
- Nunca decidas sobre un proxy del valor protegido cuando el valor mismo sea accesible.
- Nunca salgas con 0 en una ruta donde el guarda no pudo hacer su trabajo; rechaza y nombra la causa.
- Nunca suprimes los errores de la sonda que establece si el guarda puede ejecutarse.
- Cada bypass enumerado debe existir como una prueba automatizada antes de la entrega.
- Declara explícitamente qué capa es consultiva y cuál es ejecutora; una heurística presentada como garantía es peor que ningún guarda.