Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ require (
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103
github.com/oapi-codegen/runtime v1.4.2
github.com/onsi/gomega v1.42.0
github.com/openshift-hyperfleet/hyperfleet-api-spec v1.0.21
github.com/openshift-hyperfleet/hyperfleet-api-spec v1.0.23

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect Sentinel's pinned spec and Kind handling assumptions.
gh api repos/openshift-hyperfleet/hyperfleet-sentinel/contents/go.mod \
  --jq '.content' | base64 -d | rg -n 'hyperfleet-api-spec'
gh search prs --repo openshift-hyperfleet/hyperfleet-sentinel --state open 'api-spec' --json title,number

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 301


Coordinate the spec bump with Sentinel. hyperfleet-api-spec moved to v1.0.23, but hyperfleet-sentinel still pins v1.0.12 and assumes a compatible API spec. That leaves a contract-drift risk; update Sentinel in lockstep or block this bump until it does.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@go.mod` at line 23, The dependency bump to hyperfleet-api-spec v1.0.23
creates a contract-drift risk with hyperfleet-sentinel, which still expects
v1.0.12. Update the Sentinel-side spec pin and any related compatibility checks
in lockstep with this change, or revert/block the go.mod bump until Sentinel is
updated to the same API spec version. Focus on the dependency entry in go.mod
and the corresponding Sentinel version reference.

Sources: Path instructions, Linked repositories

github.com/prometheus/client_golang v1.16.0
github.com/prometheus/client_model v0.3.0
github.com/spf13/cobra v1.10.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJw
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/openshift-hyperfleet/hyperfleet-api-spec v1.0.21 h1:+Vlr1GOldX+pWJdVVlHxiCuVRQjTlr1Q3ez+ON+To/Q=
github.com/openshift-hyperfleet/hyperfleet-api-spec v1.0.21/go.mod h1:KITzIAd8HcMpH5lXdHFjgk45dvL6XLpP3wwz8iK+KCI=
github.com/openshift-hyperfleet/hyperfleet-api-spec v1.0.23 h1:HyOWpJfEonjpLFnMmmhiqaAD3EJSVIvAuaA7y5fZ4kE=
github.com/openshift-hyperfleet/hyperfleet-api-spec v1.0.23/go.mod h1:KITzIAd8HcMpH5lXdHFjgk45dvL6XLpP3wwz8iK+KCI=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
Expand Down
10 changes: 4 additions & 6 deletions pkg/api/presenters/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
openapi_types "github.com/oapi-codegen/runtime/types"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/api"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/util"
)

const clusterKind = "Cluster"
Expand All @@ -30,10 +29,9 @@ func ConvertCluster(req *openapi.ClusterCreateRequest) (*api.Cluster, error) {
return nil, fmt.Errorf("failed to marshal cluster labels: %w", err)
}

// Get Kind value, use default if not provided
kind := clusterKind
if req.Kind != nil {
kind = *req.Kind
kind := req.Kind
if kind == "" {
kind = clusterKind
}

return &api.Cluster{
Expand Down Expand Up @@ -114,7 +112,7 @@ func PresentCluster(cluster *api.Cluster) (openapi.Cluster, error) {
Generation: cluster.Generation,
Href: &href,
Id: &cluster.ID,
Kind: util.PtrString(cluster.Kind),
Kind: cluster.Kind,
Labels: &labels,
Name: cluster.Name,
Spec: spec,
Expand Down
11 changes: 5 additions & 6 deletions pkg/api/presenters/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
. "github.com/onsi/gomega"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/api"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/util"
)

const (
Expand All @@ -23,7 +22,7 @@ func createTestClusterRequest() *openapi.ClusterCreateRequest {

return &openapi.ClusterCreateRequest{
Labels: &labels,
Kind: util.PtrString("Cluster"),
Kind: "Cluster",
Name: "test-cluster",
Spec: map[string]interface{}{
"region": "us-central1",
Expand Down Expand Up @@ -76,7 +75,7 @@ func TestConvertCluster_WithLabels(t *testing.T) {

req := &openapi.ClusterCreateRequest{
Labels: &labels,
Kind: util.PtrString("Cluster"),
Kind: "Cluster",
Name: "labeled-cluster",
Spec: map[string]interface{}{"test": "spec"},
}
Expand All @@ -97,7 +96,7 @@ func TestConvertCluster_WithoutLabels(t *testing.T) {

req := &openapi.ClusterCreateRequest{
Labels: nil, // Nil labels
Kind: util.PtrString("Cluster"),
Kind: "Cluster",
Name: "unlabeled-cluster",
Spec: map[string]interface{}{"test": "spec"},
}
Expand Down Expand Up @@ -128,7 +127,7 @@ func TestConvertCluster_SpecMarshaling(t *testing.T) {
}

req := &openapi.ClusterCreateRequest{
Kind: util.PtrString("Cluster"),
Kind: "Cluster",
Name: "complex-cluster",
Spec: complexSpec,
}
Expand Down Expand Up @@ -203,7 +202,7 @@ func TestPresentCluster_Complete(t *testing.T) {

// Verify basic fields
Expect(*result.Id).To(Equal("cluster-abc123"))
Expect(*result.Kind).To(Equal("Cluster"))
Expect(result.Kind).To(Equal("Cluster"))
Expect(*result.Href).To(Equal("/api/hyperfleet/v1/clusters/cluster-abc123"))
Expect(result.Name).To(Equal("presented-cluster"))
Expect(result.Generation).To(Equal(int32(10)))
Expand Down
11 changes: 5 additions & 6 deletions pkg/api/presenters/node_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ func ConvertNodePool(req *openapi.NodePoolCreateRequest, ownerID string) (*api.N
return nil, fmt.Errorf("failed to marshal nodepool labels: %w", err)
}

kind := nodePoolKind
if req.Kind != nil {
kind = *req.Kind
kind := req.Kind
if kind == "" {
kind = nodePoolKind
}

return &api.NodePool{
Expand Down Expand Up @@ -96,7 +96,6 @@ func PresentNodePool(nodePool *api.NodePool) (openapi.NodePool, error) {
}
}

kind := nodePool.Kind
result := openapi.NodePool{
CreatedBy: toEmail(nodePool.CreatedBy),
CreatedTime: nodePool.CreatedTime,
Expand All @@ -105,12 +104,12 @@ func PresentNodePool(nodePool *api.NodePool) (openapi.NodePool, error) {
Generation: nodePool.Generation,
Href: &href,
Id: &nodePool.ID,
Kind: &kind,
Kind: nodePool.Kind,
Labels: &labels,
Name: nodePool.Name,
OwnerReferences: openapi.ObjectReference{
Id: &nodePool.OwnerID,
Kind: &nodePool.OwnerKind,
Kind: nodePool.OwnerKind,
Href: &ownerHref,
},
Spec: spec,
Expand Down
21 changes: 9 additions & 12 deletions pkg/api/presenters/node_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ import (
// Helper function to create test NodePoolCreateRequest
func createTestNodePoolRequest() *openapi.NodePoolCreateRequest {
labels := map[string]string{"env": "test"}
kind := "NodePool"

return &openapi.NodePoolCreateRequest{
Kind: &kind,
Kind: "NodePool",
Name: "test-nodepool",
Spec: map[string]interface{}{
"replicas": 3,
Expand Down Expand Up @@ -64,9 +62,8 @@ func TestConvertNodePool_Complete(t *testing.T) {
func TestConvertNodePool_WithKind(t *testing.T) {
RegisterTestingT(t)

customKind := "CustomNodePool"
req := &openapi.NodePoolCreateRequest{
Kind: &customKind,
Kind: "CustomNodePool",
Name: "custom-nodepool",
Spec: map[string]interface{}{"test": "spec"},
Labels: nil,
Expand All @@ -83,7 +80,7 @@ func TestConvertNodePool_WithoutKind(t *testing.T) {
RegisterTestingT(t)

req := &openapi.NodePoolCreateRequest{
Kind: nil, // Nil Kind
Kind: "", // empty Kind falls back to default in ConvertNodePool
Name: "default-kind-nodepool",
Spec: map[string]interface{}{"test": "spec"},
Labels: nil,
Expand Down Expand Up @@ -192,7 +189,7 @@ func TestPresentNodePool_Complete(t *testing.T) {

// Verify basic fields
Expect(*result.Id).To(Equal("nodepool-xyz"))
Expect(*result.Kind).To(Equal("NodePool"))
Expect(result.Kind).To(Equal("NodePool"))
Expect(*result.Href).To(Equal("/api/hyperfleet/v1/clusters/cluster-abc/nodepools/nodepool-xyz"))
Expect(result.Name).To(Equal("presented-nodepool"))
Expect(result.CreatedBy).To(Equal(openapi_types.Email("user123@example.com")))
Expand All @@ -206,7 +203,7 @@ func TestPresentNodePool_Complete(t *testing.T) {

// Verify OwnerReferences
Expect(*result.OwnerReferences.Id).To(Equal("cluster-abc"))
Expect(*result.OwnerReferences.Kind).To(Equal("Cluster"))
Expect(result.OwnerReferences.Kind).To(Equal("Cluster"))
Expect(*result.OwnerReferences.Href).To(Equal("/api/hyperfleet/v1/clusters/cluster-abc"))

// Verify Status
Expand Down Expand Up @@ -281,8 +278,8 @@ func TestPresentNodePool_OwnerReferences(t *testing.T) {

Expect(result.OwnerReferences.Id).ToNot(BeNil())
Expect(*result.OwnerReferences.Id).To(Equal("cluster-ref-123"))
Expect(result.OwnerReferences.Kind).ToNot(BeNil())
Expect(*result.OwnerReferences.Kind).To(Equal("Cluster"))
Expect(result.OwnerReferences.Kind).ToNot(BeEmpty())
Expect(result.OwnerReferences.Kind).To(Equal("Cluster"))
Expect(result.OwnerReferences.Href).ToNot(BeNil())
}

Expand Down Expand Up @@ -375,7 +372,7 @@ func TestConvertAndPresentNodePool_RoundTrip(t *testing.T) {

// Verify data integrity
Expect(*result.Id).To(Equal("nodepool-roundtrip-123"))
Expect(*result.Kind).To(Equal(*originalReq.Kind))
Expect(result.Kind).To(Equal(originalReq.Kind))
Expect(result.Name).To(Equal(originalReq.Name))

// Verify Spec preserved
Expand All @@ -387,7 +384,7 @@ func TestConvertAndPresentNodePool_RoundTrip(t *testing.T) {

// Verify OwnerReferences set
Expect(*result.OwnerReferences.Id).To(Equal(ownerID))
Expect(*result.OwnerReferences.Kind).To(Equal("Cluster"))
Expect(result.OwnerReferences.Kind).To(Equal("Cluster"))

// Status initialization is handled by the service layer on create, not presenters.
Expect(len(result.Status.Conditions)).To(Equal(0))
Expand Down
10 changes: 5 additions & 5 deletions pkg/api/presenters/presenter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func createTestClusterList() openapi.ClusterList {
Items: []openapi.Cluster{
{
Id: &id1,
Kind: &kind,
Kind: kind,
Name: "test-cluster",
Generation: 1,
Labels: &labels1,
Expand All @@ -76,7 +76,7 @@ func createTestClusterList() openapi.ClusterList {
},
{
Id: &id2,
Kind: &kind,
Kind: kind,
Name: "development-cluster",
Generation: 2,
Labels: &labels2,
Expand Down Expand Up @@ -486,7 +486,7 @@ func createTestCluster() openapi.Cluster {

return openapi.Cluster{
Id: &id,
Kind: &kind,
Kind: kind,
Name: "test-cluster",
Generation: 1,
Labels: &labels,
Expand Down Expand Up @@ -733,11 +733,11 @@ func createTestNodePool() openapi.NodePool {

return openapi.NodePool{
Id: &id,
Kind: &kind,
Kind: kind,
Name: "worker-pool",
OwnerReferences: openapi.ObjectReference{
Id: &ownerID,
Kind: &ownerKind,
Kind: ownerKind,
Href: &ownerHref,
},
Spec: openapi.NodePoolSpec{"replicas": 3, "instanceType": "m5.large"},
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/presenters/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func PresentResource(r *api.Resource) openapi.Resource {
}{
ObjectReference: openapi.ObjectReference{
Id: r.OwnerID,
Kind: r.OwnerKind,
Kind: util.NilToEmptyString(r.OwnerKind),
Href: r.OwnerHref,
},
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/presenters/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func TestPresentResource_WithOwner(t *testing.T) {
resp := PresentResource(resource)
Expect(resp.OwnerReferences).NotTo(BeNil())
Expect(*resp.OwnerReferences.Id).To(Equal("parent-id"))
Expect(*resp.OwnerReferences.Kind).To(Equal("Channel"))
Expect(resp.OwnerReferences.Kind).To(Equal("Channel"))
}

func TestPresentResource_EmptySpec(t *testing.T) {
Expand Down
12 changes: 6 additions & 6 deletions pkg/handlers/cluster_nodepools_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ func TestClusterNodePoolsHandler_Get(t *testing.T) {
err := json.Unmarshal(rr.Body.Bytes(), &response)
Expect(err).NotTo(HaveOccurred())
Expect(*response.Id).To(Equal(nodePoolID))
Expect(response.Kind).NotTo(BeNil())
Expect(*response.Kind).To(Equal("NodePool"))
Expect(response.Kind).NotTo(BeEmpty())
Expect(response.Kind).To(Equal("NodePool"))
}
})
}
Expand Down Expand Up @@ -425,8 +425,8 @@ func TestClusterNodePoolsHandler_Create(t *testing.T) {
err := json.Unmarshal(rr.Body.Bytes(), &response)
Expect(err).NotTo(HaveOccurred())
Expect(*response.Id).To(Equal(nodePoolID))
Expect(response.Kind).NotTo(BeNil())
Expect(*response.Kind).To(Equal("NodePool"))
Expect(response.Kind).NotTo(BeEmpty())
Expect(response.Kind).To(Equal("NodePool"))
}

if tt.expectedStatusCode == http.StatusConflict {
Expand Down Expand Up @@ -581,8 +581,8 @@ func TestClusterNodePoolsHandler_Patch(t *testing.T) {
err := json.Unmarshal(rr.Body.Bytes(), &response)
Expect(err).NotTo(HaveOccurred())
Expect(*response.Id).To(Equal(nodePoolID))
Expect(response.Kind).NotTo(BeNil())
Expect(*response.Kind).To(Equal("NodePool"))
Expect(response.Kind).NotTo(BeEmpty())
Expect(response.Kind).To(Equal("NodePool"))
}

if tt.expectedStatusCode == http.StatusConflict {
Expand Down
9 changes: 4 additions & 5 deletions pkg/handlers/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
. "github.com/onsi/gomega"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/api"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/util"
)

func TestValidateName_Valid(t *testing.T) {
Expand Down Expand Up @@ -102,7 +101,7 @@ func TestValidateKind_Valid(t *testing.T) {
RegisterTestingT(t)

req := openapi.ClusterCreateRequest{
Kind: util.PtrString("Cluster"),
Kind: "Cluster",
}
validator := validateKind(&req, "Kind", "kind", "Cluster")
err := validator()
Expand All @@ -121,7 +120,7 @@ func TestValidateKind_Invalid(t *testing.T) {

for _, kind := range invalidKinds {
req := openapi.ClusterCreateRequest{
Kind: &kind,
Kind: kind,
}
validator := validateKind(&req, "Kind", "kind", "Cluster")
err := validator()
Expand All @@ -133,7 +132,7 @@ func TestValidateKind_Empty(t *testing.T) {
RegisterTestingT(t)

req := openapi.ClusterCreateRequest{
Kind: util.PtrString(""),
Kind: "",
}
validator := validateKind(&req, "Kind", "kind", "Cluster")
err := validator()
Expand All @@ -145,7 +144,7 @@ func TestValidateKind_WrongKind(t *testing.T) {
RegisterTestingT(t)

req := openapi.ClusterCreateRequest{
Kind: util.PtrString("WrongKind"),
Kind: "WrongKind",
}
validator := validateKind(&req, "Kind", "kind", "Cluster")
err := validator()
Expand Down
Loading