Problem
make refresh-operator-digests (which calls hack/refresh-operator-image-digests.sh) fails immediately on any machine without Docker Desktop installed.
The script's preflight() function checks for both docker and docker buildx before performing any work. If either is missing, it exits immediately:
$ make refresh-operator-digests
Error: docker is required
# or
Error: docker buildx is required
This is a problem because the actual work performed by the script—resolving an image digest from the registry and writing a ConfigMap to the cluster—does not inherently depend on Docker.
Docker is only required for one implementation detail: resolving the digest behind the :latest tag.
Affected Paths
make refresh-operator-digests
hack/deploy-infra.sh when running with WITH_CONTROLPLANE=true CONTROLPLANE_OPERATORS=flux, which invokes this script internally
Affected Users
Any developer working with:
- Podman instead of Docker Desktop
- Lima, Rancher Desktop, or another OCI runtime
- Only
kubectl installed (for example, when working against an existing cluster)
Root Cause
resolve_image_digest() currently has a single implementation that depends on Docker Buildx:
docker buildx imagetools inspect "${image}" \
--format '{{json .Manifest.Digest}}' 2>/dev/null | tr -d '"'
As a result, the script fails during preflight even though Docker is only required for digest resolution.
Suggested Fix
Support multiple digest resolution backends, tried in the following order:
1. Docker Buildx (existing behaviour)
Use the current implementation when docker buildx is available.
docker buildx imagetools inspect "${image}" \
--format '{{json .Manifest.Digest}}'
2. HTTP Registry API fallback
If Docker Buildx is unavailable, resolve the digest directly through the Docker Registry V2 API by:
-
requesting
GET https://<registry>/v2/<repository>/manifests/<reference>
-
handling the 401 Unauthorized response and the WWW-Authenticate: Bearer challenge returned by GHCR
-
requesting a bearer token
-
repeating the request with the token
-
reading the digest from the Docker-Content-Digest response header
This preserves the existing behaviour for Docker Desktop users while allowing the script to run on systems without Docker installed.
Problem
make refresh-operator-digests(which callshack/refresh-operator-image-digests.sh) fails immediately on any machine without Docker Desktop installed.The script's
preflight()function checks for bothdockeranddocker buildxbefore performing any work. If either is missing, it exits immediately:This is a problem because the actual work performed by the script—resolving an image digest from the registry and writing a ConfigMap to the cluster—does not inherently depend on Docker.
Docker is only required for one implementation detail: resolving the digest behind the
:latesttag.Affected Paths
make refresh-operator-digestshack/deploy-infra.shwhen running withWITH_CONTROLPLANE=true CONTROLPLANE_OPERATORS=flux, which invokes this script internallyAffected Users
Any developer working with:
kubectlinstalled (for example, when working against an existing cluster)Root Cause
resolve_image_digest()currently has a single implementation that depends on Docker Buildx:As a result, the script fails during preflight even though Docker is only required for digest resolution.
Suggested Fix
Support multiple digest resolution backends, tried in the following order:
1. Docker Buildx (existing behaviour)
Use the current implementation when
docker buildxis available.2. HTTP Registry API fallback
If Docker Buildx is unavailable, resolve the digest directly through the Docker Registry V2 API by:
requesting
handling the
401 Unauthorizedresponse and theWWW-Authenticate: Bearerchallenge returned by GHCRrequesting a bearer token
repeating the request with the token
reading the digest from the
Docker-Content-Digestresponse headerThis preserves the existing behaviour for Docker Desktop users while allowing the script to run on systems without Docker installed.