deploy-image: image reference is parsed by hand and produces invalid version labels

Author: camilamacedo86Created Aug 14, 2026Updated Aug 14, 2026

Background

The scaffolded controller builds the app.kubernetes.io/version label like this:

go
imageTag = strings.Split(image, ":")[1]

At create api, the plugin checks that --image is not empty. It does not check the format. The --image-container-port flag next to it is validated.

PR #5962 reports the panic this causes and proposes reading only an explicit tag after the last path slash. The gap is real. The open point is whether to fix the parsing or the design.

The problem

Splitting on : does not match the structure of an image reference. The following results come from validation.IsValidLabelValue:

Image Split(image, ":")[1] Result
example.com/image:test test valid
busybox panic, index out of range
localhost:5000/busybox 5000/busybox invalid label value
localhost:5000/busybox:v1 5000/busybox invalid label value
busybox@sha256:7b3cca… 64 characters invalid, over 63 bytes
busybox:_dev _dev invalid, must start with an alphanumeric character

There are two distinct problems:

  • A tagless image is valid and common. The first reconcile panics.
  • A valid image tag is not always a valid label value. Tags allow 128 characters and can start with _. Label values allow 63 characters and must start and end with an alphanumeric character. Correct tag extraction still produces objects that the API server rejects.

app.kubernetes.io/version is one of the recommended labels. When there is no version to state, the convention is to omit the label rather than set it to an empty string.

Proposed direction

Validate the input where the plugin receives it

--image is user input, and the plugin accepts it unchecked. Validate it at create api, alongside --image-container-port. The command then fails while the user is still typing it, rather than at the first reconcile in a cluster.

Open question: how strict should the check be? Reject any value that is not a valid image reference, or accept the value and warn only when the tag cannot become a label value?

Parse the reference correctly, or drop the derived label

Splitting on : cannot be corrected by patching it. Either apply the canonical rules — registry, repository, tag, digest — or stop deriving the label from the image.

Decide what the reconcile does when no usable version exists

  • Omit the label. This matches the convention, and is silent.
  • Omit the label and report it on the resource status. This is the preference expressed on #5962.
  • Fail the reconcile. This is too strict, because a tagless image is legitimate.

If the controller reports it on status, follow the conventions the scaffold already uses:

  • Set a metav1.Condition through meta.SetStatusCondition.
  • Use a CamelCase Reason, for example InvalidImageReference.
  • Write a Message that names the image and explains why no version was derived.
  • Set ObservedGeneration.
  • Reuse the Available or Degraded types. A missing version label does not make the workload unavailable, so a third type is unlikely to be justified.
  • Set ObservedGeneration.
  • Reuse the Available or Degraded types. A missing version label does not make the workload unavailable, so a third type is unlikely to be justified.

Tests

Input validation belongs in the plugin tests, alongside the existing --image-container-port cases. It does not belong in the scaffolded controller test.

The scaffolded controller test covers reconcile behaviour. It currently hardcodes example.com/image:test and asserts only the Available condition. It never inspects the Deployment labels, which is why the panic in #5962 went unnoticed.

Add coverage for:

  • A tagged image reconciles, and the Deployment carries app.kubernetes.io/version with the tag.
  • busybox reconciles without panicking, and the version label is absent rather than empty.
  • A tag that is not a valid label value behaves the same way.
  • The expected condition Reason, if the controller reports the problem on status.

These tests are scaffolded into every user's project, so they also serve as the example of how to test a controller.

References

Source: kubernetes-sigs/kubebuilder