Skip to content

Remove latest tag from all existing and future GHCR packages #1451

@lightwalker-eth

Description

@lightwalker-eth

Background

See comment thread: #1399 (comment)

Note

I asked ChatGPT to generate the following issue description based on my prompts:

Context

All consumers of our container images must pin explicit version tags (x.y.z) and must not rely on latest, to prevent unintended upgrades when new releases are published.

We already prevent future releases from publishing latest (via docker/metadata-action with latest=false).
However, existing org-owned GHCR package versions still have both:

  • latest
  • x.y.z

In GHCR, tags are pointers to a package version (manifest digest). A single version can have multiple tags, and GitHub does not support deleting a single tag directly. Deleting a version removes all tags attached to it.

Goal

Remove the latest tag from all existing org-owned GHCR container packages while preserving all x.y.z tags.

After completion:

  • No org-owned GHCR package has a latest tag
  • All versioned tags remain available
  • CI/CD does not reintroduce latest

Scope

  • Applies to: org-owned GHCR container packages (ghcr.io//)
  • Does not apply to: user-owned packages, third-party images, or future releases

Constraints / Important Notes

  • GHCR does not support “untagging” a single tag directly.
  • Deleting a package version deletes all tags attached to it.
  • We must move x.y.z off any version that also has latest before deleting anything.
  • Version tags (x.y.z) will become mutable during this process (acceptable).
  • Deleting org-owned package versions requires:
    • GitHub org admin or package admin permissions
    • A token with delete:packages scope (PAT) or equivalent org permissions

Required Permissions

One of the following:

  • Org admin
  • Package admin for the GHCR package
  • PAT with:
    • read:packages
    • delete:packages

Implementation Plan (Safe Pattern)

For each org-owned image with a version tagged ["latest", "x.y.z"]:

  1. Re-push the x.y.z tag only
    Rebuild or re-tag and push the image using only the version tag.
docker buildx build --push \
  -t ghcr.io/<org>/<image>:x.y.z \
  .

Important:

  • Do not push latest
  • This moves x.y.z to a new package version in GHCR
  1. Verify GHCR state
    Confirm the package now shows:
  • One package version with tag x.y.z
  • One package version with tag latest only
  1. Delete the latest-only package version
    Delete the package version that now has only the latest tag.

This can be done via:

  • GitHub UI → Packages → → Versions → Delete
  • GitHub REST API (Packages → Delete package version)
  1. Repeat for all affected images

Deliverables

  • All org-owned GHCR images free of latest
  • All x.y.z tags preserved and pullable
  • Confirmation that CI/CD cannot reintroduce latest

Validation Steps

  • docker pull ghcr.io//:latest → fails
  • docker pull ghcr.io//:x.y.z → succeeds
  • GHCR UI shows no package versions with latest

Acceptance Criteria

  • Zero latest tags exist in org-owned GHCR packages
  • All consumers continue working with pinned versions
  • Future releases do not publish latest

Metadata

Metadata

Assignees

No one assigned

    Labels

    devopsDevOps related

    Type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions