Skip to content

Fleet HelmOp cannot resolve OCI charts whose tags use the +up / _up convention #5410

Description

@e-minguez

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

A Fleet HelmOp pointing at an OCI Helm chart whose only published tags use
the Helm build-metadata convention (semver X.Y.Z+upA.B.C, stored in the
registry as the OCI-safe tag X.Y.Z_upA.B.C) never becomes Accepted. Fleet's
OCI version resolver treats spec.helm.version as a semver constraint and
fails to resolve a chart for every value of version — a specific
build-metadata version, the underscore tag, the plain X.Y.Z, and empty.

The same chart installs fine with the Helm CLI, which requests the tag directly
instead of listing + semver-matching.

Expected Behavior

Fleet should resolve and install the chart. In particular, a constraint of
109.0.1 (or the exact 109.0.1+up1.0.2) should match the published chart
version 109.0.1+up1.0.2, since semver comparison ignores build metadata.

Contrast: the Helm CLI works

Helm requests the tag directly (converting + -> _) instead of
listing + semver-matching, so it succeeds:

helm show chart oci://registry.suse.com/rancher/charts/rancher-ai-agent --version 109.0.1+up1.0.2
# Pulled: registry.suse.com/rancher/charts/rancher-ai-agent:109.0.1_up1.0.2
# ... version: 109.0.1+up1.0.2

helm pull oci://registry.suse.com/rancher/charts/rancher-ai-agent --version 109.0.1+up1.0.2
# downloads rancher-ai-agent-109.0.1_up1.0.2.tgz

### Steps To Reproduce

```bash
kubectl apply -f helmop.yaml

# Read the Accepted condition:
kubectl get helmop liz-agent-repro -n fleet-local \
  -o jsonpath='{.status.conditions[?(@.type=="Accepted")].status} {.status.conditions[?(@.type=="Accepted")].message}{"\n"}'

To test the other version values, edit spec.helm.version in helmop.yaml,
re-apply, and re-read the condition.

Cleanup:

kubectl delete -f helmop.yaml

The helmop file:

# Minimal Fleet HelmOp that reproduces the OCI "+up"/"_up" tag resolution
# failure. No Rancher AI Factory operator involved — this is pure Fleet.
#
# The chart's only published OCI tags use Rancher's build-metadata convention
# (e.g. 109.0.1_up1.0.2, which is the OCI-safe encoding of the semver
# 109.0.1+up1.0.2). Fleet's HelmOp OCI resolver treats spec.helm.version as a
# semver constraint and lists/filters the registry tags; it never resolves a
# chart for any value of version (see README.md for the matrix).
#
# Apply, then read the Accepted condition:
#   kubectl apply -f helmop.yaml
#   kubectl get helmop liz-agent-repro -n fleet-local \
#     -o jsonpath='{.status.conditions[?(@.type=="Accepted")].status} {.status.conditions[?(@.type=="Accepted")].message}{"\n"}'
#   kubectl delete -f helmop.yaml   # cleanup
apiVersion: fleet.cattle.io/v1alpha1
kind: HelmOp
metadata:
  name: liz-agent-repro
  namespace: fleet-local
spec:
  defaultNamespace: default
  helm:
    releaseName: liz-agent-repro
    repo: oci://registry.suse.com/rancher/charts/rancher-ai-agent
    # Try each of these values (one at a time) — all fail; see README.md:
    #   version: "109.0.1+up1.0.2"   # -> could not find tag matching constraint
    #   version: "109.0.1_up1.0.2"   # -> improper constraint (invalid semver)
    #   version: "109.0.1"           # -> could not find tag matching constraint
    #   version: ""                  # -> improper constraint (empty)
    version: "109.0.1+up1.0.2"
    takeOwnership: true
  targets:
  - clusterName: local

Environment

- Architecture: arm64
- Fleet Version: 0.15.2
- Cluster:
  - Provider:
  - Options:
  - Kubernetes Version: v1.35.6+k3s1

- Fleet version: registry.rancher.com/rancher/fleet:v0.15.2
- Rancher version: 2.14.2
- Kubernetes: rancher-desktop (but irrelevant I guess)
- Registry: `registry.suse.com/rancher/charts/rancher-ai-agent`
  (any OCI chart whose tags all carry `+up`/`_up` build metadata reproduces this)

Logs

Anything else?

Likely root cause

Fleet's OCI resolver enumerates the repository tags and parses each as semver to
build the candidate set for constraint matching. Tags encoded the OCI-safe way
(_up, because + is not allowed in OCI tags) fail semver parsing and are
dropped, leaving an empty candidate set — so no constraint can match. The
resolver does not apply Helm's _ -> + reverse conversion before parsing, nor
does it fall back to a direct tag pull the way the Helm CLI does.

Suggested fixes

  • When listing OCI tags, reverse Helm's encoding (_ -> +) before semver
    parsing, so 109.0.1_up1.0.2 is considered as 109.0.1+up1.0.2.
  • And/or, when spec.helm.version is an exact version, request that tag directly
    (Helm-CLI behavior) instead of list + constraint-match.

Observed results (all fail)

spec.helm.version Accepted message
109.0.1+up1.0.2 False could not get a chart version: could not find tag matching constraint "109.0.1+up1.0.2" in registry oci://registry.suse.com/rancher/charts/rancher-ai-agent: %!w(<nil>)
109.0.1_up1.0.2 False ... failed to compute version constraint from version "109.0.1_up1.0.2": improper constraint: 109.0.1_up1.0.2
109.0.1 False could not get a chart version: could not find tag matching constraint "109.0.1" in registry oci://registry.suse.com/rancher/charts/rancher-ai-agent: %!w(<nil>)
`` (empty) False ... failed to compute version constraint from version "": improper constraint:

Notes:

  • %!w(<nil>) is a Go fmt artifact of wrapping a nil error — i.e. the tag
    listing returned no usable candidates and no underlying error, so the
    constraint matched nothing.
  • The available registry tags (via crane ls registry.suse.com/rancher/charts/rancher-ai-agent)
    are all of the form 10x.y.z_upA.B.C — there is no plain-semver tag and no
    latest tag.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Fields

    No fields configured for Bug.

    Projects

    Status
    📋 Backlog

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions