
dasel v3.3.1 empacotado com Melange e distribuído como uma imagem apko mínima, corrigido para CVE-2026-33320
Este repositório empacota a CLI dasel (v3.3.1) como um APK com Melange, cria uma imagem de contêiner mínima com apko e aplica uma correção para CVE-2026-33320 permanecendo no código da v3.3.1 (um patch, não um aumento de versão).
O resultado é uma imagem de ~4 MB contendo apenas o binário dasel estático — sem shell, sem gerenciador de pacotes, sem libc — que executa como um usuário não-root.
melange/
dasel.yaml # melange recipe: fetch v3.3.1, apply the patch, build the .apk
apko/
dasel.yaml # apko recipe: assemble a minimal image from the local .apk
patches/
cve-2026-33320.patch # the CVE fix (minimal backport of upstream 282943b onto v3.3.1)
NOTES.md # what the CVE is, severity, and how the fix works
tests/
test.sh # runs the built IMAGE and asserts real behavior + the CVE fix
README.md
melange e apko no PATH.Versões usadas durante o desenvolvimento:
| Tool | Version |
|---|---|
| melange | 0.50.8 |
| apko | 1.2.14 |
| Docker | 29.5.2 |
Todos os comandos abaixo são executados a partir da raiz do repositório.
melange keygen
Produz melange.rsa (privada) e melange.rsa.pub (pública). Ambas estão no gitignore — as chaves são regeneradas por quem reproduzir o build, nunca commitadas.
melange build melange/dasel.yaml \
--source-dir patches \
--signing-key melange.rsa \
--arch x86_64 \
--runner docker
--source-dir patches disponibiliza patches/cve-2026-33320.patch dentro do sandbox de build, onde a etapa patch da receita o aplica. Saída: packages/x86_64/dasel-3.3.1-r0.apk (assinado) e packages/x86_64/APKINDEX.tar.gz.
O melange test instala o .apk recém-construído em um ambiente limpo e executa o bloco test: da receita. Ele precisa do repositório Wolfi (para busybox) e do nosso repositório local packages/ (para dasel), cada um com sua chave de assinatura:
melange test melange/dasel.yaml dasel \
--arch x86_64 --runner docker \
--repository-append https://packages.wolfi.dev/os \
--keyring-append https://packages.wolfi.dev/os/wolfi-signing.rsa.pub \
--repository-append "$(pwd)/packages" \
--keyring-append melange.rsa.pub
Verifica: dasel version informa 3.3.1; uma consulta JSON real; uma conversão JSON→YAML; e que uma bomba YAML billion-laughs é rejeitada pela proteção de expansão (CVE-2026-33320 corrigido).
apko build apko/dasel.yaml dasel:test dasel.tar --arch x86_64
docker load < dasel.tar
Saída: dasel.tar (uma imagem OCI carregável) mais um SBOM (SPDX JSON). O apko anexa a arquitetura à tag, portanto a imagem carregada é dasel:test-amd64.
Como a imagem consome o pacote construído localmente (a restrição-chave). O apko/dasel.yaml lista ./packages como repositório e ./melange.rsa.pub como keyring. Assim, o apko instala o APK dasel exato que o melange build escreveu em packages/x86_64/ — verificado com nossa própria chave de assinatura — e não um pacote upstream pré-construído. (Execute apko build a partir da raiz do repositório para que esses caminhos relativos sejam resolvidos.) É isso que conecta o build do pacote ao build da imagem.
./tests/test.sh
Executa a imagem via docker run e verifica (5 checagens): o dasel está presente e informa v3.3.1, uma consulta JSON aninhada, uma conversão JSON→YAML, uma consulta por índice de array e a rejeição da bomba YAML. O script sai com código diferente de zero se qualquer checagem falhar (para funcionar como gate no CI). Substitua a tag com IMAGE=<tag> ./tests/test.sh.
CVE-2026-33320 é uma negação de serviço (CWE-674, recursão não controlada) no leitor YAML do dasel: um ataque de "billion laughs" por meio de expansão de alias YAML sem limites. O dasel implementou seu próprio UnmarshalYAML e resolveu nós de alias recursivamente sem limite, contornando a proteção embutida da biblioteca subjacente.
Fazemos o backport apenas da correção upstream (commit 282943b, publicado na v3.3.2) para o código v3.3.1 como patches/cve-2026-33320.patch. Ela limita a expansão com um limite de profundidade (32) e um orçamento (1000) compartilhado, retornando um erro em vez de expandir sem limites. Nós deliberadamente excluímos as correções de bugs não relacionadas que também saíram na v3.3.2, mantendo a alteração mínima e auditável. Consulte patches/NOTES.md para detalhes completos.
git-checkout fixa expected-commit no SHA do commit v3.3.1, então o
build falha se a tag for re-apontada para um código diferente (segurança da cadeia de suprimentos).CGO_ENABLED=0 (definido no ambiente de build da receita), então o
binário não tem cgo nem dependências de bibliotecas compartilhadas — é isso que permite que a imagem seja distribuída sem
libc/shell/gerenciador de pacotes.packages: do apko contém apenas dasel; a imagem instala somente nosso
pacote construído localmente (verificado com nosso melange.rsa.pub).nonroot) para defesa em profundidade.x86_64 (a arquitetura da máquina de desenvolvimento).docker como runner do Melange (bubblewrap também funcionaria em Linux nativo)./etc/os-release); nada na imagem
precisa dele. Esta é uma escolha deliberada de minimalismo, trivialmente reversível ao adicionar
wolfi-baselayout.go e o busybox rolling do Wolfi em vez de snapshots fixados, então pressupõe
que o Wolfi continue fornecendo um Go ≥ 1.25 (exigência do go.mod do dasel). O código-fonte do dasel é fixado por
commit; fixar também a toolchain de build tornaria o build totalmente hermético (veja abaixo).go/busybox do Wolfi) e uma data de build fixa para um
build totalmente hermético e reproduzível bit a bit (o código-fonte já é fixado por commit).aarch64) para máquinas ARM.melange build + melange test: o pacote compila, o patch é aplicado limpo (todos os 7 hunks — 1 em
parsing/yaml/yaml.go, 6 em parsing/yaml/yaml_reader.go), todos os testes do pacote verdes, incluindo
o teste de bomba da CVE.apko build + tests/test.sh: a imagem compila (~4 MB de conteúdo), todos os 5 testes da imagem verdes.