Baixe arquivos com cURL e verifique checksums SHA-256
Use o cURL para baixar um arquivo e sha256sum para comparar seus bytes com um checksum confiável. O
script Bash abaixo mantém o download em um diretório temporário e só dá a ele o nome final depois
que a verificação é bem-sucedida. Você pode executar o mesmo script localmente e no GitHub Actions.
Escolha um checksum confiável
O SHA-256 produz um digest de 256 bits, geralmente escrito como 64 caracteres hexadecimais. Um digest correspondente confere os bytes baixados com o valor esperado. Ele não estabelece quem forneceu esse valor: alguém capaz de substituir tanto um download quanto seu checksum pode fazer os dois coincidirem.
Obtenha o checksum esperado nos metadados da versão publicados pelo publicador via HTTPS e mantenha-o junto com a URL versionada que você pretende baixar. Se precisar autenticar a versão de forma independente do site que a hospeda, siga o procedimento de verificação de assinatura do publicador usando uma chave de assinatura cuja identidade você tenha confirmado de forma independente. O projeto cURL oferece assinaturas destacadas para os arquivos compactados de suas versões; o exemplo de checksum aqui não verifica essas assinaturas.
Automatize a verificação com Bash
Use Linux com Bash, uma build do cURL com suporte a HTTPS e o GNU coreutils: sha256sum, mktemp, ln
e rm. O destino é o diretório atual, que precisa ter permissão de escrita e estar em um sistema
de arquivos com suporte a hard links. O script usa o GNU ln -T; ele não é um script /bin/sh portável
nem um script para macOS. Os exemplos foram testados com Bash 5.2.21, cURL 8.5.0 e coreutils 9.4 no
Ubuntu 24.04, e com Bash 5.3.15, cURL 8.22.0 e coreutils 9.11 no Linux.
Salve isto como verify-download.sh em um diretório que você controla. Execute-o com Bash, como mostrado
abaixo; não carregue o script no seu shell com source. Os três argumentos são a URL HTTPS, o digest
SHA-256 esperado e um nome de arquivo local. Os nomes de saída podem conter espaços, hifens no início
ou caracteres % literais, mas não podem conter barra nem quebra de linha. Um arquivo,
diretório ou link simbólico já existente causa erro e permanece intacto.
#!/usr/bin/env bash
set -euo pipefail
export LC_ALL=C
if [[ $# -ne 3 ]]; then
printf 'Usage: bash verify-download.sh HTTPS_URL SHA256 OUTPUT_NAME\n' >&2
exit 2
fi
url=$1
expected=$2
output=$3
if [[ $url != https://* || ! $expected =~ ^[[:xdigit:]]{64}$ ]]; then
printf 'Provide an HTTPS URL and a 64-digit hexadecimal SHA-256 checksum.\n' >&2
exit 2
fi
case "$output" in
''|.|..|*/*|*$'\n'*|*$'\r'*)
printf 'Provide a filename without slashes or line breaks.\n' >&2
exit 2
;;
esac
if [[ -e "./$output" || -L "./$output" ]]; then
printf 'Destination already exists: %s\n' "$output" >&2
exit 1
fi
umask 077
temp_dir=$(mktemp -d ./.verify-download.XXXXXX)
trap 'rm -rf -- "$temp_dir"' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
curl -q -fsSL --globoff --proto '=https' --proto-redir '=https' \
--connect-timeout 10 --max-time 120 --retry 3 \
--output "$temp_dir/payload" --url "$url"
if ! printf '%s %s\n' "$expected" "$temp_dir/payload" | sha256sum --check --status -; then
printf 'SHA-256 mismatch or unreadable download.\n' >&2
exit 1
fi
ln -T -- "$temp_dir/payload" "./$output"
printf 'Verified: %s\n' "$output"
As opções do cURL fazem erros HTTP, como um 404, resultarem em falha
(-f), ocultam o medidor de progresso sem suprimir as mensagens de erro (-sS) e seguem
redirecionamentos (-L). Tanto a requisição original quanto os redirecionamentos ficam restritos
a HTTPS. --globoff trata a URL literalmente; -q, colocado primeiro, impede que um .curlrc
local altere a requisição. Falhas transitórias recebem até três novas tentativas, com limite de
120 segundos por tentativa de transferência.
O script monta um único registro de checksum: o digest, dois espaços e o caminho privado do payload.
O GNU sha256sum --check
lê esse registro da entrada padrão. --status faz com que o status de saída determine se a
verificação teve sucesso. Nenhum arquivo de checksum remoto pode escolher quais nomes de arquivo
locais são verificados.
Depois de uma correspondência, o GNU ln
adiciona o nome final ao arquivo já verificado. -T trata o destino como um nome exato,
inclusive quando existe um diretório nesse local, e a ausência de -f impede a substituição.
Manter o diretório temporário ao lado do destino coloca os dois nomes no mesmo sistema de arquivos. O
trap de saída remove o nome temporário e o diretório; o arquivo verificado permanece com seu nome
final.
Falhas de download ou de checksum retornam um status diferente de zero e removem os dados temporários
sem criar o arquivo final. Novas execuções iniciam um download do zero; elas não retomam bytes
parciais. Os traps também tratam interrupções normais, mas uma queda de energia ou um SIGKILL pode
deixar um diretório .verify-download.* que exige limpeza manual. Trata-se de um download para um diretório
que pertence a você, não de uma proteção contra outro processo capaz de modificar seus arquivos.
Verifique uma versão do cURL
A versão 8.22.0 do cURL inclui
curl-8.22.0.tar.gz. Os
metadados da versão listam o digest desse
asset exato como
sha256:d54dd598bf05927a726deb38df31c6a255ba83ff1de57c5d1464dac3ed8f44a1.
Use os 64 caracteres depois de sha256: como valor esperado. Os assets .tar.xz e .zip têm
bytes e checksums diferentes.
Esses são metadados JSON, não um arquivo de entrada para o sha256sum --check. Não tente adivinhar uma URL de
checksum acrescentando .sha256 a uma URL de download: curl-8.5.0.tar.gz.sha256 não tem nenhum arquivo nesse endereço.
Aqui fixamos o digest publicado para o asset da versão e baixamos o arquivo compactado de
curl.se:
bash verify-download.sh \
'https://curl.se/download/curl-8.22.0.tar.gz' \
'd54dd598bf05927a726deb38df31c6a255ba83ff1de57c5d1464dac3ed8f44a1' \
'curl-8.22.0.tar.gz'
Em caso de sucesso, o comando termina com status zero e exibe:
Verified: curl-8.22.0.tar.gz
O arquivo compactado agora está no seu diretório atual. Isso baixa código-fonte; não instala nem atualiza o cURL. Para repetir o exemplo, use outro nome de saída ou remova deliberadamente o download anterior antes. Para verificar outra versão, selecione o asset exato dela e atualize tanto a URL quanto o digest.
Integração com GitHub Actions
Mantenha verify-download.sh na raiz do seu repositório e salve este fluxo de trabalho como
.github/workflows/verify-download.yml. Ele usa a mesma URL e o mesmo digest fixados. A etapa final
lista o arquivo compactado verificado com o tar e o gzip do Ubuntu; quando a verificação
funcionar, coloque sua etapa de build nesse lugar.
name: Verify download
on: [push, pull_request]
permissions:
contents: read
jobs:
verify:
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- name: Download and verify
shell: bash
run: |
bash verify-download.sh \
'https://curl.se/download/curl-8.22.0.tar.gz' \
'd54dd598bf05927a726deb38df31c6a255ba83ff1de57c5d1464dac3ed8f44a1' \
'curl-8.22.0.tar.gz'
- name: Read verified archive
shell: bash
run: tar -tzf curl-8.22.0.tar.gz > /dev/null
Por padrão, o GitHub Actions interrompe as etapas seguintes após uma falha.
Mantenha esse comportamento: adicionar continue-on-error ou um || true que force o sucesso permitiria que uma
etapa posterior prosseguisse depois de uma falha na verificação. Revise mudanças de checksum junto
com as atualizações de dependências; calcular um digest “esperado” a partir do arquivo recém-baixado
apenas o compararia consigo mesmo.
Solução de problemas
- Erro HTTP, incluindo
curl: (22): confira a URL exata do asset. Uma página de erro não pode virar o seu arquivo compactado da versão. Um redirecionamento para HTTP também é rejeitado, mesmo que o destino esteja acessível. - Transferência parcial, como
curl: (18): o servidor fechou a resposta antes de entregar o tamanho anunciado. Tente novamente depois de verificar a conexão. Se o servidor informar um arquivo menor como resposta bem-sucedida, a comparação de checksum ainda rejeita os bytes alterados. - Divergência de SHA-256: confira a versão e a extensão do arquivo compactado nos metadados do publicador. Não substitua o checksum esperado pelo valor do download suspeito.
- O destino já existe: o arquivo anterior é preservado. Escolha outro nome local ou inspecione e remova você mesmo o download anterior.
- Erro de hard link ou de escrita: use um sistema de arquivos local com permissão de escrita e suporte a hard links. Uma falha na etapa de publicação retorna status diferente de zero mesmo que o checksum tenha correspondido.
