Skip to content

Add a minimum release age for mutable image tags using registry tag history #13933

Description

@wolph

Description

Summary

Docker Compose should support an opt-in minimum release age for images referenced by mutable tags. During docker compose pull or docker compose up, Compose should resolve the tag to the newest digest that has remained associated with that tag for at least the configured duration.

Conceptually, this is uv exclude-newer for container images:

services:
  redis:
    image: redis:latest
    minimum_release_age: 14d

This is intentionally a runtime policy, not a lock-file feature. Pinning a digest is already possible, but it does not let users follow a mutable channel such as latest, stable, or 7 with a deliberate delay.

Why this matters

Automated updates can deploy a compromised, broken, or prematurely published release within minutes. If it is removed or replaced a few hours later, immediate consumers have already run it. A minimum-age policy provides an observation window in which maintainers, scanners, users, and registries can detect and retract a bad release before it becomes eligible.

This mitigation has become common in package tooling:

Existing Compose pull_policy values such as daily or weekly only control when Compose checks. They do not ensure that the digest found at that moment has existed for a minimum amount of time.

Proposed behavior

For redis:latest with a 14-day minimum, Compose should inspect the history of that exact tag:

  • Digest A was assigned for 30 days: eligible.
  • Digest B replaced A but was removed after two days: never eligible.
  • Digest C is currently assigned but only eight days old: not yet eligible.

Compose should continue pulling A until C has remained assigned for 14 days. This prevents a short-lived or retracted digest from becoming eligible merely because its original timestamp is now old.

Important semantics:

  • Age must be based on the registry-recorded tag-to-digest assignment, not the publisher-controlled image build timestamp. Retagging old content must not bypass the waiting period.
  • Registries must retain at least the last eligible digest and its blobs while a successor is maturing. Explicitly withdrawn or revoked digests must not be selected.
  • Multi-platform tags should be resolved at the manifest-list/image-index digest.
  • If trustworthy tag history or a retained eligible digest is unavailable, configured enforcement should fail closed rather than silently pulling the newest image.
  • An explicit one-shot CLI override should allow urgent security updates.
  • pull_policy should decide whether to check the registry; minimum_release_age should constrain which digest may be pulled.

The feature should be opt-in and backward compatible. The exact Compose schema and override name are open for discussion.

Existing foundation and implementation scope

The standard OCI Distribution API can list tags and retrieve manifests, but it does not currently provide portable history for a mutable tag. The optional org.opencontainers.image.created annotation describes build time and is not a safe substitute for registry-recorded tag history.

Relevant work already exists:

That OCI proposal is a strong foundation, but the complete feature also needs retention and revocation semantics: a historical digest is useless if its manifest or blobs have been garbage-collected, and normal supersession must be distinguishable from withdrawal of a previously matured digest.

I expect the work to span:

  1. OCI Distribution and registries: standardize and implement tag history, withdrawal, and sufficient content retention.
  2. Docker Engine/API: authenticate to registries, resolve the newest eligible digest, and expose that result to clients. Engine is the appropriate layer because it already handles credentials, mirrors, proxies, custom CAs, platforms, and pulling.
  3. Compose Specification and Docker Compose: add the service policy, apply it to pull and up, show the selected digest and skipped newer assignments, provide the emergency override, and test the behavior.

Implementing registry-specific history clients directly in Compose would duplicate Engine responsibilities and would not produce an interoperable solution. This issue could serve as the user-facing umbrella for coordinated work across those projects.

This is defense in depth, not a replacement for signatures, attestations, scanning, digest pinning, or trusted registries. It primarily protects against releases that are detected and withdrawn within the configured observation window.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions