ci(docker): never emit latest/v* from a manual preview build

The workflow_dispatch `ref` input is meant to preview an unmerged branch,
and the only ref guaranteed to carry this workflow after merge is master —
so the expected way to run it is dispatch-from-master with `ref` set to the
branch. But on a workflow_dispatch dispatched from master, `github.ref` is
the default branch, so `type=raw,value=latest,enable={{is_default_branch}}`
still fired: a preview image would move `latest` and poison every host that
pulls it. `type=semver` was likewise ungated (a dispatch from a v* tag would
have minted a release tag pointing at the previewed ref).

Gate both off for workflow_dispatch so a manual run can only ever produce
the `sha-<short>` tag. The `latest` gate now checks the default branch
explicitly instead of `{{is_default_branch}}` so it can also exclude the
dispatch case; on push:master and tag:v* the emitted tags are unchanged.

Tested: js-yaml and ruby YAML both parse the file; grep confirms both the
self-hosted and cloud meta blocks are gated symmetrically.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
TonioandPaperclip committed 2026-08-08 17:48:57 -07:00
1 parent 02c6fa1c6c
commit 0cec411087
1 file changed
+18 -6
+18 -6
View File
@@ -169,9 +169,15 @@ jobs:
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
# `latest` and `v*` are release pointers. Gate them off for manual
# (workflow_dispatch) runs — even one dispatched from master — so a
# preview build can never move `latest` or mint a release tag. The
# explicit default-branch check replaces `{{is_default_branch}}`,
# which is also true on a dispatch from master and would otherwise
# leak `latest` onto a preview image.
type=raw,value=latest,enable=${{ github.ref_name == github.event.repository.default_branch && github.event_name != 'workflow_dispatch' }}
type=semver,pattern={{version}},enable=${{ github.event_name != 'workflow_dispatch' }}
type=semver,pattern={{major}}.{{minor}},enable=${{ github.event_name != 'workflow_dispatch' }}
# push/tag builds keep the stock sha tag (sha-<short> of github.sha).
# A manual run may build a ref other than github.sha, so it tags the
# resolved commit instead — same sha-<short> format, correct commit.
@@ -353,9 +359,15 @@ jobs:
flavor: |
suffix=-cloud,onlatest=true
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
# `latest` and `v*` are release pointers. Gate them off for manual
# (workflow_dispatch) runs — even one dispatched from master — so a
# preview build can never move `latest` or mint a release tag. The
# explicit default-branch check replaces `{{is_default_branch}}`,
# which is also true on a dispatch from master and would otherwise
# leak `latest` onto a preview image.
type=raw,value=latest,enable=${{ github.ref_name == github.event.repository.default_branch && github.event_name != 'workflow_dispatch' }}
type=semver,pattern={{version}},enable=${{ github.event_name != 'workflow_dispatch' }}
type=semver,pattern={{major}}.{{minor}},enable=${{ github.event_name != 'workflow_dispatch' }}
# push/tag builds keep the stock sha tag (sha-<short> of github.sha).
# A manual run may build a ref other than github.sha, so it tags the
# resolved commit instead — same sha-<short> format, correct commit.