Build reprodutível
Um build é reprodutível quando a mesma entrada — mesmo commit, mesmas dependências, mesmas instruções — produz exatamente o mesmo artefato, bit a bit, hoje e daqui a seis meses, na sua máquina e no CI.
A maioria dos builds não é. Duas execuções do mesmo commit produzem imagens com digests diferentes, e quase ninguém percebe — até o dia em que a diferença importa.
Por que isso é segurança, não estética
Seção intitulada “Por que isso é segurança, não estética”Reprodutibilidade responde a uma pergunta que nenhuma assinatura responde sozinha: este artefato corresponde mesmo a este código-fonte?
Se o build é reprodutível, qualquer pessoa pode reconstruí-lo a partir do fonte e comparar o digest. Se bater, o artefato não foi adulterado no caminho — nem por um comprometimento do pipeline. Se não é reprodutível, você confia no processo de build por fé: a assinatura prova quem construiu, não o quê foi construído.
Esse é o cerne dos ataques de cadeia de suprimentos mais graves dos últimos anos: o fonte público estava limpo, o artefato distribuído não. Reprodutibilidade é a defesa que torna esse tipo de divergência detectável.
O que quebra a reprodutibilidade
Seção intitulada “O que quebra a reprodutibilidade”Em ordem de frequência:
- Dependência sem versão fixa.
pip install requests,FROM node:22,apt-get install curl— todos resolvem para versões diferentes conforme o dia. - Timestamps embutidos. Data de build no binário,
mtimede arquivos, metadados de camada. - Ordem não determinística. Iteração sobre map ou glob de arquivos com ordem variável.
- Caminhos absolutos do diretório de build gravados no artefato.
- Recursos de rede voláteis: um script que baixa “a última versão” de algo.
- Aleatoriedade: identificadores gerados, chaves temporárias, sementes não fixadas.
- Ambiente: variáveis, locale, fuso horário, número de núcleos afetando paralelismo.
Fixação de dependência e lockfile
Seção intitulada “Fixação de dependência e lockfile”O primeiro nível — e o que dá mais retorno — é fixar tudo:
npm ci # usa package-lock.json; nunca npm install no CIpip install -r requirements.txt --require-hashesgo build -mod=readonly # go.sum verifica os hashesFROM node:22.9.0-slim@sha256:SUBSTITUA_PELO_DIGESTCommite os lockfiles. Fixe também as actions do CI por commit SHA, não por tag móvel — o pipeline é código com acesso a segredos, e uma tag pode ser reapontada.
Digest em vez de tag
Seção intitulada “Digest em vez de tag”Tag é ponteiro mutável: loja:1.8.3 pode apontar para conteúdos diferentes em momentos
diferentes. Digest (loja@sha256:...) é a identidade do conteúdo.
Consequência prática: assine, verifique, promova e implante por digest. Toda a argumentação de promover o mesmo artefato depende disso — sem digest, “o mesmo artefato” não tem como ser garantido.
Determinismo além das dependências
Seção intitulada “Determinismo além das dependências”Para chegar ao bit a bit, ainda faltam os detalhes:
# timestamps fixos nas camadasARG SOURCE_DATE_EPOCH=0# Go: remova caminhos e informação de build variávelgo build -trimpath -ldflags="-s -w -buildid=" -o loja ./cmd/loja
# compare dois buildsdiffoscope artefato-1.tar artefato-2.tarSOURCE_DATE_EPOCH é a convenção adotada por várias ferramentas para normalizar
timestamps, e o buildx a respeita. diffoscope é a ferramenta que mostra exatamente onde
dois artefatos divergem — costuma ser esclarecedor rodá-la uma vez.
O limite honesto
Seção intitulada “O limite honesto”Reprodutibilidade bit a bit é difícil e nem sempre vale o custo. Ecossistemas variam muito: Go e Rust chegam lá com pouco esforço; Java e Node exigem trabalho; imagens com muitas camadas de sistema exigem bastante.
Por isso, pense em níveis, e pare onde o retorno acabar:
- Dependências fixas e lockfiles versionados. Barato, e resolve a maior parte dos “funciona aqui e não lá”. Todo mundo deveria estar aqui.
- Digest em tudo, do
FROMao manifest de deploy. Barato, e habilita assinatura e promoção confiáveis. - Determinismo de timestamps e caminhos. Esforço moderado.
- Bit a bit verificável por terceiros. Caro, e justificável para software distribuído publicamente, base de imagens corporativa e componentes críticos.
Para a maioria dos times, os níveis 1 e 2 entregam quase todo o benefício prático. Os níveis 3 e 4 são investimento de quem publica artefatos que outros consomem — e é exatamente aí que a cadeia de suprimentos é atacada.