build: pin ko base images by digest (#1500)

Fixes #1498

- [x] Tests pass
- [x] Appropriate changes to documentation are included in the PR

Every base image in `.ko.yaml` was referenced by tag only, so two builds
of
the same commit could produce different images depending on when they
ran.

- Pin all three by digest, keeping the tag alongside so a bump can
re-resolve it.
- `alpine` → `alpine:3.24` and `debian:stable-slim` → `debian:13-slim`:
the same
releases the floating tags resolve to today, but a routine bump now
stays
  within a major; moving majors becomes a deliberate edit.
- Distroless only publishes `latest`/`nonroot`, so it stays `latest` +
digest.

### How the digests were resolved

Each is the multi-arch **index** digest for the tag (what ko needs,
since it
builds `linux/amd64` and `linux/arm64` from one base), resolved on
2026-09-04
with the `crane` that ships in the go-containerregistry version ko
already
pins — no new dependency:

    cd hack/tools/ko
    go run github.com/google/go-containerregistry/cmd/crane digest <ref>

| Pinned ref | Digest |
|---|---|
| `gcr.io/distroless/static-debian13:latest` |
`sha256:f2ea2709ac8db56323cbd7d014277f32cb572d9ea124b0076f7aafe5980678fe`
|
| `alpine:3.24` |
`sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b`
|
| `debian:13-slim` |
`sha256:d7e12182ce18b85b93007c1dedf31f2d29e01ccf3182cc4017c709b6259bc132`
|

Cross-checks at resolve time: `alpine:latest`, `alpine:3`, and
`alpine:3.24`
all resolve to the same digest, so the tag change does not change the
image.
`debian:13-slim` and `debian:trixie-slim` are the same digest;
`debian:stable-slim` currently also points at Debian 13. Anyone can
re-run
the command above to confirm (the digests will match until upstream
publishes a rebuild, which is what the bump job will pick up).

### Verified locally

- `hack/verify/ko-base-images.sh` passes, and fails correctly when a
digest
  is removed from any ref.
- `hack/verify/boilerplate.sh` passes.
- `ko build --push=false` of `cmd/podcertcontroller`,
`cmd/ateom-microvm`,
  and `demos/sandbox` (one per base) resolves all three pinned bases and
  builds.
- The kind e2e lane builds every image on these bases.

Follow-up: a scheduled job to re-resolve the digests weekly.
This commit is contained in:
Grant McCloskey
2026-09-08 11:03:12 -07:00
committed by GitHub
parent a1d3bb650b
commit 965552d9b6
+4 -4
View File
@@ -12,15 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
defaultBaseImage: gcr.io/distroless/static-debian13
defaultBaseImage: gcr.io/distroless/static-debian13:latest@sha256:f2ea2709ac8db56323cbd7d014277f32cb572d9ea124b0076f7aafe5980678fe
defaultPlatforms:
- linux/amd64
- linux/arm64
baseImageOverrides:
github.com/agent-substrate/substrate/demos/sandbox: alpine
github.com/agent-substrate/substrate/demos/sandbox: alpine:3.24@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b
# ateom-microvm needs glibc (for the fetched cloud-hypervisor binary) and mount/umount
# (to bind the image into the virtiofsd shared dir) — both in debian:stable-slim but
# (to bind the image into the virtiofsd shared dir) — both in debian:13-slim but
# not in the distroless static default.
github.com/agent-substrate/substrate/cmd/ateom-microvm: debian:stable-slim
github.com/agent-substrate/substrate/cmd/ateom-microvm: debian:13-slim@sha256:d7e12182ce18b85b93007c1dedf31f2d29e01ccf3182cc4017c709b6259bc132