Skip to content

Resolve dependent images (pre_start hooks, type: image volumes) in WithImagesResolved#894

Merged
glours merged 2 commits into
compose-spec:mainfrom
ndeloof:resolve-prestart-hook-images
Jul 21, 2026
Merged

Resolve dependent images (pre_start hooks, type: image volumes) in WithImagesResolved#894
glours merged 2 commits into
compose-spec:mainfrom
ndeloof:resolve-prestart-hook-images

Conversation

@ndeloof

@ndeloof ndeloof commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

What I did

Project.WithImagesResolved only resolved the top-level service.Image, but a service can depend on other images that should be pinned by docker compose config --resolve-image-digests too:

  • pre_start hook images — hooks run as ephemeral init containers with their own image (ServiceHook.Image)
  • type: image volume sources — these mount an image referenced by the volume source

This PR extracts the single-image digest resolution into a resolveImageDigest helper and applies it to the service image, each pre_start hook image, and each type: image volume source.

  • Hooks without an explicit image fall back to the service image at runtime, so they are left untouched (empty in → empty out).
  • type: image volume sources that reference another service by name are resolved to a locally built image, not a registry digest, so they are skipped.
  • Already-canonical (digested) references and empty images are returned unchanged, preserving the existing behaviour for the service image.
  • The original Project stays unchanged: WithServicesTransform operates on a deepCopy, whose PreStart/Volumes slices have their own backing arrays, so the in-place updates never touch the caller's project.

Motivation

Downstream in Docker Compose, pre_start hook images are otherwise ignored by image resolution (see docker/compose#13924 / docker/compose#13937). That PR handles config --images, pull and up, but digest resolution/locking has to be done here because WithImagesResolved is the single place where digests are computed. The type: image volume case is the same class of dependent-image resolution.

Tests

  • Test_ResolveImages_preStartHooks: a service with image: alpine:3.20 and two pre_start hooks (one with image: alpine:3.19, one without an image) — asserts the service image and the explicit hook image are both resolved to ...@sha256:..., and the image-less hook is left empty.
  • Test_ResolveImages_imageVolumes: a service with three volumes — an external type: image source (alpine:3.19, resolved to a digest), a type: image source referencing another service (builder, left untouched), and a plain named volume (left untouched).

@ndeloof
ndeloof requested a review from glours July 13, 2026 08:06
@ndeloof ndeloof changed the title Resolve pre_start hook images in WithImagesResolved Resolve dependent images (pre_start hooks, type: image volumes) in WithImagesResolved Jul 13, 2026
@ndeloof
ndeloof force-pushed the resolve-prestart-hook-images branch 3 times, most recently from 0da904e to 467d4e8 Compare July 21, 2026 07:06
@glours
glours enabled auto-merge (rebase) July 21, 2026 07:52
ndeloof added 2 commits July 21, 2026 09:52
pre_start hooks run as ephemeral init containers with their own image, but
WithImagesResolved only resolved the service image, leaving hook images
un-pinned by `docker compose config --resolve-image-digests`.

Extract the single-image digest resolution into a resolveImageDigest helper
and apply it to both the service image and each pre_start hook image. Hooks
without an explicit image (which fall back to the service image at runtime)
are left untouched.

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
`type: image` volumes mount an image, referenced by the volume source, so
their digest should be pinned by `--resolve-image-digests` too. Resolve the
source like the service image, unless it references another service by name
(those map to a locally built image, not a registry digest).

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
@glours
glours force-pushed the resolve-prestart-hook-images branch from 467d4e8 to 903ac4c Compare July 21, 2026 07:52
@glours
glours merged commit 587a6bd into compose-spec:main Jul 21, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants