[bug]: feature-branch workflows publish to public Docker Hub, polluting release registries
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 59.6k
- Forks
- 5.8k
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 49
Description
Summary
makeplane/plane's build workflows publish Docker images to the public makeplane/* Docker Hub org for any workflow_dispatch invocation, regardless of which branch is selected. The branch name becomes the tag. As a result, makeplane/* (and the parallel makeplane/*-commercial repos, presumably built by a sibling private repo using the same shared action) accumulate hundreds of feature-branch, ephemeral, and label tags mixed in with semver releases.
This breaks automated dependency trackers (Renovate, Dependabot) for consumers of these images and leaks internal development state (branch names, fix descriptions, contributor shorthand) into a public registry.
Context
I hit this while setting up Renovate against a Kubernetes deployment of Plane Commercial Edition at my company, tracking the planeVersion Helm chart value automatically. Renovate proposed v2.5.3 → v2.11.1 as an "upgrade" — which led me down the rabbit hole of auditing the registry and figuring out why.
Evidence
Audited makeplane/backend-commercial on Docker Hub: 367 tags total.
| Bucket | Count | Examples |
|---|---|---|
Clean semver vX.Y.Z |
65 | v2.5.4, v2.5.3 |
CalVer vYY.MM.DD-N |
2 | v24.09.23-1, v24.09.22-1 |
*-phoenix-<sha> builds |
44 | v2.5.0-phoenix-0ab83bc |
| Branch names, labels, RCs, prerelease majors | 256 | buildcache, fixpnpmpathci, fix-pi-streaming, feat-auto-embedding-model-creation, v2.5.4-rc1, v3.0.0-guinness-4fb2ad3, stable, preview, chorereusedbconnections |
The CE-side makeplane/* repos exhibit the same pattern — same workflows, same shared action.
Specific consumer impact:
v2.11.1(published 2025-10-17) version-sorts abovev2.5.xbut predates it in the real release timeline — and in fact was published ~7 weeks beforev2.0.0itself (2025-12-05). Renovate proposesv2.5.3 → v2.11.1as an upgrade — actually a downgrade to a stale, out-of-band build.v24.09.23-1,v24.09.22-1sort as major version 24, becoming the "newest" tag oncev2.11.1is excluded.v3.0.0-guinness-<sha>is a publicv3.0.0prerelease that would propose a phantom major upgrade if a tracker ever relaxed its prerelease filter.
Renovate workaround we landed on after several CI iterations:
"allowedVersions": "<v2.11.1 || >v2.11.1 <v24.0.0"
Root cause
Two workflows in this repo invoke the shared makeplane/actions/build-push@v1.4.0 composite action against arbitrary branches:
.github/workflows/build-branch.yml— auto-push is gated topreview/canary, butworkflow_dispatchaccepts any branch as input..github/workflows/feature-deployment.yml— explicitly designed to publish feature-branch previews, always viaworkflow_dispatch.
The shared action's tag-selection logic (in build-push/action.yml):
elif [ "${{ env.TARGET_BRANCH }}" == "master" ]; then
TAG=${{ env.IMG_OWNER }}/${{ env.IMG_NAME }}:latest
...
else
TAG=${{ env.IMG_OWNER }}/${{ env.IMG_NAME }}:${FLAT_BRANCH_VERSION}
if [ "${{ env.PRIVATE_REGISTRY_PUSH }}" == "true" ]; then
TAG=${TAG},${{ env.PRIVATE_REGISTRY_ADDR }}/...:${FLAT_BRANCH_VERSION}
fi
fi
For any non-release, non-master invocation, the action pushes to public Docker Hub with the flattened branch name as the tag. The private-registry-push input adds a private target alongside the public push rather than replacing it — there is no way for a caller to publish privately only.
buildcache comes from the BuildKit cache-to: type=registry,ref=.../img:buildcache configuration pointing at the same public repo. stable, *-phoenix-<sha>, and v3.0.0-guinness-<sha> come from the release path with a permissive semver regex (^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)?$) that accepts arbitrary suffix chains.
Proposed fix
Two layers to consider, depending on where you'd prefer the gate:
At the caller (this repo):
- Restrict
feature-deployment.ymlto push toregistry.plane.toolsonly (or a separatemakeplane/*-previewDocker Hub org), never the release repo. - Restrict
build-branch.yml'sworkflow_dispatchmode to a ref allowlist (master,preview,canary, plus release tags). - Move BuildKit
cache-tooff the public release repo to a private cache target or GHA cache backend.
At the shared action (makeplane/actions):
- Make public Docker Hub push opt-in rather than always-on. Add a
public-registry-pushboolean (parallel toprivate-registry-push), defaulting tofalsefor non-release builds. This prevents the class of mistake for every consumer, including whichever private repo builds the*-commercialimages. - Tighten the release-version regex to reject
-<word>-<sha>style suffixes, or require an explicit prerelease flag and route them to aprerelease-namespaced tag.
The caller-side fix unblocks the immediate registry hygiene problem. The action-side fix is the systemic version. Both are worthwhile; the caller fix is the smaller patch.
Happy to open a PR if there's directional agreement on which approach you'd prefer.
Why this matters externally
For self-hosters tracking planeVersion automatically, every release the registry produces a new ambiguous tag that breaks the next upgrade proposal. The workaround range above is fragile — the next leaked v25.* or v3.0.1-foo tag will require another CI iteration and another Renovate config update. Cleaning this up at the source benefits every consumer of the public images.
Beyond the tooling impact, it also just looks messy. A public registry surfacing tags like fixpnpmpathci, chorereusedbconnections, and feat-auto-embedding-model-creation alongside semver releases reads as either unmaintained or careless to anyone browsing the tag list. Branch-name internal state (in-flight feature names, fix descriptions, contributor shorthand) is visible to anyone with a Docker Hub account. For the self-hosters and integrators who do look — anyone wiring up automation, debugging an image pull, or evaluating the project's release discipline — the registry reads as part of the public surface. Worth treating it as one.
Immediate ask
Independent of any workflow changes, it would be great to get the three tags that actively break version-aware trackers retagged or removed from makeplane/*-commercial (and makeplane/* if present there too):
v2.11.1v24.09.23-1v24.09.22-1
These are the ones that cause incorrect upgrade proposals today. Removing them lets consumers drop the allowedVersions workaround and unblocks normal version tracking while the longer-term fix is being scoped.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with .github/workflows/build-branch.yml and feature-deployment.yml, then inspect the referenced makeplane/actions/build-push@v1.4.0 action and its build-push/action.yml. Compare workflow_dispatch ref handling, registry targets, and cache-to behavior; done means feature builds no longer pollute public release repositories while intended release publishing still works.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, github-actions
- Domain
- ci-cd, devops, release
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100