Repository navigation
chore(docker): shell-free runtime image on a pinned Wolfi base - #4187
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4187 +/- ##
==========================================
- Coverage 80.91% 80.87% -0.04%
==========================================
Files 509 509
Lines 39161 39161
==========================================
- Hits 31686 31671 -15
- Misses 7469 7484 +15
Partials 6 6 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Claude finished @brbrr's task in 8m 7s —— View job Review complete
SummaryThis is a well-scoped, well-documented infra change (Debian → Chainguard Wolfi runtime base, jemalloc static-link trick, Nit
Verified separately:
No inline blockers. Nice work on the CVE reduction and documentation. |
|
Claude finished @brbrr's task in 18m 3s —— View job Review complete
This round switches the final-stage approach from the previously-reviewed digest-pinned Nit
No correctness, concurrency, or protocol-path issues — this PR only touches build tooling ( |
|
Claude finished @brbrr's task in 16m 58s —— View job Review complete
SummaryThis PR only touches build tooling ( Latest commit ( Verified in this pass:
No inline comments this round — nothing new to flag beyond what was already addressed. Nice iteration on hardening the manifest parsing. |
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
|
Claude finished @brbrr's task in 4m 22s —— View job Review complete
SummaryThis PR only touches build tooling ( Blocker from the prior round — resolved
Nit (carried over, non-blocking)
Verified
No inline comments this round — the only blocker from prior reviews has been addressed and nothing new surfaced. |
|
Claude finished @brbrr's task in 6m 48s —— View job Review complete
SummaryThe Docker/build-tooling files ( This PR only touches build tooling and an indirect Go dependency bump — nothing under Carried-over blocker — already resolved
Nits (non-blocking, previously raised, still open by design)
Verified
No inline comments this round — everything previously flagged as a blocker has been addressed, and nothing new surfaced since the last review. |
|
The only caveat is that we no longer have the image updated on each build, but I think that is a feature, not a bug, right? |
adf7b5a to
8c3be88
Compare
|
Claude finished @brbrr's task in 5m 6s —— View job Review complete
SummaryThe new commit (
This is a reasonable way to de-risk the rollout. All blockers from prior review rounds (missing Nit (posted inline on
Also noted (non-blocking, not flagged inline)
|
User description
Summary
The security scan of
nethermind/juno:v0.16.7reports 158 CVE IDs (17 Critical, 51 High, 73 Medium, 17 Low). Almost all of them come from the Debian 12 base image and from packages that juno does not use (curl, gawk, grep, and the libstdc++ thatlibjemalloc2pulls in). This PR removes them.FROM scratchwith a Wolfi root filesystem. A newbasestage builds it with apko from the public Wolfi repository (packages.wolfi.dev/os, checked with the Wolfi signing key). The image has glibc, libgcc, CA certificates and tzdata, but no shell and no package manager.docker/apko.yamllists the packages.docker/apko.lock.jsonpins the exact version of each package for amd64 and arm64, so a build from a given commit is reproducible.make apko-lockupdates the lock file to the latest Wolfi packages.basestage runs on the build platform, so a cross-arch build needs no emulation for it.libjemalloc.so, so-ljemalloclinkslibjemalloc.a. The binary now needs only libc, libm, libgcc_s and ld-linux. Thenarenas:2config still applies.title,vendor,sourceandlicenseslabels.golang.org/x/netv0.58.0 → v0.60.0: fixes CVE-2026-78659, -78660, -78663 and -78669 inx/net/http2(used through grpc). The Go 1.27.2 builder fixes the stdlib part of these CVEs.docker-compose.yml: the healthcheck runsjuno --help, because the image has nosleep.Image size: 248MB → 141MB (arm64), 150MB (amd64).
Breaking change
The image has no shell and no utilities. These no longer work:
docker exec -it <container> sh. Use a debug container that shares the namespaces (docker run --pid container:juno --network container:juno busybox sh, orkubectl debug --target=juno), ordocker cp.command: ["sh", "-c", "juno ..."], or any other script in the container. Runjunodirectly with a list of args. Kubernetes expands$(VAR)in args, and juno readsJUNO_*environment variables.curlor other tools in the container. HTTP probes on/liveand/readyare not affected.The ArgoCD workloads that started juno through a shell were changed in NethermindEth/argocd#10983 (merged).
CVE result
Trivy 0.69.3, same DB, old and new image:
nethermind/juno:v0.16.7The remaining Go finding is GO-2026-5932 (
golang.org/x/cryptov0.57.0). It has no fix yet.Trivy does not report 3 IDs from the scan list:
Testing
On arm64 with the image built from this branch, and on amd64 with the same Wolfi base and juno binary (CI builds the full amd64 image):
x/netv0.60.0, and the jemallocnarenas:2config applies./bin/shand no libstdc++.starknet_callof ETHname()returns0x4574686572("Ether").TZ=Europe/Berlingives log timestamps in+02:00.apko buildruns from the same lock file give the same SHA-256.In CI,
smoke_test_100_blockspasses with the amd64 image.dev_deploy_test / deployfails because the dev node does not get the new image. It fails the same way on all branches since 2026-10-13, so this PR does not cause it.PR Type
Enhancement
Description
Replace Debian runtime base with a shell-free Wolfi rootfs built via apko, dropping most scanned CVEs
Pin exact Wolfi package versions in
docker/apko.lock.json; addmake apko-lockto refreshLink jemalloc statically in the builder; final image is built
FROM scratchwith OCI labelsBump
golang.org/x/netto v0.60.0, fixing http2 CVEs reached through grpcFile Walkthrough
4 files
Makefile
Add apko-lock target for pinning Wolfi packagesMakefile
APKO_VERSIONvariable (v1.4.11), kept in sync with the Dockerfileapko-locktarget that runs apko to regeneratedocker/apko.lock.jsonwith the latest Wolfi packagesdocker-compose.yml
Fix healthcheck for shell-free runtime imagedocker-compose.yml
sleep 4withjuno --help, since thenew runtime image contains no shell
apko.lock.json
Pin Wolfi package versions for reproducible image buildsdocker/apko.lock.json
package for x86_64 and aarch64
packages.wolfi.devrepositoryreferences for reproducible, verified builds
apko.yaml
Add apko config for Wolfi runtime filesystemdocker/apko.yaml
wolfi-baselayout,ca-certificates-bundle,glibc-2.44,ld-linux-2.44,libgccandtzdata1 files
Dockerfile
Build scratch-based runtime image from apko Wolfi rootfsDockerfile
libjemalloc.soso-ljemalloclinks thestatic
libjemalloc.abasestage installs apko and builds a Wolfi rootfs fromdocker/apko.yamland the lock file, extracting its single layer on thebuild platform (no emulation for cross-arch)
debian:bookworm-slimtoscratch, copyingonly the apko rootfs and the juno binary
SSL_CERT_FILEand adds OCItitle,vendor,sourceandlicenseslabels
2 files
go.mod
Upgrade golang.org/x/net for http2 CVE fixesgo.mod
golang.org/x/netfrom v0.58.0 to v0.60.0, fixing CVEs inx/net/http2used through grpcgo.sum
Update checksums for x/net dependency bumpgo.sum
golang.org/x/netv0.60.0upgrade and its transitive module changes