Dominando el uso de Vendoring en Go

Vendoring es la práctica de copiar el código fuente de todas tus dependencias externas directamente dentro de una carpeta llamada vendor/ en la raíz de tu proyecto. En lugar de que el compilador busque las librerías en el cache global de tu máquina ($GOPATH/pkg/mod), las lee exclusivamente de este directorio local. Esto funciona porque, al utilizar la bandera -mod=vendor (o configurar GOFLAGS=-mod=vendor), el comando go build ignora el cache de módulos del sistema y utiliza estrictamente lo que tienes en tu carpeta vendor/. Debes usarlo cuando necesites builds 100% reproducibles en entornos de CI/CD aislados (sin acceso a internet), cuando tu equipo de seguridad necesite realizar auditorías sobre el código fuente exacto de terceros alojado en tu repositorio, o si tu infraestructura no puede depender de la disponibilidad de proxy.golang.org. Si lo gestionas mal, específicamente si actualizas una dependencia en tu go.mod pero no actualizas la carpeta vendor/, terminarás compilando un código distinto al que declaras, rompiendo la consistencia entre tu código fuente y tu binario final.

// main.go
// Para probar este ejemplo, ejecuta en tu terminal:
// 1. go mod init example.com/vendoring-demo
// 2. go get github.com/google/uuid
// 3. go mod vendor
// 4. go run -mod=vendor main.go

package main

import (
	"fmt"
	// uuid es una dependencia externa que vivirá en /vendor/github.com/google/uuid
	"github.com/google/uuid"
)

func main() {
	// Generamos un UUID usando la librería externa.
	// Si usamos vendoring, el compilador no irá a internet ni al cache de Go,
	// sino que leerá el código de 'uuid' desde la carpeta ./vendor/
	id := uuid.New().String()

	fmt.Printf("ID generado con éxito: %s\n", id)
}

Cuando ejecutas go mod vendor, Go escanea tu archivo go.mod y descarga (si es necesario) todas las dependencias necesarias, para luego volcarlas en el directorio vendor/. En el ejemplo anterior, la llamada a uuid.New().String() no busca la librería en tu $GOPATH/pkg/mod si utilizas la bandera -mod=vendor, sino que entra directamente en la ruta de tu proyecto para buscar el código fuente.

Es importante entender que, desde Go 1.14, si el directorio vendor existe y tu go.mod está correctamente configurado, go build usará automáticamente el contenido de vendor sin necesidad de pasarle la bandera -mod=vendor. Sin embargo, en entornos de integración continua (CI) o pipelines de despliegue muy estrictos, es una buena práctica forzar el uso de la carpeta mediante la variable de entorno GOFLAGS=-mod=vendor para garantizar que el build sea totalmente autónomo y no intente descargar nada de la red.

El error frecuente

El problema más común con el vendoring ocurre cuando hay una desincronización entre el archivo go.mod y el contenido de la carpeta vendor/.

Si ejecutas go get github.com/google/uuid@v1.6.0 para actualizar la librería, tu archivo go.mod se actualizará, pero tu carpeta vendor/ seguirá teniendo la versión anterior. Si tu pipeline de CI está configurado para usar -mod=vendor, el binario resultante usará la versión vieja de la librería, aunque tu código fuente parezca indicar la nueva. Esto genera bugs extremadamente difíciles de rastrear porque “en mi máquina funciona” (porque tú tienes la versión nueva en el cache local), pero en producción el comportamiento es distinto.

Para evitarlo, cualquier cambio en las dependencias debe ir seguido obligatoriamente de un go mod tidy y un go mod vendor.

100

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio