applicationset: coerce ClusterDecisionResource values to string in DuckType generator

applicationset/generators/duck_type.go:167 did:

    for key, value := range clusterDecision.(map[string]any) {
        params[key] = value.(string)
    }

The unstructured decision map is fed in verbatim from the duck-type
resource's status (OCM PlacementDecision, etc). Those statuses can
contain non-string fields, and recent OCM releases added
`score` as int64 under each `decisions` entry. The blanket
`value.(string)` panics the whole ApplicationSet controller with

    interface conversion: interface {} is int64, not string

on the first reconcile after the upstream schema change, which
breaks every ApplicationSet backed by a ClusterDecisionResource
generator (#27264).

Keep params map typed as string-to-any as before, but stop asserting
the value type. Use the string value directly when present, treat
nil as empty string (matching the prior happy path for missing
fields), and fall back to fmt.Sprintf for anything else. The
generator still emits string-valued params for downstream templating;
only the behaviour on non-string values changes from panic to a
best-effort string rendering.

Fixes #27264

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>
This commit is contained in:
SAY-5 2026-04-20 00:41:10 -07:00
parent 611fcb012c
commit ce004939ee

View file

@ -164,7 +164,25 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A
}
for key, value := range clusterDecision.(map[string]any) {
params[key] = value.(string)
// ClusterDecisionResource status fields can contain non-string
// types (e.g. OCM PlacementDecision's `score` is an int64 after
// the recent schema change, see #27264). The previous blanket
// `value.(string)` assertion panicked the controller with
// `interface conversion: interface {} is int64, not string`
// whenever any generator consumed such a status. Coerce to
// string so the generator keeps emitting string-valued params
// regardless of the decision value's concrete type; preserve
// nil as empty string to match the prior happy-path behaviour
// when a field was missing.
if value == nil {
params[key] = ""
continue
}
if s, ok := value.(string); ok {
params[key] = s
continue
}
params[key] = fmt.Sprintf("%v", value)
}
for key, value := range appSetGenerator.ClusterDecisionResource.Values {