Builds reproduzíveis
Esta página aún no está disponible en tu idioma.
Construir o mesmo commit duas vezes dá os mesmos bytes. Dois builds independentes de um commit (construtores novos, sem cache, caminhos diferentes, datas de arquivo diferentes) produzem, bit a bit, idênticos:
- o binário do servidor (
dumbmonit, musl estático, com a interface web embutida); - os binários do agente para Linux x86_64 e aarch64, Windows x86_64 e FreeBSD x86_64;
- os arquivos da interface web embutidos no servidor;
- a imagem do servidor e a imagem do agente, comparadas pelo digest do
manifesto OCI (cada camada e a configuração da imagem), quando construídas
com a data do commit como
SOURCE_DATE_EPOCH; - os binários do agente para macOS, quando construídos na mesma versão de macOS e Xcode.
Isso é verificado em cada pull request que toca o código e em cada push para
main pelo workflow
Reproducible builds:
dois runners constroem o commit de forma independente e o job falha se um único
arquivo difere, com um relatório do diffoscope como
artefato.
O que o torna repetível
Seção intitulada “O que o torna repetível”- Dependências travadas.
Cargo.lockeweb/package-lock.jsonestão no repositório; o build usacargo build --lockedenpm ci. - Ferramentas fixadas. Toda imagem base do
Dockerfileé fixada pelo digest SHA-256: Node para a interface web, Rust sobre Alpine para o servidor (seugccemusl-dev, que compilam o SQLite, vêm com essa imagem), cargo-zigbuild para os agentes (ele fixa a versão do zig, que os liga) e a release do VictoriaMetrics. A toolchain Rust dos agentes é fixada comRUST_TOOLCHAIN. - Nenhuma data de build na saída. O commit identifica um build, nunca o
momento do build:
- o identificador de versão da interface web (o
version.namedo SvelteKit, que por padrão é a hora atual) é o commit (DUMBMONIT_BUILD) ou, na falta,SOURCE_DATE_EPOCH; - os arquivos embutidos no servidor não carregam data de modificação
(
rust-embedcomdeterministic-timestamps); - o cabeçalho PE do agente Windows recebe uma data de link fixa
(
SOURCE_DATE_EPOCH=0no estágio do agente); - o BuildKit grava a data do commit na configuração da imagem, em seu
histórico e, com
rewrite-timestamp=true, nas datas dos arquivos das camadas.
- o identificador de versão da interface web (o
- Nenhum caminho da máquina nos binários. Os builds rodam em contêineres
com caminhos fixos (
/build,/usr/local/cargo); o build do macOS remapeia seus caminhos com--remap-path-prefix. - Perfil de build fixo. O
Cargo.tomlfixalto, uma unidade de geração de código,stripepanic = "abort".
Como verificar você mesmo
Seção intitulada “Como verificar você mesmo”Você precisa do Docker com Buildx (BuildKit 0.13 ou posterior) e de um checkout do commit ou da tag a verificar. Passe as mesmas duas entradas do workflow de release, o commit e sua data:
git clone https://github.com/selfhostr/dumbmonit && cd dumbmonitgit checkout v0.9.1 # or any commitexport SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)set -- --build-arg DUMBMONIT_BUILD=$(git rev-parse HEAD) --platform linux/amd64 \ --provenance=false --sbom=false
docker buildx build "$@" --target server-dist --output type=local,dest=out/server .docker buildx build "$@" --target agent-dist --output type=local,dest=out/agent .sha256sum out/server/* out/agent/*Construa uma segunda vez (outra máquina, outro diretório, --no-cache) e
compare os checksums: eles são idênticos.
Para comparar com uma versão publicada:
-
Binários do agente: compare com os arquivos
.sha256anexados à release do GitHub da tag. -
Binário do servidor: retire-o da imagem publicada e compare:
Janela do terminal docker create --name dm ghcr.io/selfhostr/dumbmonit:0.9.1docker cp dm:/dumbmonit published-dumbmonit && docker rm dmsha256sum published-dumbmonit out/server/dumbmonit -
Imagens: construa a imagem como um arquivo OCI e compare suas camadas com as publicadas (a imagem publicada também traz rótulos, uma proveniência de build e um SBOM, que mudam o digest do manifesto mas não as camadas; imagem do agente: os mesmos comandos com
--target agent-imageeghcr.io/selfhostr/dumbmonit-agent):Janela do terminal docker buildx build "$@" --output type=oci,dest=image.tar,rewrite-timestamp=true .mkdir image && tar -xf image.tar -C imageblob() { echo "image/blobs/sha256/${1#sha256:}"; }manifest=$(jq -r '.manifests[0].digest' image/index.json)config=$(jq -r '.config.digest' "$(blob "$manifest")")# Layers of the local build (uncompressed digests):jq -r '.rootfs.diff_ids[]' "$(blob "$config")"# Layers of the published image:docker buildx imagetools inspect ghcr.io/selfhostr/dumbmonit:0.9.1 \--format '{{range .Image.RootFS.DiffIDs}}{{println .}}{{end}}'
Uma divergência merece uma issue: por favor, abra uma com os comandos que você executou.
Limites
Seção intitulada “Limites”- Imagens publicadas antes da 0.9.1 foram construídas sem
SOURCE_DATE_EPOCH: seus binários e camadas diferem de uma reconstrução. A comparação de um build local com uma imagem publicada ainda não foi executada: a primeira release construída assim é a 0.9.1. - O agente macOS é construído em um runner macOS do GitHub (o SDK da Apple
não pode ser redistribuído, então não dá para construí-lo em um contêiner). Ele
é idêntico entre dois builds no mesmo macOS e Xcode, que o log da release
imprime (
xcodebuild -version); outro Xcode pode dar outro binário. - Tempo. As imagens base são fixadas por digest e continuam disponíveis,
mas o índice de pacotes do Alpine usado para o
make(uma ferramenta de build, que não faz parte da saída), o npm e o crates.io são serviços online: uma reconstrução anos depois depende de eles ainda servirem as versões travadas. - Sem os argumentos de build, um
docker build .local semDUMBMONIT_BUILDe semSOURCE_DATE_EPOCHdá um identificador de versão da interface web tirado da hora atual e, portanto, um binário do servidor diferente a cada vez. Passe os dois, como acima.