Skip to content

Commit 2c5bfa4

Browse files
harcheclaude
andcommitted
pkg/readiness: Return error from CompareVersions for invalid semver
Returning 0 on parse errors conflated invalid input with equal versions, causing false-positive blockers in api_deprecations and network checks when version strings were unparseable. Now callers can distinguish parse failures from genuine equality. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d94dfe3 commit 2c5bfa4

4 files changed

Lines changed: 25 additions & 15 deletions

File tree

pkg/readiness/api_deprecations.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ func (c *APIDeprecationsCheck) Run(ctx context.Context, dc dynamic.Interface, cu
3838

3939
// Check RemovedInRelease annotation
4040
removedIn := NestedString(arc.Object, "status", "removedInRelease")
41-
if removedIn != "" && CompareVersions(removedIn, target) <= 0 {
41+
cmp, err := CompareVersions(removedIn, target)
42+
if removedIn != "" && err == nil && cmp <= 0 {
4243
requestCount := NestedInt64(arc.Object, "status", "requestCount")
4344
if requestCount > 0 {
4445
blockers = append(blockers, map[string]any{

pkg/readiness/client.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package readiness
22

33
import (
44
"context"
5+
"fmt"
56
"strings"
67

78
semver "github.com/blang/semver/v4"
@@ -151,16 +152,16 @@ const (
151152
)
152153

153154
// CompareVersions compares two semver strings. Returns -1, 0, or 1.
154-
func CompareVersions(a, b string) int {
155+
func CompareVersions(a, b string) (int, error) {
155156
va, err := semver.ParseTolerant(a)
156157
if err != nil {
157-
return 0
158+
return 0, fmt.Errorf("invalid version %q: %w", a, err)
158159
}
159160
vb, err := semver.ParseTolerant(b)
160161
if err != nil {
161-
return 0
162+
return 0, fmt.Errorf("invalid version %q: %w", b, err)
162163
}
163-
return va.Compare(vb)
164+
return va.Compare(vb), nil
164165
}
165166

166167
// FormatLabelSelector converts a map of labels to a label selector string.

pkg/readiness/client_test.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,27 @@ func TestGetConditions_NoConditions(t *testing.T) {
6767

6868
func TestCompareVersions(t *testing.T) {
6969
tests := []struct {
70-
a, b string
71-
expected int
70+
a, b string
71+
expected int
72+
expectErr bool
7273
}{
73-
{"4.21.5", "4.21.8", -1},
74-
{"4.21.8", "4.21.5", 1},
75-
{"4.21.5", "4.21.5", 0},
76-
{"4.22.0", "4.21.5", 1},
77-
{"bad", "4.21.5", 0},
78-
{"4.21.5", "bad", 0},
74+
{"4.21.5", "4.21.8", -1, false},
75+
{"4.21.8", "4.21.5", 1, false},
76+
{"4.21.5", "4.21.5", 0, false},
77+
{"4.22.0", "4.21.5", 1, false},
78+
{"bad", "4.21.5", 0, true},
79+
{"4.21.5", "bad", 0, true},
7980
}
8081

8182
for _, tt := range tests {
8283
t.Run(tt.a+"_vs_"+tt.b, func(t *testing.T) {
83-
got := CompareVersions(tt.a, tt.b)
84+
got, err := CompareVersions(tt.a, tt.b)
85+
if tt.expectErr && err == nil {
86+
t.Errorf("CompareVersions(%q, %q) expected error, got nil", tt.a, tt.b)
87+
}
88+
if !tt.expectErr && err != nil {
89+
t.Errorf("CompareVersions(%q, %q) unexpected error: %v", tt.a, tt.b, err)
90+
}
8491
if got != tt.expected {
8592
t.Errorf("CompareVersions(%q, %q) = %d, want %d", tt.a, tt.b, got, tt.expected)
8693
}

pkg/readiness/network.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ func (c *NetworkCheck) Run(ctx context.Context, dc dynamic.Interface, current, t
2727

2828
// SDN deprecation warning
2929
if networkType == "OpenShiftSDN" {
30-
if target != "" && CompareVersions(target, "4.17.0") >= 0 {
30+
cmp, err := CompareVersions(target, "4.17.0")
31+
if target != "" && err == nil && cmp >= 0 {
3132
result["sdn_warning"] = "OpenShiftSDN blocks upgrades to 4.17+; migrate to OVN-Kubernetes first."
3233
} else {
3334
result["sdn_warning"] = "OpenShiftSDN detected. Migration to OVN-Kubernetes is required for future upgrades to 4.17+."

0 commit comments

Comments
 (0)