Skip to content

Conversation

@rh-amarin
Copy link
Contributor

@rh-amarin rh-amarin commented Jan 12, 2026

HYPERFLEET-500 - feat: introduce oapi-codegen

This PR introduces oapi-codegen to generate the go types from openapi.yaml schema instead of the Java openapi-generator tool.

This PR depends on the approval of: openshift-hyperfleet/hyperfleet-api-spec#21
The generated openapi.yaml from that PR is already introduced in this PR, with v1.0.2

The PR is organized in 3 commits:

Summary by CodeRabbit

  • New Features

    • Switch to direct OpenAPI code generation; API version bumped to v1.0.2.
  • Improvements

    • Responses now include richer metadata (created/updated by, timestamps, labels, hrefs) and clearer pagination.
    • Client patterns and test helpers unified; safer pointer-based helpers and consistent enum values.
  • Breaking Changes

    • Several request/response shapes and field types changed (value → pointer and renamed enum/constants); update clients/integrations.

✏️ Tip: You can customize this high-level summary in your review settings.

@openshift-ci
Copy link

openshift-ci bot commented Jan 12, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@coderabbitai
Copy link

coderabbitai bot commented Jan 12, 2026

Walkthrough

Replaces Docker-based OpenAPI generation with direct oapi-codegen invocation and adds oapi-codegen as a managed bingo tool (.bingo/* changes). Removes Dockerfile.openapi, its dockerignore, and openapitools.json; adds openapi/oapi-codegen.yaml and .bingo module for oapi-codegen. Makefile updated to call $(OAPI_CODEGEN) to generate pkg/api/openapi. Updates go.mod, regenerates OpenAPI types (pointerized Kind, renamed enums, expanded explicit schemas), adapts presenters/handlers, removes embedded spec accessor, and updates tests and Dockerfile to the new generation/runtime flow.

Sequence Diagram(s)

sequenceDiagram
  actor Developer
  participant Makefile
  participant Bingo as .bingo target
  participant OAPI as oapi-codegen
  participant Spec as openapi/openapi.yaml
  participant Generated as pkg/api/openapi
  participant GoBuild as go build / test

  Developer->>Makefile: make generate
  Makefile->>Bingo: ensure $(OAPI_CODEGEN) target
  Bingo->>OAPI: build/install oapi-codegen binary
  Makefile->>OAPI: run oapi-codegen with openapi/oapi-codegen.yaml + Spec
  OAPI->>Spec: read OpenAPI spec
  OAPI-->>Generated: write generated client/models
  Makefile->>GoBuild: run go build / go test using Generated
  GoBuild-->>Developer: build/test results
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

  • openshift-hyperfleet/hyperfleet-api#11 — Related to OpenAPI generation/embedding workflow and removal of embedding artifacts.
  • openshift-hyperfleet/hyperfleet-api#4 — Overlaps on adapter status semantics and OpenAPI-generated types changes.
  • openshift-hyperfleet/hyperfleet-api#14 — Related to Makefile/Dockerfile/OpenAPI generation and image build flow changes.

Suggested labels

lgtm, approved

Suggested reviewers

  • vkareh
  • aredenba-rh
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly identifies the main change: introducing oapi-codegen as a replacement for the Java-based OpenAPI Generator tool.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@rh-amarin
Copy link
Contributor Author

⏺ OpenAPI Code Generation Comparison

Overview

Aspect main/ (OpenAPI Generator) ogen/ oapi-codegen/
Files Generated 34 20 2
Lines of Code ~11,274 ~20,261 ~2,530
Runtime Deps None (stdlib only) ogen-go/ogen, go-faster/jx, OpenTelemetry oapi-codegen/runtime

  1. main/ - OpenAPI Generator (Java-based)

Type Style:

  type Cluster struct {
      CreatedTime time.Time `json:"created_time"`
      Name string `json:"name" validate:"regexp=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"`
      Spec map[string]interface{} `json:"spec"`
      Labels *map[string]string `json:"labels,omitempty"`  // pointer for optional
      Id *string `json:"id,omitempty"`
  }

Strengths:

  • ✅ No runtime dependencies - uses only stdlib (encoding/json)
  • ✅ Null-safety pattern with NullableCluster wrapper types
  • ✅ Constructor functions (NewCluster, NewClusterWithDefaults)
  • ✅ Validation in UnmarshalJSON - checks required properties
  • ✅ GetXxxOk() methods return tuple (value, bool) for presence checking
  • ✅ HasXxx() methods for optional field presence
  • ✅ ToMap() method for generic map conversion
  • ✅ Mature tooling - widely used, extensive documentation

Weaknesses:

  • ❌ Verbose - each model in separate file with many boilerplate methods
  • ❌ Pointer-based optionals (*string) - less idiomatic for Go
  • ❌ No built-in validation beyond required field checking
  • ❌ Flattens allOf schemas - loses composition structure
  • ❌ Java dependency - requires JVM to run generator

  1. ogen/ (Go-native generator)

Type Style:

  type Cluster struct {
      ID          OptString     `json:"id"`           // Optional type wrapper
      Kind        string        `json:"kind"`
      Labels      OptClusterLabels `json:"labels"`
      Name        string        `json:"name"`
      Spec        ClusterSpec   `json:"spec"`
      Generation  int32         `json:"generation"`
      Status      ClusterStatus `json:"status"`
  }

  type OptString struct {
      Value string
      Set   bool
  }

Strengths:

  • ✅ Opt[T] types for optionals - explicit presence tracking, no nil pointer issues
  • ✅ Built-in validation (oas_validators_gen.go) with structured errors
  • ✅ OpenTelemetry integration - tracing/metrics out of the box
  • ✅ Enum validation with MarshalText/UnmarshalText
  • ✅ High-performance JSON using go-faster/jx (no reflection)
  • ✅ Generated getters/setters for all fields
  • ✅ Pure Go toolchain - no JVM needed
  • ✅ Server + Client generation in same package
  • ✅ Type-safe response types (GetClusterByIdRes interface)

Weaknesses:

  • ❌ Largest output (~20k lines) - more code to maintain
  • ❌ Heavy runtime dependencies - ogen-go/ogen, go-faster/*, OTel
  • ❌ Learning curve - Opt[T] pattern different from idiomatic Go
  • ❌ Less flexibility - opinionated about patterns
  • ❌ Flattens allOf - doesn't preserve schema composition

  1. oapi-codegen/ (Go-native generator)

Type Style:

  type Cluster struct {
      // Preserves allOf composition!
      ClusterBase `yaml:",inline"`

      CreatedBy   openapi_types.Email `json:"created_by"`  // Typed email
      CreatedTime time.Time           `json:"created_time"`
      Generation  int32               `json:"generation"`
      Status      ClusterStatus       `json:"status"`
  }

  type ClusterBase struct {
      APIResource `yaml:",inline"`
      Kind string `json:"kind"`
      Name string `json:"name"`
      Spec ClusterSpec `json:"spec"`
  }

Strengths:

  • ✅ Most compact (~2.5k lines, 2 files) - minimal footprint
  • ✅ Preserves allOf composition - embedded structs match schema
  • ✅ Semantic types - openapi_types.Email instead of string
  • ✅ Lightweight runtime - just oapi-codegen/runtime
  • ✅ Pure Go toolchain - no JVM
  • ✅ ClientWithResponses - parsed response bodies with type safety
  • ✅ RequestEditorFn pattern - clean auth/middleware injection
  • ✅ Go-idiomatic - feels like handwritten Go code

Weaknesses:

  • ❌ No built-in validation - must add manually or use external
  • ❌ Pointer-based optionals (*string) - though less pervasive
  • ❌ Fewer accessor methods - direct field access preferred
  • ❌ Less observability - no OTel integration
  • ❌ Returns *http.Response - need ClientWithResponses for parsed bodies

Comparison Summary

Feature main/ ogen/ oapi-codegen/
Code Size Medium Large Small ✅
Runtime Deps None ✅ Heavy Light
Optional Handling Pointers Opt[T] ✅ Pointers
Validation Basic Full ✅ None
Schema Composition Flattened Flattened Preserved ✅
Observability None OTel ✅ None
Go Idiomaticity Medium Medium High ✅
Type Safety Good Excellent ✅ Good
Maintenance Java needed Go Go

Recommendation

For your use case (types + client only):

  • oapi-codegen is the best fit if you want minimal, Go-idiomatic code that preserves your schema composition (allOf inheritance). The embedded struct pattern (ClusterBase → Cluster) is clean and matches your OpenAPI design.
  • ogen is better if you need built-in validation, observability (OTel), or are building a complete server+client solution. The Opt[T] pattern is cleaner than nil pointers.
  • OpenAPI Generator (main/) is worth keeping if you need maximum compatibility or zero runtime dependencies, though the Java requirement and verbose output are downsides.

JobName *string `json:"job_name,omitempty"`
JobNamespace *string `json:"job_namespace,omitempty"`
StartedTime *time.Time `json:"started_time,omitempty"`
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it better to define AdapterMetadata under pkg/api/adapter_status_types.go instead of here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I defined a struct in api as you suggest
But, the current openapi metadata struct still has to be defined since is a loose type in the openapi contract
We may want to revisit the definition of metadata in the api-spec project
But that will be better in a separate ticket

@rh-amarin rh-amarin marked this pull request as ready for review January 13, 2026 10:42
@openshift-ci openshift-ci bot requested review from aredenba-rh and vkareh January 13, 2026 10:42
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
openapi/openapi.yaml (1)

78-105: SearchParams on single-resource endpoint may be unintended.

Line 83 adds SearchParams to getClusterById, but search/filter parameters are typically only meaningful for list endpoints that return multiple items. For a single-resource GET by ID, the search parameter would have no effect.

Consider removing SearchParams from this endpoint unless there's a specific use case (e.g., field projection).

test/helper.go (1)

448-456: OpenapiError method exists but is not being used anywhere in the codebase.

The method signature change to accept []byte is correct, but the verification reveals no test callsites actually invoke helper.OpenapiError(). Integration tests directly unmarshal response bodies using json.Unmarshal(resp.Body(), &errorResponse) instead of calling this helper method. Either this is dead code, or the refactoring to use this method in tests is incomplete and needs to be completed.

pkg/api/presenters/cluster_test.go (1)

393-398: Verify the pointer comparison for Kind field.

Line 395 compares result.Kind (a *string) with originalReq.Kind (also a *string). Gomega's Equal matcher will compare the pointer values, not the underlying strings. Since these are different pointers (one from the original request, one newly allocated in PresentCluster), this assertion may fail unexpectedly.

🐛 Proposed fix to dereference the pointer
 	// Verify data integrity
 	Expect(*result.Id).To(Equal("cluster-roundtrip-123"))
-	Expect(result.Kind).To(Equal(originalReq.Kind))
+	Expect(*result.Kind).To(Equal(*originalReq.Kind))
 	Expect(result.Name).To(Equal(originalReq.Name))
test/integration/clusters_test.go (1)

650-660: Missing nil check on listResp.JSON200 before iterating over .Items.

Line 652 assigns list from listResp.JSON200, but there's no nil check before accessing list.Items on line 656. This is inconsistent with other tests in this file that perform nil checks.

🐛 Proposed fix
 	listResp, err := client.GetClustersWithResponse(ctx, params, test.WithAuthToken(ctx))
 	Expect(err).NotTo(HaveOccurred(), "Failed to list clusters with orderBy desc")
 	list := listResp.JSON200
+	Expect(list).NotTo(BeNil())

 	// Find our test clusters in the response
🤖 Fix all issues with AI agents
In @test/integration/clusters_test.go:
- Around line 299-303: The test accesses getResp.JSON200.Spec without ensuring
JSON200 is non-nil; add a nil-check (e.g.,
Expect(getResp.JSON200).NotTo(BeNil()) or if getResp.JSON200 == nil { Fail(...)
}) immediately after calling GetClusterByIdWithResponse and before accessing
Spec so the test fails with a clear message instead of panicking; keep the
existing assertions (Err check and using *resp.JSON201.Id) and then assert
len(getResp.JSON200.Spec) once the nil-check passes.
- Around line 232-235: The test accesses getResp.JSON200.Name without ensuring
JSON200 is non-nil; add an explicit nil assertion before accessing Name by
checking Expect(getResp.JSON200).NotTo(BeNil()) (or an equivalent nil check)
immediately after the err check from client.GetClusterByIdWithResponse, then
assert Expect(getResp.JSON200.Name).To(Equal("duplicate-name-test")); this
ensures the test fails clearly if the response body is absent instead of
panicking.
- Around line 196-204: The test accesses resp.JSON200.Items without checking
that resp.JSON200 is non-nil after calling GetClustersWithResponse; add a
nil-check on resp.JSON200 (and fail the test or use Expect to assert
resp.StatusCode() == 200 or resp.JSON200 != nil) before referencing .Items so
you avoid a nil pointer dereference — update the GetClustersWithResponse
response handling in the test to assert/handle non-200 responses (e.g.,
Expect(resp.JSON200).NotTo(BeNil()) or Expect(resp.StatusCode()).To(Equal(200))
) prior to using resp.JSON200.Items.
🧹 Nitpick comments (7)
pkg/handlers/validation_test.go (2)

118-121: Consider using openapi.PtrString for consistency.

Other tests in this file use openapi.PtrString() (lines 101, 132, 144), but this loop uses &kind. While functionally correct in Go 1.22+, using the helper would maintain consistency.

♻️ Suggested change
 	for _, kind := range invalidKinds {
 		req := openapi.ClusterCreateRequest{
-			Kind: &kind,
+			Kind: openapi.PtrString(kind),
 		}

128-138: Consider adding a test case for nil Kind.

This test covers empty string (""), but there's no test for when Kind is nil (pointer not set). Depending on the validator implementation, nil vs empty string may produce different behavior.

📝 Suggested test case
func TestValidateKind_Nil(t *testing.T) {
	RegisterTestingT(t)

	req := openapi.ClusterCreateRequest{
		Kind: nil,
	}
	validator := validateKind(&req, "Kind", "kind", "Cluster")
	err := validator()
	Expect(err).ToNot(BeNil())
	Expect(err.Reason).To(ContainSubstring("required"))
}
pkg/handlers/openapi.go (1)

63-65: Consider migrating to structured slog-based logger.

NewOCMLogger(ctx) is deprecated. When convenient, consider switching to logger.With(ctx, ...) for structured, context-aware logging. This applies to line 75 as well. Based on learnings, this is a known deprecation but can be addressed in a follow-up.

Makefile (1)

226-243: Generate target successfully migrates to oapi-codegen.

The refactored target correctly:

  1. Depends on the bingo-managed $(OAPI_CODEGEN) tool
  2. Cleans and recreates the output directory
  3. Generates types via config file
  4. Creates helper pointer functions

The inline helpers.go generation is functional. As an optional improvement, consider extracting the helpers to a committed template file to improve readability and make the helpers easier to extend.

♻️ Optional: Extract helpers to a template file

Create openapi/helpers.go.tmpl:

package openapi

// Ptr returns a pointer to the given value.
func Ptr[T any](v T) *T { return &v }

// PtrString returns a pointer to the given string.
func PtrString(v string) *string { return &v }

// PtrInt32 returns a pointer to the given int32.
func PtrInt32(v int32) *int32 { return &v }

Then simplify the Makefile:

 generate: $(OAPI_CODEGEN)
 	rm -rf pkg/api/openapi
 	mkdir -p pkg/api/openapi
 	$(OAPI_CODEGEN) --config openapi/oapi-codegen.yaml openapi/openapi.yaml
-	@printf '%s\n' \
-		'package openapi' \
-		'' \
-		'// Ptr returns a pointer to the given value.' \
-		'func Ptr[T any](v T) *T { return &v }' \
-		'' \
-		'// PtrString returns a pointer to the given string.' \
-		'func PtrString(v string) *string { return &v }' \
-		'' \
-		'// PtrInt32 returns a pointer to the given int32.' \
-		'func PtrInt32(v int32) *int32 { return &v }' \
-		> pkg/api/openapi/helpers.go
+	cp openapi/helpers.go.tmpl pkg/api/openapi/helpers.go
pkg/handlers/node_pool.go (1)

39-41: Consider disabling standalone nodepool creation or requiring owner context.

The comment acknowledges that standalone nodepools (without an owner cluster) may not be a supported use case. Passing an empty ownerID could lead to orphaned resources or break referential integrity constraints.

The createdBy update to "[email protected]" is consistent with other handlers.

If standalone nodepool creation isn't supported, consider returning errors.NotImplemented("standalone nodepool creation") or requiring the owner cluster ID in the request body.

pkg/handlers/cluster_nodepools_test.go (1)

133-142: Consider adding missing fields for consistency.

The "different cluster" error case returns a minimal NodePool without Spec, Labels, StatusConditions, CreatedBy, or UpdatedBy. While this works because the presenter isn't invoked on the error path, adding these fields would maintain consistency with the success case mock and prevent issues if the test logic changes.

♻️ Proposed consistency fix
 				mockNodePoolSvc.EXPECT().Get(gomock.Any(), nodePoolID).Return(&api.NodePool{
 					Meta: api.Meta{
 						ID:          nodePoolID,
 						CreatedTime: now,
 						UpdatedTime: now,
 					},
-					Kind:    "NodePool",
-					Name:    "test-nodepool",
-					OwnerID: "different-cluster-789", // Different cluster
+					Kind:             "NodePool",
+					Name:             "test-nodepool",
+					OwnerID:          "different-cluster-789", // Different cluster
+					Spec:             []byte("{}"),
+					Labels:           []byte("{}"),
+					StatusConditions: []byte("[]"),
+					CreatedBy:        "[email protected]",
+					UpdatedBy:        "[email protected]",
 				}, nil)
pkg/api/presenters/adapter_status.go (1)

114-139: Consider extracting the inline metadata struct to reduce duplication.

The anonymous struct definition for openapiMetadata is duplicated verbatim (lines 114-121 and 124-131). If the generated OpenAPI type uses an inline anonymous struct, this is unavoidable. However, if possible, consider defining a local type alias or using direct assignment to reduce the ~30 lines of duplication.

♻️ Potential simplification (if OpenAPI schema allows)

If the generated type permits, you could simplify:

// If openapi.AdapterStatus.Metadata accepts *api.AdapterStatusMetadata or similar
if metadata != nil {
    openapiMetadata = &openapi.AdapterStatusMetadata{
        Attempt:       metadata.Attempt,
        CompletedTime: metadata.CompletedTime,
        // ... etc
    }
}

Otherwise, the current approach is correct given the anonymous struct constraint.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b4c857 and 5f363a9.

⛔ Files ignored due to path filters (2)
  • .bingo/oapi-codegen.sum is excluded by !**/*.sum
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (34)
  • .bingo/Variables.mk
  • .bingo/oapi-codegen.mod
  • .bingo/variables.env
  • Dockerfile.openapi
  • Dockerfile.openapi.dockerignore
  • Makefile
  • go.mod
  • openapi/oapi-codegen.yaml
  • openapi/openapi.yaml
  • openapitools.json
  • pkg/api/adapter_status_types.go
  • pkg/api/openapi_embed.go
  • pkg/api/presenters/adapter_status.go
  • pkg/api/presenters/adapter_status_test.go
  • pkg/api/presenters/cluster.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/node_pool.go
  • pkg/api/presenters/node_pool_test.go
  • pkg/errors/errors.go
  • pkg/handlers/cluster.go
  • pkg/handlers/cluster_nodepools.go
  • pkg/handlers/cluster_nodepools_test.go
  • pkg/handlers/node_pool.go
  • pkg/handlers/openapi.go
  • pkg/handlers/validation_test.go
  • test/factories/clusters.go
  • test/factories/node_pools.go
  • test/helper.go
  • test/integration/adapter_status_test.go
  • test/integration/api_contract_test.go
  • test/integration/clusters_test.go
  • test/integration/node_pools_test.go
  • test/integration/search_field_mapping_test.go
  • test/registration.go
💤 Files with no reviewable changes (4)
  • pkg/api/openapi_embed.go
  • openapitools.json
  • Dockerfile.openapi.dockerignore
  • Dockerfile.openapi
🧰 Additional context used
📓 Path-based instructions (9)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID

Files:

  • pkg/handlers/node_pool.go
  • test/registration.go
  • pkg/handlers/cluster.go
  • test/factories/clusters.go
  • pkg/api/adapter_status_types.go
  • test/integration/api_contract_test.go
  • pkg/handlers/cluster_nodepools.go
  • test/helper.go
  • pkg/api/presenters/adapter_status_test.go
  • pkg/handlers/validation_test.go
  • pkg/handlers/cluster_nodepools_test.go
  • test/factories/node_pools.go
  • test/integration/node_pools_test.go
  • pkg/handlers/openapi.go
  • test/integration/search_field_mapping_test.go
  • pkg/api/presenters/adapter_status.go
  • pkg/errors/errors.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/cluster.go
  • pkg/api/presenters/node_pool.go
  • test/integration/adapter_status_test.go
  • pkg/api/presenters/node_pool_test.go
  • test/integration/clusters_test.go
pkg/handlers/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

pkg/handlers/**/*.go: HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table
Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration

Files:

  • pkg/handlers/node_pool.go
  • pkg/handlers/cluster.go
  • pkg/handlers/cluster_nodepools.go
  • pkg/handlers/validation_test.go
  • pkg/handlers/cluster_nodepools_test.go
  • pkg/handlers/openapi.go
pkg/{dao,handlers}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

List operations must support pagination via ListArgs struct with limit, offset, and search parameters

Files:

  • pkg/handlers/node_pool.go
  • pkg/handlers/cluster.go
  • pkg/handlers/cluster_nodepools.go
  • pkg/handlers/validation_test.go
  • pkg/handlers/cluster_nodepools_test.go
  • pkg/handlers/openapi.go
pkg/{handlers,services,dao}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)

Files:

  • pkg/handlers/node_pool.go
  • pkg/handlers/cluster.go
  • pkg/handlers/cluster_nodepools.go
  • pkg/handlers/validation_test.go
  • pkg/handlers/cluster_nodepools_test.go
  • pkg/handlers/openapi.go
pkg/{handlers,services,db}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state

Files:

  • pkg/handlers/node_pool.go
  • pkg/handlers/cluster.go
  • pkg/handlers/cluster_nodepools.go
  • pkg/handlers/validation_test.go
  • pkg/handlers/cluster_nodepools_test.go
  • pkg/handlers/openapi.go
openapi/**/*.yaml

📄 CodeRabbit inference engine (AGENTS.md)

openapi/**/*.yaml: Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0
Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Files:

  • openapi/oapi-codegen.yaml
  • openapi/openapi.yaml
test/factories/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use test data factories in test/factories/ to provide consistent, reusable test data with builder pattern (e.g., NewClusterBuilder().WithName().Build())

Files:

  • test/factories/clusters.go
  • test/factories/node_pools.go
pkg/api/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment

Files:

  • pkg/api/adapter_status_types.go
  • pkg/api/presenters/adapter_status_test.go
  • pkg/api/presenters/adapter_status.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/cluster.go
  • pkg/api/presenters/node_pool.go
  • pkg/api/presenters/node_pool_test.go
test/integration/**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

test/integration/**/*_test.go: Integration tests must use Testcontainers to create isolated PostgreSQL instances for each test suite to ensure no state leakage
All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation

Files:

  • test/integration/api_contract_test.go
  • test/integration/node_pools_test.go
  • test/integration/search_field_mapping_test.go
  • test/integration/adapter_status_test.go
  • test/integration/clusters_test.go
🧠 Learnings (27)
📓 Common learnings
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/errors/errors.go:9-9
Timestamp: 2026-01-08T09:40:10.138Z
Learning: In openshift-hyperfleet/hyperfleet-api, pkg/api/openapi is a generated directory (excluded in .gitignore) created by `make generate` using openapi-generator-cli via Docker; linters that run before code generation will report false-positive import errors for this package.
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: go.mod:32-36
Timestamp: 2026-01-13T04:19:50.012Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository, the team has decided to keep OpenTelemetry core packages (go.opentelemetry.io/otel, go.opentelemetry.io/otel/sdk, go.opentelemetry.io/otel/trace, go.opentelemetry.io/otel/exporters/stdout/stdouttrace) at v1.38.0 rather than upgrading to v1.39.0 in PR #31.
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/telemetry/otel.go:10-10
Timestamp: 2026-01-13T10:10:24.211Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository (PR #31), the team has decided to keep the OpenTelemetry semantic conventions package at v1.37.0 (go.opentelemetry.io/otel/semconv/v1.37.0) while using the SDK at v1.38.0 in pkg/telemetry/otel.go.
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Use Podman to run openapi-generator-cli v7.16.0 via make generate to ensure version consistency and avoid environment-specific issues
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment

Applied to files:

  • go.mod
  • .bingo/variables.env
  • openapi/oapi-codegen.yaml
  • .bingo/Variables.mk
  • test/helper.go
  • .bingo/oapi-codegen.mod
  • Makefile
  • pkg/handlers/openapi.go
  • pkg/errors/errors.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/cluster.go
  • pkg/api/presenters/node_pool_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files

Applied to files:

  • go.mod
  • .bingo/variables.env
  • openapi/oapi-codegen.yaml
  • test/integration/api_contract_test.go
  • test/helper.go
  • .bingo/oapi-codegen.mod
  • Makefile
  • pkg/handlers/openapi.go
  • pkg/api/presenters/adapter_status.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/cluster.go
  • pkg/api/presenters/node_pool_test.go
  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress

Applied to files:

  • go.mod
  • openapi/oapi-codegen.yaml
  • .bingo/oapi-codegen.mod
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0

Applied to files:

  • go.mod
  • .bingo/variables.env
  • openapi/oapi-codegen.yaml
  • test/helper.go
  • .bingo/oapi-codegen.mod
  • Makefile
  • pkg/handlers/openapi.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/cluster.go
  • pkg/api/presenters/node_pool_test.go
  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T09:40:10.138Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/errors/errors.go:9-9
Timestamp: 2026-01-08T09:40:10.138Z
Learning: In openshift-hyperfleet/hyperfleet-api, pkg/api/openapi is a generated directory (excluded in .gitignore) created by `make generate` using openapi-generator-cli via Docker; linters that run before code generation will report false-positive import errors for this package.

Applied to files:

  • go.mod
  • .bingo/variables.env
  • openapi/oapi-codegen.yaml
  • .bingo/oapi-codegen.mod
  • Makefile
  • pkg/handlers/openapi.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/cluster.go
  • pkg/api/presenters/node_pool_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/db/**/*.go : Use PostgreSQL 14.2 with GORM ORM for database operations

Applied to files:

  • go.mod
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to **/*.go : Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)

Applied to files:

  • go.mod
  • .bingo/variables.env
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{db/migrations,dao}/**/*.go : NodePool owner_references.id must enforce foreign key relationship to parent cluster to maintain referential integrity

Applied to files:

  • pkg/handlers/node_pool.go
  • pkg/handlers/cluster_nodepools.go
  • pkg/handlers/cluster_nodepools_test.go
  • test/factories/node_pools.go
  • test/integration/node_pools_test.go
  • pkg/api/presenters/node_pool.go
  • pkg/api/presenters/node_pool_test.go
📚 Learning: 2026-01-13T04:16:08.743Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/middleware/masking.go:28-36
Timestamp: 2026-01-13T04:16:08.743Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository, NewOCMLogger(ctx) is deprecated. Switch to the slog-based logger and use logger.With(ctx, ...) to produce structured, context-aware logs. Replace occurrences of NewOCMLogger(ctx) with logger.With(ctx, ...). Update imports to use the new logger and adjust any tests to expect structured logging behavior.

Applied to files:

  • pkg/handlers/node_pool.go
  • test/registration.go
  • pkg/handlers/cluster.go
  • test/factories/clusters.go
  • pkg/api/adapter_status_types.go
  • test/integration/api_contract_test.go
  • pkg/handlers/cluster_nodepools.go
  • test/helper.go
  • pkg/api/presenters/adapter_status_test.go
  • pkg/handlers/validation_test.go
  • pkg/handlers/cluster_nodepools_test.go
  • test/factories/node_pools.go
  • test/integration/node_pools_test.go
  • pkg/handlers/openapi.go
  • test/integration/search_field_mapping_test.go
  • pkg/api/presenters/adapter_status.go
  • pkg/errors/errors.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/cluster.go
  • pkg/api/presenters/node_pool.go
  • test/integration/adapter_status_test.go
  • pkg/api/presenters/node_pool_test.go
  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Environment-based configuration: use OCM_ENV variable to select development, unit_testing, integration_testing, or production configuration

Applied to files:

  • .bingo/variables.env
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Use Podman to run openapi-generator-cli v7.16.0 via make generate to ensure version consistency and avoid environment-specific issues

Applied to files:

  • .bingo/variables.env
  • .bingo/Variables.mk
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Applied to files:

  • openapi/oapi-codegen.yaml
  • Makefile
  • pkg/handlers/openapi.go
  • pkg/api/presenters/cluster.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to test/factories/**/*.go : Use test data factories in test/factories/ to provide consistent, reusable test data with builder pattern (e.g., NewClusterBuilder().WithName().Build())

Applied to files:

  • test/factories/clusters.go
  • test/factories/node_pools.go
  • pkg/api/presenters/cluster_test.go
  • test/integration/adapter_status_test.go
  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/handlers/**/*.go : Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table

Applied to files:

  • pkg/api/adapter_status_types.go
  • pkg/api/presenters/adapter_status_test.go
  • pkg/api/presenters/adapter_status.go
  • test/integration/adapter_status_test.go
  • openapi/openapi.yaml
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/services/**/*.go : Calculate aggregate status from adapter conditions and return in status.phase field (Ready, Failed, NotReady)

Applied to files:

  • pkg/api/adapter_status_types.go
  • test/integration/api_contract_test.go
  • pkg/api/presenters/adapter_status_test.go
  • test/integration/search_field_mapping_test.go
  • pkg/api/presenters/adapter_status.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/cluster.go
  • pkg/api/presenters/node_pool.go
  • test/integration/adapter_status_test.go
  • pkg/api/presenters/node_pool_test.go
  • openapi/openapi.yaml
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/services/**/*.go : Status aggregation: Phase is 'Ready' if all adapters report Ready=True, 'Failed' if any adapter reports Ready=False, 'NotReady' otherwise

Applied to files:

  • pkg/api/adapter_status_types.go
  • test/integration/api_contract_test.go
  • pkg/api/presenters/adapter_status_test.go
  • test/integration/search_field_mapping_test.go
  • pkg/api/presenters/adapter_status.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/cluster.go
  • test/integration/adapter_status_test.go
  • pkg/api/presenters/node_pool_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to test/integration/**/*_test.go : All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation

Applied to files:

  • test/integration/api_contract_test.go
  • test/helper.go
  • Makefile
  • test/integration/search_field_mapping_test.go
  • test/integration/adapter_status_test.go
  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,handlers}/**/*.go : List operations must support pagination via ListArgs struct with limit, offset, and search parameters

Applied to files:

  • .bingo/oapi-codegen.mod
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags

Applied to files:

  • pkg/handlers/openapi.go
  • pkg/api/presenters/cluster.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/migrate/**/*.go : Use GORM AutoMigrate at startup via ./bin/hyperfleet-api migrate command; migrations are idempotent and track applied migrations

Applied to files:

  • pkg/handlers/openapi.go
  • pkg/api/presenters/cluster.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{handlers,services,dao}/**/*.go : Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)

Applied to files:

  • pkg/handlers/openapi.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,db}/**/*.go : Use polymorphic status tables with owner_type + owner_id to support multiple resource types without creating separate status tables

Applied to files:

  • pkg/api/presenters/adapter_status.go
  • test/integration/adapter_status_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/handlers/**/*.go : Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes

Applied to files:

  • pkg/api/presenters/cluster_test.go
📚 Learning: 2026-01-13T10:10:24.211Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/telemetry/otel.go:10-10
Timestamp: 2026-01-13T10:10:24.211Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository (PR #31), the team has decided to keep the OpenTelemetry semantic conventions package at v1.37.0 (go.opentelemetry.io/otel/semconv/v1.37.0) while using the SDK at v1.38.0 in pkg/telemetry/otel.go.

Applied to files:

  • openapi/openapi.yaml
📚 Learning: 2026-01-13T04:19:50.012Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: go.mod:32-36
Timestamp: 2026-01-13T04:19:50.012Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository, the team has decided to keep OpenTelemetry core packages (go.opentelemetry.io/otel, go.opentelemetry.io/otel/sdk, go.opentelemetry.io/otel/trace, go.opentelemetry.io/otel/exporters/stdout/stdouttrace) at v1.38.0 rather than upgrading to v1.39.0 in PR #31.

Applied to files:

  • openapi/openapi.yaml
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/**/*{auth,middleware}*.go : JWT authentication validates tokens from Red Hat SSO and extracts account ID and username from claims for authorization

Applied to files:

  • test/integration/clusters_test.go
🧬 Code graph analysis (13)
test/registration.go (1)
test/helper.go (1)
  • Helper (55-68)
pkg/handlers/cluster.go (1)
pkg/api/presenters/cluster.go (1)
  • ConvertCluster (14-55)
test/integration/api_contract_test.go (1)
pkg/api/status_types.go (6)
  • PhaseNotReady (10-10)
  • PhaseReady (11-11)
  • PhaseFailed (12-12)
  • ConditionTrue (20-20)
  • ConditionFalse (21-21)
  • ConditionUnknown (22-22)
pkg/handlers/cluster_nodepools.go (1)
pkg/api/presenters/node_pool.go (1)
  • ConvertNodePool (13-54)
test/factories/node_pools.go (1)
pkg/api/metadata_types.go (1)
  • Meta (37-42)
test/integration/node_pools_test.go (1)
test/helper.go (2)
  • WithAuthToken (308-316)
  • GetAccessTokenFromContext (300-305)
pkg/handlers/openapi.go (1)
pkg/errors/errors.go (1)
  • GeneralError (196-198)
test/integration/search_field_mapping_test.go (1)
test/helper.go (1)
  • WithAuthToken (308-316)
pkg/api/presenters/adapter_status.go (3)
pkg/api/status_types.go (1)
  • ConditionStatus (17-17)
pkg/api/adapter_status_types.go (2)
  • AdapterStatus (11-30)
  • AdapterStatusMetadata (32-39)
pkg/api/metadata_types.go (1)
  • Metadata (28-34)
pkg/api/presenters/cluster_test.go (2)
pkg/errors/errors.go (1)
  • Href (188-190)
pkg/api/presenters/cluster.go (1)
  • ConvertCluster (14-55)
pkg/api/presenters/cluster.go (3)
pkg/api/cluster_types.go (1)
  • Cluster (11-34)
pkg/api/status_types.go (2)
  • ConditionStatus (17-17)
  • ResourcePhase (7-7)
pkg/errors/errors.go (1)
  • Href (188-190)
test/integration/adapter_status_test.go (3)
test/helper.go (1)
  • WithAuthToken (308-316)
pkg/api/adapter_status_types.go (1)
  • AdapterStatus (11-30)
pkg/api/resource_id.go (1)
  • NewID (14-16)
test/integration/clusters_test.go (1)
test/helper.go (2)
  • WithAuthToken (308-316)
  • GetAccessTokenFromContext (300-305)
🪛 checkmake (0.2.2)
Makefile

[warning] 227-227: Target body for "generate" exceeds allowed length of 5 (15).

(maxbodylength)

🔇 Additional comments (61)
pkg/handlers/validation_test.go (2)

97-106: LGTM!

Correctly uses the openapi.PtrString helper to construct the pointer-based Kind field.


140-150: LGTM!

Correctly validates that a wrong kind value produces the expected error message.

pkg/errors/errors.go (1)

165-178: LGTM — correct adaptation to oapi-codegen's inline struct type.

The anonymous struct repetition (lines 165-168 and 170-173) is required because oapi-codegen generates Details as a pointer to an anonymous struct slice (*[]struct{...}). Go's type system doesn't allow substituting a locally-defined named type here, so this pattern is the idiomatic approach.

.bingo/variables.env (1)

11-18: LGTM!

The bingo-managed environment variables are correctly updated to include the new OAPI_CODEGEN tool and the golangci-lint version bump. This aligns with the PR's objective to introduce oapi-codegen for OpenAPI code generation.

pkg/handlers/openapi.go (1)

22-40: LGTM!

The migration from YAML-based OpenAPI loading to using the generated openapi.GetSwagger() and MarshalJSON() is clean and aligns well with the oapi-codegen approach. Error handling is appropriate with descriptive error messages.

openapi/oapi-codegen.yaml (1)

1-17: LGTM!

The oapi-codegen configuration is well-structured:

  • embedded-spec: true correctly enables the GetSwagger() function used in pkg/handlers/openapi.go.
  • client: true generates the ClientWithResponses pattern mentioned in the PR objectives.
  • The compatibility options (old-merge-schemas, old-aliasing) ensure smoother migration from the previous generator.
.bingo/Variables.mk (1)

44-49: LGTM!

The OAPI_CODEGEN make target follows the established bingo pattern consistently with other tool entries. The build command correctly references the oapi-codegen module and outputs to the versioned binary path.

.bingo/oapi-codegen.mod (1)

1-5: Align Go version across bingo module files to match main go.mod.

The .bingo/oapi-codegen.mod specifies Go 1.25.0, which is inconsistent with the main go.mod (1.24.0). Additionally, .bingo/mockgen.mod also specifies Go 1.25.0. Update both files to 1.24.0 to maintain consistency across the project. Per organizational guidelines, the target version should be Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto).

⛔ Skipped due to learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to **/*.go : Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,handlers}/**/*.go : List operations must support pagination via ListArgs struct with limit, offset, and search parameters
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/errors/errors.go:9-9
Timestamp: 2026-01-08T09:40:10.138Z
Learning: In openshift-hyperfleet/hyperfleet-api, pkg/api/openapi is a generated directory (excluded in .gitignore) created by `make generate` using openapi-generator-cli via Docker; linters that run before code generation will report false-positive import errors for this package.
pkg/api/adapter_status_types.go (1)

32-44: LGTM! New metadata struct aligns with OpenAPI schema.

The AdapterStatusMetadata struct correctly mirrors the metadata object defined in the OpenAPI spec for AdapterStatus. All field types match (int32 for attempt, date-time for timestamps, string for duration), and the JSON tags use consistent snake_case naming.

pkg/api/presenters/node_pool_test.go (3)

9-12: LGTM! Import and type updates align with oapi-codegen migration.

The new openapi_types import from github.com/oapi-codegen/runtime/types is correctly used for email-typed fields (CreatedBy, UpdatedBy). This aligns with the OpenAPI spec's format: email definition for these fields.


225-231: Status enum assertions correctly updated.

The test expectations properly use the new typed enum values (openapi.Ready, openapi.True) instead of string constants. This provides compile-time type safety and matches the updated OpenAPI ResourcePhase and ConditionStatus enum definitions.


395-439: Round-trip test properly validates email type handling.

The test correctly verifies that CreatedBy/UpdatedBy fields maintain their semantic openapi_types.Email type through the ConvertNodePoolPresentNodePool cycle. This ensures the presenter layer correctly wraps string values into the typed representation.

test/helper.go (2)

245-257: Client creation correctly adapted for oapi-codegen.

The NewApiClient() method properly constructs the server URL and initializes the ClientWithResponses client. Using helper.T.Fatalf on error is appropriate for test setup failures.


288-316: Auth context infrastructure is well-designed.

The implementation follows Go best practices:

  • Unexported contextKeyAccessToken type prevents key collisions
  • GetAccessTokenFromContext safely returns empty string for missing values
  • WithAuthToken conditionally injects the header only when a token exists, avoiding empty Authorization headers
openapi/openapi.yaml (2)

627-680: List schemas with explicit pagination metadata are well-structured.

The AdapterStatusList (and similarly ClusterList, NodePoolList) now explicitly defines pagination fields (kind, page, size, total) as required properties. This provides a consistent structure across all list endpoints and generates clean Go types.


1265-1271: ResourcePhase enum correctly defines lifecycle states.

The enum provides the three standard lifecycle phases (NotReady, Ready, Failed) that align with the status aggregation logic documented in the coding guidelines (Ready if all adapters Ready=True, Failed if any Ready=False, NotReady otherwise).

Makefile (1)

254-256: Generate-vendor alias maintains backward compatibility.

The simplified alias ensures existing workflows calling make generate-vendor continue to work while eliminating the redundant Docker-based generation path.

go.mod (2)

47-47: Transitive dependency updates look correct.

The go-jsonmerge/v2 is a transitive dependency of oapi-codegen/runtime, and the bluemonday update from v1.0.23 to v1.0.25 is a minor security-related bump.

Also applies to: 89-89


24-24: LGTM - oapi-codegen runtime dependency is current.

The github.com/oapi-codegen/runtime v1.1.2 is the latest version and provides the required runtime library for oapi-codegen generated types and client code. This aligns with the PR objective.

test/integration/search_field_mapping_test.go (3)

34-44: LGTM - Clean migration to ClientWithResponses pattern.

The search parameter construction and response handling follow the new oapi-codegen conventions correctly:

  • openapi.SearchParams(searchStr) type conversion
  • GetClustersWithResponse with params and auth token
  • Proper nil-check on resp.JSON200 before assertions

This pattern is consistently applied throughout the file.


54-54: Enum naming updated correctly.

The change from openapi.NOT_READY to openapi.NotReady aligns with the standardized enum naming convention in the new generated types.


275-293: NodePool search tests properly mirror Cluster tests.

The GetNodePoolsParams and GetNodePoolsWithResponse usage correctly parallels the Cluster search implementation, maintaining consistency across resource types.

test/integration/adapter_status_test.go (4)

15-24: Good extraction of helper function.

The newAdapterStatusRequest helper reduces code duplication and ensures consistent construction of AdapterStatusCreateRequest objects. Setting ObservedTime: time.Now() is appropriate for test scenarios.


44-51: Status enum migration looks correct.

The change from string literals "True"/"False" to typed constants openapi.True/openapi.False provides type safety and aligns with the new generated types.


54-60: Response handling correctly uses JSON201 for created resources.

The pattern of using resp.JSON201 for POST responses returning created resources and resp.JSON200 for GET responses is consistent with HTTP semantics and the oapi-codegen conventions.


375-398: No issue with increment operation on QueryParamsPage.

The pageNum++ operation on line 397 is valid. openapi.QueryParamsPage supports increment operations, as evidenced by its successful use in the pagination loop. No changes needed.

test/factories/node_pools.go (1)

34-41: LGTM - Audit fields added to test factory.

Adding CreatedBy and UpdatedBy fields ensures test data includes user-tracking metadata, which aligns with the broader test infrastructure updates in this PR. The placeholder email "[email protected]" is appropriate for test factories.

test/registration.go (1)

11-23: LGTM - Return type updated for new client pattern.

The change from *openapi.APIClient to *openapi.ClientWithResponses is the foundational change enabling all integration tests to use the new oapi-codegen response-based API pattern. This aligns with helper.NewApiClient() returning *openapi.ClientWithResponses as shown in the helper context.

pkg/handlers/cluster_nodepools.go (2)

151-152: Owner identifier updated to email format.

The change from "system" to "[email protected]" aligns with the PR-wide standardization of owner/user metadata as email-typed fields. This is consistent with changes in pkg/handlers/cluster.go and pkg/handlers/node_pool.go.


45-49: The string concatenation approach, while not ideal, does not present a SQL injection vulnerability in this context. The search string is parsed by the tree-search-language (TSL) query parser (line 167 of generic.go), which properly extracts values and converts them to parameterized SQL before GORM execution. Additionally, the clusterID is validated to exist (line 37) before being used in the search filter, and KSUID-generated IDs are constrained to alphanumeric characters (0-9, a-v), preventing quote injection. While a more structured approach would be preferable for clarity, the current implementation is safe through its combination of validation and parameterized query processing.

Likely an incorrect or invalid review comment.

test/factories/clusters.go (1)

24-25: LGTM!

The addition of CreatedBy and UpdatedBy fields with a consistent test email aligns with the API schema changes and mirrors the approach in test/factories/node_pools.go. As per coding guidelines, the factory pattern is correctly maintained for consistent, reusable test data.

pkg/handlers/cluster.go (1)

41-42: LGTM!

The update to "[email protected]" is consistent with the PR-wide standardization of owner/user metadata as email-typed fields across all handlers.

pkg/handlers/cluster_nodepools_test.go (1)

59-66: LGTM!

The mock NodePool now includes all required fields (Spec, Labels, StatusConditions, CreatedBy, UpdatedBy) needed for the presenter to work correctly. The empty JSON values and test email are appropriate for test fixtures.

test/integration/api_contract_test.go (1)

14-40: LGTM!

The contract tests correctly verify that domain constants (api.PhaseNotReady, api.ConditionTrue, etc.) remain synchronized with the renamed OpenAPI constants (openapi.NotReady, openapi.True, etc.). This is a valuable safeguard against drift between domain and generated types after the oapi-codegen migration.

pkg/api/presenters/node_pool.go (2)

114-124: LGTM!

The ResourceCondition mapping is complete with all required fields properly ordered: CreatedTime, LastTransitionTime, LastUpdatedTime, Message, ObservedGeneration, Reason, Status, and Type. The type cast for Status correctly converts from domain to OpenAPI type.


126-151: LGTM!

The NodePool construction comprehensively populates all required fields including metadata, owner references, spec, and status. The use of toEmail helper (defined in cluster.go) for CreatedBy/UpdatedBy aligns with the new openapi_types.Email type requirement.

pkg/api/presenters/cluster.go (3)

37-41: LGTM!

The Kind defaulting logic follows the same pattern as ConvertNodePool, ensuring consistency across resource types. Using the pointer value when provided and falling back to "Cluster" is the correct approach.


57-60: LGTM!

The toEmail helper provides a clean conversion from string to openapi_types.Email. Since validation occurs at the API boundary, this simple type cast is appropriate for the presenter layer.


126-145: LGTM!

The Cluster construction is comprehensive and properly uses the new OpenAPI types: openapi.PtrString for pointer fields, toEmail for email-typed fields, and direct struct embedding for Status. The field ordering and type casts are correct.

pkg/api/presenters/adapter_status.go (2)

43-47: LGTM!

The Data handling correctly initializes an empty map when req.Data is nil, ensuring the marshaled JSON is always valid ({} vs null). The pointer dereference on line 46 is safe due to the nil check.


152-160: LGTM!

The returned AdapterStatus correctly uses pointer types for Data and Metadata as required by the new OpenAPI schema. Field ordering is clean and the nil-safe timestamp handling ensures zero values are returned rather than nil pointers.

pkg/api/presenters/adapter_status_test.go (3)

22-34: LGTM!

The test helper correctly constructs the request with the new pointer-based Data and inline Metadata struct patterns. This aligns with the updated OpenAPI schema.


209-211: LGTM!

The test cases correctly use the renamed OpenAPI constants (openapi.True, openapi.False, openapi.Unknown) and verify bidirectional mapping with domain constants.


426-460: LGTM!

The round-trip test (TestConvertAndPresent_RoundTrip) validates data integrity through the convert/present cycle, including proper handling of pointer-based Data access. This is excellent coverage for the new type patterns.

test/integration/node_pools_test.go (3)

61-77: LGTM!

The test correctly uses the new *_WithResponse pattern with resp.StatusCode() and resp.JSON201 payload access. The local variable for kind pointer is the correct approach for the updated pointer-based field.


106-128: LGTM!

The paging test correctly constructs GetNodePoolsParams with typed query parameters (QueryParamsPage, QueryParamsPageSize) and uses the *_WithResponse variant. The nil check on resp.JSON200 ensures safe access.


197-231: LGTM!

The test comprehensively covers the happy path (200 OK) and error cases (404 for non-existent nodepool, non-existent cluster, and wrong cluster). The consistent use of *_WithResponse variants and StatusCode() assertions is correct.

pkg/api/presenters/cluster_test.go (3)

15-27: LGTM!

The test helper correctly constructs the request with pointer-based Labels and Kind fields using openapi.PtrString. This aligns with the updated ClusterCreateRequest schema.


216-217: LGTM!

The assertions correctly compare CreatedBy and UpdatedBy against openapi_types.Email typed values, validating the toEmail helper conversion in PresentCluster.


226-230: LGTM!

The Status phase and condition assertions correctly use the new OpenAPI enum constants (openapi.Ready, openapi.True). The test validates the complete status structure including nested conditions.

test/integration/clusters_test.go (11)

21-51: LGTM!

The test correctly adapts to the new WithResponse pattern, properly checks for nil on resp.JSON200 before dereferencing, and correctly uses test.WithAuthToken(ctx) for authentication.


53-86: LGTM!

The test properly uses openapi.PtrString("Cluster") for the pointer field, correctly extracts and validates the JSON201 response, and appropriately falls back to raw resty for the malformed JSON test case.


112-125: LGTM!

The pagination parameter construction using openapi.QueryParamsPage and openapi.QueryParamsPageSize type aliases is idiomatic for oapi-codegen generated types. The nil check on resp.JSON200 is properly placed.


128-149: LGTM!

The search parameter construction and response handling are correct and idiomatic.


316-383: LGTM!

The schema validation tests properly handle both the typed client and raw resty approaches. The nil checks on JSON201 are in place.


453-507: LGTM!

This test correctly uses raw resty for the invalid request, and resp.Body() from resty works as expected (unlike the HTTPResponse.Body from the oapi-codegen client).


509-560: LGTM!

The default sorting test properly uses the new client pattern and includes appropriate nil checks.


562-616: LGTM!

The orderBy parameter construction and response handling are correct.


672-705: LGTM!

The test correctly uses raw resty to send invalid JSON payloads that can't be represented with the typed structs.


707-740: LGTM!

The test correctly validates that wrong kind values are rejected with a 400 response.


421-434: Response body already consumed by PostClusterWithResponse client.

The PostClusterWithResponse method parses the response body to populate typed response fields like resp.JSON201 or resp.JSON400. Calling io.ReadAll(resp.HTTPResponse.Body) on line 426 attempts to read an already-consumed stream, which returns empty data or EOF.

Use the pre-parsed response from the generated client. For error responses on non-2xx status codes, the typed response field (e.g., resp.JSON400) should contain the parsed error object, or access the raw body bytes from the response wrapper if available.

🐛 Proposed fix
-	// Parse error response to verify field-level details
-	bodyBytes, err := io.ReadAll(resp.HTTPResponse.Body)
-	if err != nil {
-		t.Fatalf("failed to read response body: %v", err)
-	}
-
 	var errorResponse openapi.Error
-	if err := json.Unmarshal(bodyBytes, &errorResponse); err != nil {
+	if err := json.Unmarshal(resp.Body, &errorResponse); err != nil {
 		t.Fatalf("failed to unmarshal error response body: %v", err)
 	}

@rh-amarin rh-amarin changed the title Oapi codegen HYPERFLEET-500 - Introduce oapi-codegen Jan 13, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @Dockerfile:
- Around line 4-5: The Dockerfile declares ARGs GIT_SHA and GIT_DIRTY but the
RUN step calls make build which re-computes them; instead pass the ARG values
into make so the build uses the provided values—modify the RUN that invokes make
build to export or forward GIT_SHA and GIT_DIRTY (e.g., pass GIT_SHA="$GIT_SHA"
GIT_DIRTY="$GIT_DIRTY" to make or export them into the environment before
calling make build) so the make process receives the build ARGs.
- Around line 1-2: Update the Dockerfile to use the correct Go toolchain and
FIPS crypto build settings: replace the base image reference FROM golang:1.25
with FROM golang:1.24.9-bookworm to match go.mod/toolchain, change the build
invocation that currently sets CGO_ENABLED=0 to run CGO_ENABLED=1
GOEXPERIMENT=boringcrypto GOOS=linux make build so the binary is built with
BoringCrypto, and remove or rename the stale top comment "OpenAPI generation
stage" to reflect this being a standard builder stage; locate these changes
around the existing FROM line and the command invoking make build in the builder
stage.

In @Makefile:
- Around line 274-280: The clean target currently only removes
pkg/api/openapi/openapi.gen.go but generate produces both openapi.gen.go and
helpers.go; update the Makefile clean target (the "clean" rule) to remove
pkg/api/openapi/helpers.go as well or simply rm -rf the entire pkg/api/openapi
directory (matching the generate target behavior) so helpers.go is cleaned up
too.
🧹 Nitpick comments (1)
Makefile (1)

231-242: Consider removing redundant helper functions.

PtrString and PtrInt32 are functionally redundant since Ptr[T any] handles all types generically. Unless there's a specific need for non-generic helpers (e.g., compatibility with code that can't use generics), these can be removed to reduce surface area.

Additionally, consider moving the helpers template to a separate file (e.g., openapi/helpers.go.tmpl) and using cp or cat instead of inline printf. This addresses the static analysis warning about target body length and improves maintainability.

Simplified helpers.go
 	@printf '%s\n' \
 		'package openapi' \
 		'' \
 		'// Ptr returns a pointer to the given value.' \
 		'func Ptr[T any](v T) *T { return &v }' \
-		'' \
-		'// PtrString returns a pointer to the given string.' \
-		'func PtrString(v string) *string { return &v }' \
-		'' \
-		'// PtrInt32 returns a pointer to the given int32.' \
-		'func PtrInt32(v int32) *int32 { return &v }' \
 		> pkg/api/openapi/helpers.go
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f363a9 and f04dc61.

📒 Files selected for processing (2)
  • Dockerfile
  • Makefile
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/errors/errors.go:9-9
Timestamp: 2026-01-08T09:40:10.138Z
Learning: In openshift-hyperfleet/hyperfleet-api, pkg/api/openapi is a generated directory (excluded in .gitignore) created by `make generate` using openapi-generator-cli via Docker; linters that run before code generation will report false-positive import errors for this package.
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/telemetry/otel.go:10-10
Timestamp: 2026-01-13T10:10:24.211Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository (PR #31), the team has decided to keep the OpenTelemetry semantic conventions package at v1.37.0 (go.opentelemetry.io/otel/semconv/v1.37.0) while using the SDK at v1.38.0 in pkg/telemetry/otel.go.
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: go.mod:32-36
Timestamp: 2026-01-13T04:19:50.012Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository, the team has decided to keep OpenTelemetry core packages (go.opentelemetry.io/otel, go.opentelemetry.io/otel/sdk, go.opentelemetry.io/otel/trace, go.opentelemetry.io/otel/exporters/stdout/stdouttrace) at v1.38.0 rather than upgrading to v1.39.0 in PR #31.
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Use Podman to run openapi-generator-cli v7.16.0 via make generate to ensure version consistency and avoid environment-specific issues
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files
📚 Learning: 2026-01-08T09:40:10.138Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/errors/errors.go:9-9
Timestamp: 2026-01-08T09:40:10.138Z
Learning: In openshift-hyperfleet/hyperfleet-api, pkg/api/openapi is a generated directory (excluded in .gitignore) created by `make generate` using openapi-generator-cli via Docker; linters that run before code generation will report false-positive import errors for this package.

Applied to files:

  • Dockerfile
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags

Applied to files:

  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/migrate/**/*.go : Use GORM AutoMigrate at startup via ./bin/hyperfleet-api migrate command; migrations are idempotent and track applied migrations

Applied to files:

  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment

Applied to files:

  • Dockerfile
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Use Podman to run openapi-generator-cli v7.16.0 via make generate to ensure version consistency and avoid environment-specific issues

Applied to files:

  • Dockerfile
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0

Applied to files:

  • Dockerfile
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files

Applied to files:

  • Dockerfile
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Applied to files:

  • Dockerfile
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress

Applied to files:

  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to test/integration/**/*_test.go : All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation

Applied to files:

  • Makefile
🪛 checkmake (0.2.2)
Makefile

[warning] 227-227: Target body for "generate" exceeds allowed length of 5 (15).

(maxbodylength)

🔇 Additional comments (4)
Dockerfile (1)

20-42: LGTM!

The runtime stage configuration is well-structured: distroless base image for minimal attack surface, correct binary and schema paths, appropriate port exposure, and clear metadata labels.

Makefile (3)

80-82: LGTM!

The uppercase naming (GIT_SHA, GIT_DIRTY) follows Make conventions for variables that may be overridden via environment or command line, and the ?= operator correctly allows external overrides while providing sensible defaults.


254-256: LGTM!

Good backward compatibility approach—existing CI/CD workflows or developer habits using make generate-vendor will continue to work seamlessly.


314-317: LGTM!

Build args are correctly propagated to the container build. Once the Dockerfile is updated to export these as environment variables for make build, the version metadata will be properly embedded.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @Dockerfile:
- Line 4: Update the Dockerfile base image from "golang:1.25 AS builder" to the
project-required Go version "golang:1.24.9 AS builder" and ensure the build
preserves FIPS-compliant crypto by not forcing CGO off; remove any occurrence of
"CGO_ENABLED=0" in the Dockerfile (or explicitly set "ENV CGO_ENABLED=1" if an
explicit value is required) so the container build honors the Makefile's
CGO_ENABLED default and enables FIPS-compliant crypto.
🧹 Nitpick comments (1)
Makefile (1)

227-243: Consider extracting helper generation to a separate file.

The inline printf for helpers.go works but makes the target body long (15 statements). Consider placing the helper source in a template file (e.g., openapi/helpers.go.tmpl) and copying it during generation, or accept this as-is given it's a one-time setup.

Also, the generic Ptr[T] already covers the functionality of PtrString and PtrInt32. You could simplify to just the generic helper unless there are call sites where type inference struggles.

♻️ Simplified helpers.go with generic only
 	@printf '%s\n' \
 		'package openapi' \
 		'' \
 		'// Ptr returns a pointer to the given value.' \
 		'func Ptr[T any](v T) *T { return &v }' \
-		'' \
-		'// PtrString returns a pointer to the given string.' \
-		'func PtrString(v string) *string { return &v }' \
-		'' \
-		'// PtrInt32 returns a pointer to the given int32.' \
-		'func PtrInt32(v int32) *int32 { return &v }' \
 		> pkg/api/openapi/helpers.go
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f04dc61 and 4367834.

📒 Files selected for processing (3)
  • .dockerignore
  • Dockerfile
  • Makefile
✅ Files skipped from review due to trivial changes (1)
  • .dockerignore
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/errors/errors.go:9-9
Timestamp: 2026-01-08T09:40:10.138Z
Learning: In openshift-hyperfleet/hyperfleet-api, pkg/api/openapi is a generated directory (excluded in .gitignore) created by `make generate` using openapi-generator-cli via Docker; linters that run before code generation will report false-positive import errors for this package.
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/telemetry/otel.go:10-10
Timestamp: 2026-01-13T10:10:24.211Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository (PR #31), the team has decided to keep the OpenTelemetry semantic conventions package at v1.37.0 (go.opentelemetry.io/otel/semconv/v1.37.0) while using the SDK at v1.38.0 in pkg/telemetry/otel.go.
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: go.mod:32-36
Timestamp: 2026-01-13T04:19:50.012Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository, the team has decided to keep OpenTelemetry core packages (go.opentelemetry.io/otel, go.opentelemetry.io/otel/sdk, go.opentelemetry.io/otel/trace, go.opentelemetry.io/otel/exporters/stdout/stdouttrace) at v1.38.0 rather than upgrading to v1.39.0 in PR #31.
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Use Podman to run openapi-generator-cli v7.16.0 via make generate to ensure version consistency and avoid environment-specific issues
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
📚 Learning: 2026-01-08T09:40:10.138Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/errors/errors.go:9-9
Timestamp: 2026-01-08T09:40:10.138Z
Learning: In openshift-hyperfleet/hyperfleet-api, pkg/api/openapi is a generated directory (excluded in .gitignore) created by `make generate` using openapi-generator-cli via Docker; linters that run before code generation will report false-positive import errors for this package.

Applied to files:

  • Makefile
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0

Applied to files:

  • Makefile
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files

Applied to files:

  • Makefile
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Applied to files:

  • Makefile
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Use Podman to run openapi-generator-cli v7.16.0 via make generate to ensure version consistency and avoid environment-specific issues

Applied to files:

  • Makefile
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment

Applied to files:

  • Makefile
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress

Applied to files:

  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to **/*.go : Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)

Applied to files:

  • Makefile
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Environment-based configuration: use OCM_ENV variable to select development, unit_testing, integration_testing, or production configuration

Applied to files:

  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to test/integration/**/*_test.go : All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation

Applied to files:

  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags

Applied to files:

  • Dockerfile
🪛 checkmake (0.2.2)
Makefile

[warning] 228-228: Target body for "generate" exceeds allowed length of 5 (15).

(maxbodylength)

🔇 Additional comments (8)
Makefile (4)

7-8: LGTM!

The conditional assignment pattern allows the Dockerfile to override CGO_ENABLED for Alpine-based builds while preserving the FIPS-compliant default for local development. Good documentation in the comment.


81-83: LGTM!

Good use of ?= for build metadata variables, enabling both CI and Dockerfile overrides while providing sensible defaults from git.


255-256: LGTM!

Good backward compatibility by aliasing generate-vendor to generate now that oapi-codegen handles dependencies natively.


315-319: LGTM!

Propagating GIT_SHA and GIT_DIRTY as build args improves image traceability. The BASE_IMAGE override for dev builds enables Alpine-based images.

Also applies to: 343-348

Dockerfile (4)

19-19: Verify FIPS compliance requirement with CGO_ENABLED=0.

The Makefile comment states CGO is required for FIPS-compliant crypto (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto). Hardcoding CGO_ENABLED=0 disables BoringCrypto and breaks FIPS compliance for production images.

If FIPS is required for production:

  1. Use CGO_ENABLED=1 GOEXPERIMENT=boringcrypto
  2. Switch to a glibc-based runtime image (e.g., gcr.io/distroless/base-debian12 or UBI) since static linking with CGO requires musl or glibc

If FIPS is only required for certain deployments, consider parameterizing via build arg.

Based on learnings, the project requires FIPS-compliant crypto. Please confirm whether the container image needs FIPS compliance or if this is acceptable for dev/non-FedRAMP deployments.


1-1: LGTM!

The BASE_IMAGE ARG pattern is well-designed — distroless for production security, overridable to Alpine for dev builds via --build-arg BASE_IMAGE=alpine:3.21.

Also applies to: 22-22


27-33: LGTM!

Binary and OpenAPI schema paths are correctly updated. The OPENAPI_SCHEMA_PATH env var enables Helm-based overrides for provider-specific schemas.


40-44: LGTM!

Good addition of OCI labels for image metadata. Consider adding org.opencontainers.image.* labels for broader tooling compatibility in a follow-up.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @Dockerfile:
- Around line 6-7: The Dockerfile declares ARGs GIT_SHA and GIT_DIRTY but never
forwards them into the build, so the Makefile fallback GIT_SHA ?= $(shell git
rev-parse ...) runs inside the container and yields "unknown"; change the RUN
that invokes make (e.g., the make build invocation) to pass the ARG values into
make by appending GIT_SHA="$GIT_SHA" and GIT_DIRTY="$GIT_DIRTY" (and update any
other make invocations similarly), ensuring the Makefile receives the values
instead of attempting to read .git inside the container.
- Line 4: Change the base image from golang:1.25 to golang:1.24 by updating the
FROM line, and enable FIPS-compliant crypto by setting the build environment to
CGO_ENABLED=1 GOEXPERIMENT=boringcrypto where you currently set CGO_ENABLED=0;
locate the FROM instruction and the build environment/ARG or RUN line that
exports CGO_ENABLED and replace those values accordingly to use Go 1.24 and the
boringcrypto experiment.
🧹 Nitpick comments (2)
Makefile (1)

227-244: Consider extracting helpers.go to a separate file.

Embedding Go code in a printf within the Makefile works but is fragile—escaping issues and maintenance become harder over time. Consider creating a openapi/helpers.go.tmpl or scripts/helpers.go file and copying it instead.

♻️ Proposed refactor: use a template file

Create openapi/helpers.go.tmpl:

package openapi

// Ptr returns a pointer to the given value.
func Ptr[T any](v T) *T { return &v }

// PtrString returns a pointer to the given string.
func PtrString(v string) *string { return &v }

// PtrInt32 returns a pointer to the given int32.
func PtrInt32(v int32) *int32 { return &v }

Then simplify the Makefile:

 generate: $(OAPI_CODEGEN)
 	rm -rf pkg/api/openapi
 	mkdir -p pkg/api/openapi
 	$(OAPI_CODEGEN) --config openapi/oapi-codegen.yaml openapi/openapi.yaml
-	@printf '%s\n' \
-		'package openapi' \
-		'' \
-		'// Ptr returns a pointer to the given value.' \
-		'func Ptr[T any](v T) *T { return &v }' \
-		'' \
-		'// PtrString returns a pointer to the given string.' \
-		'func PtrString(v string) *string { return &v }' \
-		'' \
-		'// PtrInt32 returns a pointer to the given int32.' \
-		'func PtrInt32(v int32) *int32 { return &v }' \
-		> pkg/api/openapi/helpers.go
+	cp openapi/helpers.go.tmpl pkg/api/openapi/helpers.go
 .PHONY: generate
.dockerignore (1)

1-8: Consider adding secrets/ to prevent accidental exposure.

The Makefile creates a secrets/ directory with database credentials and service tokens. While this directory may not exist in the repository, it could be created locally and inadvertently included in the Docker build context.

♻️ Proposed addition
 .git
 .gitignore
 .github
 bin/
 docs/
 charts/
 .env
 .env.*
+secrets/
+*.md
+test/
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f04dc61 and 4367834.

📒 Files selected for processing (3)
  • .dockerignore
  • Dockerfile
  • Makefile
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/errors/errors.go:9-9
Timestamp: 2026-01-08T09:40:10.138Z
Learning: In openshift-hyperfleet/hyperfleet-api, pkg/api/openapi is a generated directory (excluded in .gitignore) created by `make generate` using openapi-generator-cli via Docker; linters that run before code generation will report false-positive import errors for this package.
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/telemetry/otel.go:10-10
Timestamp: 2026-01-13T10:10:24.211Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository (PR #31), the team has decided to keep the OpenTelemetry semantic conventions package at v1.37.0 (go.opentelemetry.io/otel/semconv/v1.37.0) while using the SDK at v1.38.0 in pkg/telemetry/otel.go.
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: go.mod:32-36
Timestamp: 2026-01-13T04:19:50.012Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository, the team has decided to keep OpenTelemetry core packages (go.opentelemetry.io/otel, go.opentelemetry.io/otel/sdk, go.opentelemetry.io/otel/trace, go.opentelemetry.io/otel/exporters/stdout/stdouttrace) at v1.38.0 rather than upgrading to v1.39.0 in PR #31.
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Use Podman to run openapi-generator-cli v7.16.0 via make generate to ensure version consistency and avoid environment-specific issues
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
📚 Learning: 2026-01-08T09:40:10.138Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/errors/errors.go:9-9
Timestamp: 2026-01-08T09:40:10.138Z
Learning: In openshift-hyperfleet/hyperfleet-api, pkg/api/openapi is a generated directory (excluded in .gitignore) created by `make generate` using openapi-generator-cli via Docker; linters that run before code generation will report false-positive import errors for this package.

Applied to files:

  • Dockerfile
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags

Applied to files:

  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment

Applied to files:

  • Dockerfile
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to **/*.go : Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)

Applied to files:

  • Dockerfile
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Use Podman to run openapi-generator-cli v7.16.0 via make generate to ensure version consistency and avoid environment-specific issues

Applied to files:

  • Dockerfile
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0

Applied to files:

  • Dockerfile
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files

Applied to files:

  • Dockerfile
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Applied to files:

  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress

Applied to files:

  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Environment-based configuration: use OCM_ENV variable to select development, unit_testing, integration_testing, or production configuration

Applied to files:

  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to test/integration/**/*_test.go : All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation

Applied to files:

  • Makefile
🪛 checkmake (0.2.2)
Makefile

[warning] 228-228: Target body for "generate" exceeds allowed length of 5 (15).

(maxbodylength)

🔇 Additional comments (7)
Makefile (5)

7-8: LGTM! Good use of conditional assignment.

Using ?= for CGO_ENABLED allows the Dockerfile to override the value (setting CGO_ENABLED=0 for Alpine-based builds that don't have glibc), while keeping the FIPS-compliant default of 1 for local development.


81-83: LGTM! Git metadata extraction is well-handled.

The ?= assignment allows CI systems or Dockerfiles to inject these values, and the fallback to "unknown" when git is unavailable is sensible. The || echo pattern correctly handles missing .git or non-git contexts.


255-256: LGTM! Clean alias for backward compatibility.

Aliasing generate-vendor to generate maintains backward compatibility for scripts or CI pipelines that may still call the old target. Based on learnings, the previous workflow used Podman/Docker for generation, so this alias provides a smooth transition.


315-319: LGTM! Build-args properly propagated.

The GIT_SHA and GIT_DIRTY build-args are correctly passed to the Dockerfile, enabling consistent version metadata in the built image.


343-348: Verify Alpine compatibility with CGO_ENABLED=0.

The dev image uses alpine:3.21 as the base. The Dockerfile sets CGO_ENABLED=0 which produces a statically-linked binary—this is correct for Alpine (musl libc). However, the comment on line 7 mentions FIPS compliance requires CGO_ENABLED=1. Ensure that dev images intentionally skip FIPS compliance.

Dockerfile (2)

22-27: LGTM! Multi-stage build with configurable base image.

Using ${BASE_IMAGE} allows switching between distroless (production) and Alpine (dev) at build time. The distroless default provides a minimal attack surface for production deployments.


37-38: LGTM! Clean entrypoint configuration.

Separating ENTRYPOINT and CMD allows users to override the command (e.g., migrate) while keeping the binary path fixed.

rm -f /local/pkg/api/openapi/go.mod /local/pkg/api/openapi/go.sum && \
rm -rf /local/pkg/api/openapi/test
# OpenAPI generation stage
FROM golang:1.25 AS builder
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Go programming language release golang:1.25 January 2026

💡 Result:

Go 1.25 was released on August 12, 2025. See the official Go blog announcement and the Go 1.25 release notes for details. [1][2]

Sources:
[1] Go blog — "Go 1.25 is released" (Aug 12, 2025).
[2] Go 1.25 Release Notes (go.dev/doc/go1.25).


🏁 Script executed:

cd /dev/shm && find . -name "Dockerfile" -type f 2>/dev/null | head -5

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 137


🏁 Script executed:

git ls-files | grep -i dockerfile

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 89


🏁 Script executed:

cat -n Dockerfile

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 1421


Update Go builder to use 1.24.9 with FIPS-compliant crypto settings.

The Dockerfile uses golang:1.25 and CGO_ENABLED=0, but the project requires Go 1.24.9 with FIPS-compliant crypto enabled. Update line 4 to golang:1.24 and line 19 to CGO_ENABLED=1 GOEXPERIMENT=boringcrypto to comply with project standards.

🤖 Prompt for AI Agents
In @Dockerfile at line 4, Change the base image from golang:1.25 to golang:1.24
by updating the FROM line, and enable FIPS-compliant crypto by setting the build
environment to CGO_ENABLED=1 GOEXPERIMENT=boringcrypto where you currently set
CGO_ENABLED=0; locate the FROM instruction and the build environment/ARG or RUN
line that exports CGO_ENABLED and replace those values accordingly to use Go
1.24 and the boringcrypto experiment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @Makefile:
- Around line 81-83: GIT_DIRTY fallback produces false positives when git is
unavailable; update the Makefile so GIT_DIRTY is only set when git exists and
we're inside a work tree: check that git is callable and that `git rev-parse
--is-inside-work-tree` (or existence of .git) succeeds before running `git diff
--quiet`; otherwise set GIT_DIRTY to empty. Keep the existing GIT_SHA and
build_version concatenation but ensure GIT_DIRTY is "" (not "-modified") in
non-git environments so build_version becomes just the SHA or "unknown".
- Around line 303-307: The build passes GIT_SHA and GIT_DIRTY as build args but
the Dockerfile's ARG GIT_SHA and ARG GIT_DIRTY are never consumed, so embed them
into the image by referencing those args in the Dockerfile (e.g., after ARG
GIT_SHA / ARG GIT_DIRTY add a LABEL like
org.opencontainers.image.revision="$GIT_SHA" and a label or ENV for dirty state
such as org.example.git.dirty="$GIT_DIRTY"); update the Dockerfile to consume
ARG GIT_SHA and ARG GIT_DIRTY in a LABEL or ENV so the values supplied by the
Makefile build command are persisted in the image metadata.

In @test/integration/clusters_test.go:
- Around line 651-654: The test reads listResp.JSON200 into list without
verifying it's non-nil; update the test after calling
client.GetClustersWithResponse to check that listResp.JSON200 is not nil before
using it (as other tests do). Specifically, after GetClustersWithResponse and
the Expect(err) assertion, add a nil assertion on listResp.JSON200 (or on list
after assignment) before accessing list.Items so the test fails clearly if the
response body is absent.
- Around line 202-205: The test accesses resp.JSON200.Items without ensuring
resp.JSON200 is non-nil; add a nil-check before accessing Items (e.g., assert
that resp.JSON200 is not nil) after calling client.GetClustersWithResponse so
the test fails with a clear message instead of panicking; reference the response
from GetClustersWithResponse, assert resp.JSON200 is not nil, then safely assert
on resp.JSON200.Items.
- Around line 533-538: The test may append a nil pointer when building
createdClusters by dereferencing resp.JSON201; update the logic around where
createdClusters is appended (the code that does createdClusters =
append(createdClusters, *resp.JSON201) after creating clusters) to first assert
or guard that resp != nil and resp.JSON201 != nil (use
Expect(resp).NotTo(BeNil()) and Expect(resp.JSON201).NotTo(BeNil()) or an if
check) and only then append the dereferenced value, mirroring the nil-safety
pattern used elsewhere in this test file.
🧹 Nitpick comments (3)
pkg/util/utils.go (1)

57-59: Consider using the existing generic ToPtr function instead.

PtrString duplicates functionality already provided by ToPtr[T any] at lines 8-11. For consistency, consider using util.ToPtr("someString") throughout the codebase instead of introducing a string-specific helper.

That said, PtrString is more explicit and avoids type inference, which may be preferable for readability in some contexts.

pkg/api/presenters/cluster.go (1)

58-61: Consider documenting the Email type semantics.

The toEmail helper performs a direct type cast. This works, but consider adding a brief comment noting that openapi_types.Email is a string alias without validation, so email format validation should occur elsewhere (e.g., at API input boundaries).

pkg/api/presenters/cluster_test.go (1)

394-396: Pointer comparison may not test value equality correctly.

Line 396 compares result.Kind to originalReq.Kind, both of which are *string. This compares pointer addresses rather than the underlying string values. Since util.PtrString creates a new pointer each time, and PresentCluster creates another new pointer, these will always be different pointers even if the values match.

The test currently passes because Gomega's Equal matcher dereferences pointers when comparing, but this is implicit behavior that could be confusing. Consider making the comparison explicit.

✨ Suggested improvement for clarity
 	// Verify data integrity
 	Expect(*result.Id).To(Equal("cluster-roundtrip-123"))
-	Expect(result.Kind).To(Equal(originalReq.Kind))
+	Expect(*result.Kind).To(Equal(*originalReq.Kind))
 	Expect(result.Name).To(Equal(originalReq.Name))
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4367834 and 6e31497.

📒 Files selected for processing (11)
  • Makefile
  • pkg/api/presenters/cluster.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/kind.go
  • pkg/api/presenters/object_reference.go
  • pkg/api/presenters/path.go
  • pkg/errors/errors.go
  • pkg/handlers/validation_test.go
  • pkg/util/utils.go
  • test/integration/adapter_status_test.go
  • test/integration/clusters_test.go
🧰 Additional context used
📓 Path-based instructions (7)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID

Files:

  • pkg/util/utils.go
  • pkg/api/presenters/object_reference.go
  • pkg/api/presenters/path.go
  • pkg/api/presenters/cluster.go
  • pkg/errors/errors.go
  • pkg/api/presenters/kind.go
  • test/integration/adapter_status_test.go
  • pkg/api/presenters/cluster_test.go
  • pkg/handlers/validation_test.go
  • test/integration/clusters_test.go
pkg/api/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment

Files:

  • pkg/api/presenters/object_reference.go
  • pkg/api/presenters/path.go
  • pkg/api/presenters/cluster.go
  • pkg/api/presenters/kind.go
  • pkg/api/presenters/cluster_test.go
test/integration/**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

test/integration/**/*_test.go: Integration tests must use Testcontainers to create isolated PostgreSQL instances for each test suite to ensure no state leakage
All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation

Files:

  • test/integration/adapter_status_test.go
  • test/integration/clusters_test.go
pkg/handlers/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

pkg/handlers/**/*.go: HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table
Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration

Files:

  • pkg/handlers/validation_test.go
pkg/{dao,handlers}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

List operations must support pagination via ListArgs struct with limit, offset, and search parameters

Files:

  • pkg/handlers/validation_test.go
pkg/{handlers,services,dao}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)

Files:

  • pkg/handlers/validation_test.go
pkg/{handlers,services,db}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state

Files:

  • pkg/handlers/validation_test.go
🧠 Learnings (22)
📓 Common learnings
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/errors/errors.go:9-9
Timestamp: 2026-01-08T09:40:10.138Z
Learning: In openshift-hyperfleet/hyperfleet-api, pkg/api/openapi is a generated directory (excluded in .gitignore) created by `make generate` using openapi-generator-cli via Docker; linters that run before code generation will report false-positive import errors for this package.
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: go.mod:32-36
Timestamp: 2026-01-13T04:19:50.012Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository, the team has decided to keep OpenTelemetry core packages (go.opentelemetry.io/otel, go.opentelemetry.io/otel/sdk, go.opentelemetry.io/otel/trace, go.opentelemetry.io/otel/exporters/stdout/stdouttrace) at v1.38.0 rather than upgrading to v1.39.0 in PR #31.
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/telemetry/otel.go:10-10
Timestamp: 2026-01-13T10:10:24.211Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository (PR #31), the team has decided to keep the OpenTelemetry semantic conventions package at v1.37.0 (go.opentelemetry.io/otel/semconv/v1.37.0) while using the SDK at v1.38.0 in pkg/telemetry/otel.go.
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Use Podman to run openapi-generator-cli v7.16.0 via make generate to ensure version consistency and avoid environment-specific issues
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
📚 Learning: 2026-01-13T04:16:08.743Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/middleware/masking.go:28-36
Timestamp: 2026-01-13T04:16:08.743Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository, NewOCMLogger(ctx) is deprecated. Switch to the slog-based logger and use logger.With(ctx, ...) to produce structured, context-aware logs. Replace occurrences of NewOCMLogger(ctx) with logger.With(ctx, ...). Update imports to use the new logger and adjust any tests to expect structured logging behavior.

Applied to files:

  • pkg/util/utils.go
  • pkg/api/presenters/object_reference.go
  • pkg/api/presenters/path.go
  • pkg/api/presenters/cluster.go
  • pkg/errors/errors.go
  • pkg/api/presenters/kind.go
  • test/integration/adapter_status_test.go
  • pkg/api/presenters/cluster_test.go
  • pkg/handlers/validation_test.go
  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T09:40:10.138Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/errors/errors.go:9-9
Timestamp: 2026-01-08T09:40:10.138Z
Learning: In openshift-hyperfleet/hyperfleet-api, pkg/api/openapi is a generated directory (excluded in .gitignore) created by `make generate` using openapi-generator-cli via Docker; linters that run before code generation will report false-positive import errors for this package.

Applied to files:

  • pkg/api/presenters/path.go
  • pkg/errors/errors.go
  • pkg/api/presenters/cluster_test.go
  • Makefile
  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment

Applied to files:

  • pkg/api/presenters/path.go
  • pkg/errors/errors.go
  • pkg/api/presenters/kind.go
  • pkg/api/presenters/cluster_test.go
  • Makefile
  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/services/**/*.go : Calculate aggregate status from adapter conditions and return in status.phase field (Ready, Failed, NotReady)

Applied to files:

  • pkg/api/presenters/cluster.go
  • test/integration/adapter_status_test.go
  • pkg/api/presenters/cluster_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/services/**/*.go : Status aggregation: Phase is 'Ready' if all adapters report Ready=True, 'Failed' if any adapter reports Ready=False, 'NotReady' otherwise

Applied to files:

  • pkg/api/presenters/cluster.go
  • test/integration/adapter_status_test.go
  • pkg/api/presenters/cluster_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{handlers,services,dao}/**/*.go : Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)

Applied to files:

  • pkg/errors/errors.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files

Applied to files:

  • pkg/errors/errors.go
  • Makefile
  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0

Applied to files:

  • pkg/errors/errors.go
  • pkg/api/presenters/cluster_test.go
  • Makefile
  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags

Applied to files:

  • pkg/errors/errors.go
  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/migrate/**/*.go : Use GORM AutoMigrate at startup via ./bin/hyperfleet-api migrate command; migrations are idempotent and track applied migrations

Applied to files:

  • pkg/errors/errors.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/handlers/**/*.go : Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table

Applied to files:

  • test/integration/adapter_status_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to test/integration/**/*_test.go : All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation

Applied to files:

  • test/integration/adapter_status_test.go
  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,db}/**/*.go : Use polymorphic status tables with owner_type + owner_id to support multiple resource types without creating separate status tables

Applied to files:

  • test/integration/adapter_status_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to test/factories/**/*.go : Use test data factories in test/factories/ to provide consistent, reusable test data with builder pattern (e.g., NewClusterBuilder().WithName().Build())

Applied to files:

  • pkg/api/presenters/cluster_test.go
  • pkg/handlers/validation_test.go
  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/handlers/**/*.go : Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes

Applied to files:

  • pkg/api/presenters/cluster_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to **/*.go : Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)

Applied to files:

  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress

Applied to files:

  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Applied to files:

  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Environment-based configuration: use OCM_ENV variable to select development, unit_testing, integration_testing, or production configuration

Applied to files:

  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Use Podman to run openapi-generator-cli v7.16.0 via make generate to ensure version consistency and avoid environment-specific issues

Applied to files:

  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/**/*{auth,middleware}*.go : JWT authentication validates tokens from Red Hat SSO and extracts account ID and username from claims for authorization

Applied to files:

  • test/integration/clusters_test.go
🧬 Code graph analysis (7)
pkg/api/presenters/object_reference.go (1)
pkg/util/utils.go (1)
  • PtrString (59-59)
pkg/api/presenters/path.go (1)
pkg/util/utils.go (1)
  • PtrString (59-59)
pkg/errors/errors.go (1)
pkg/util/utils.go (1)
  • PtrString (59-59)
pkg/api/presenters/kind.go (1)
pkg/util/utils.go (1)
  • PtrString (59-59)
pkg/api/presenters/cluster_test.go (2)
pkg/util/utils.go (1)
  • PtrString (59-59)
pkg/api/presenters/cluster.go (1)
  • ConvertCluster (15-56)
pkg/handlers/validation_test.go (1)
pkg/util/utils.go (1)
  • PtrString (59-59)
test/integration/clusters_test.go (2)
test/helper.go (2)
  • WithAuthToken (308-316)
  • GetAccessTokenFromContext (300-305)
pkg/util/utils.go (1)
  • PtrString (59-59)
🔇 Additional comments (26)
Makefile (6)

7-8: LGTM!

The change to ?= assignment allows the Dockerfile to override CGO_ENABLED for Alpine-based dev images while maintaining the default FIPS-compliant setting. The comment clearly documents this intent.


27-27: LGTM!

The DEV_TAG definition correctly uses the deferred $(GIT_SHA) variable. Make's lazy evaluation ensures the forward reference works properly.


227-231: LGTM!

The generate target cleanly transitions from Docker-based openapi-generator to the bingo-managed oapi-codegen. The pattern of removing and recreating the output directory ensures no stale artifacts remain. Based on learnings, openapi/openapi.yaml is the source of truth.


243-244: LGTM!

Good backward compatibility choice to alias generate-vendor to generate rather than removing it entirely. This prevents breaking existing workflows.


266-266: LGTM!

The clean target correctly includes pkg/api/openapi to match the new generation output location.


331-336: LGTM!

The image-dev target correctly passes BASE_IMAGE=alpine:3.21 for lighter dev images, which aligns with the CGO_ENABLED ?= change allowing override for Alpine compatibility.

pkg/handlers/validation_test.go (2)

119-127: LGTM - loop variable capture is safe with Go 1.22+.

Taking the address of kind inside the loop (&kind) is safe because Go 1.22+ scopes loop variables per iteration. Since the project uses Go 1.24.9 per coding guidelines, this pattern works correctly.


98-107: LGTM - test correctly adapted to pointer-based Kind field.

The test properly uses util.PtrString to construct the pointer value for the Kind field, aligning with the new oapi-codegen generated types.

pkg/errors/errors.go (2)

185-191: LGTM - helper functions correctly migrated to util.PtrString.

The CodeStr and Href functions maintain the same behavior, simply switching to the new util.PtrString helper.


154-183: The Details field type assignment is correct. Test code in clusters_test.go:443-445 confirms that openapi.Error.Details is a pointer to a slice with elements containing Field and Error fields as pointers to strings. The code correctly creates the anonymous struct slice and assigns its pointer to the field.

test/integration/adapter_status_test.go (5)

16-25: LGTM - clean helper function for test data construction.

The newAdapterStatusRequest helper consolidates adapter status creation with sensible defaults. Using time.Now() for ObservedTime is appropriate for integration tests.


38-62: LGTM - test correctly migrated to new API client pattern.

The test properly uses the WithResponse client methods and validates the JSON201 response body for the created status.


219-296: LGTM - thorough idempotency test correctly validates update-not-duplicate behavior.

The test properly verifies that posting the same adapter twice updates the existing status rather than creating a duplicate, validating the upsert semantics of the adapter status endpoint.


298-406: LGTM - comprehensive pagination edge case coverage.

The test covers important edge cases: empty dataset, page beyond total, single item, and pagination consistency (no duplicates/missing items). This aligns well with integration test guidelines.


376-402: The pagination loop implementation is correct.

The pageNum++ operator at line 398 works properly. openapi.QueryParamsPage is a numeric type alias generated by oapi-codegen and supports the increment operator. The pattern is used consistently across multiple integration test files without compilation issues.

Likely an incorrect or invalid review comment.

pkg/api/presenters/object_reference.go (1)

8-20: LGTM - presenter correctly migrated to util.PtrString.

The change is a straightforward migration from openapi.PtrString to util.PtrString, maintaining identical behavior for constructing the ObjectReference.Id field.

pkg/api/presenters/kind.go (1)

1-44: LGTM!

Clean migration from openapi.PtrString to util.PtrString. The helper function semantics are preserved, and the change aligns with the broader PR objective of decoupling from the generated openapi package utilities.

pkg/api/presenters/path.go (1)

1-50: LGTM!

Consistent migration pattern matching kind.go. The util.PtrString usage in ObjectPath is correct.

pkg/api/presenters/cluster.go (2)

38-42: Good defensive default for Kind.

The fallback to "Cluster" when req.Kind is nil ensures backward compatibility and prevents nil pointer dereference. This aligns well with the pointer-based Kind field in the new OpenAPI types.


127-146: The enum conversions are valid and safe. The domain types (api.ResourcePhase and api.ConditionStatus) are string-based enums with constants explicitly defined to match their OpenAPI counterparts. The code comments confirm this (e.g., "matches openapi.NOT_READY"), and comprehensive unit tests in pkg/api/presenters/adapter_status_test.go verify the mappings work correctly. No changes needed.

pkg/api/presenters/cluster_test.go (2)

8-12: LGTM!

Import additions for openapi_types and util are correct and align with the presenter changes.


160-239: Comprehensive test coverage for PresentCluster.

The test thoroughly validates:

  • Basic field mapping (Id, Kind, Href, Name, Generation)
  • Email type conversion for CreatedBy/UpdatedBy
  • Spec and Labels unmarshaling
  • Status phase and conditions conversion
  • Timestamp preservation

Good coverage of the new OpenAPI type changes.

test/integration/clusters_test.go (4)

22-52: LGTM!

The migration to GetClusterByIdWithResponse is well-implemented with proper:

  • Status code assertions via resp.StatusCode()
  • Nil checks on resp.JSON200 before field access
  • Pointer dereferencing for Id, Kind, Href

104-127: LGTM!

Clean migration of paging tests to GetClustersWithResponse with properly constructed GetClustersParams. The use of type aliases openapi.QueryParamsPage and openapi.QueryParamsPageSize aligns with the generated client types.


443-450: Good defensive nil handling for error details.

The nested nil checks for errorResponse.Details and detail.Field properly handle optional fields in the error response, preventing panics when iterating over validation error details.


54-87: LGTM!

The POST test properly demonstrates:

  • Using PostClusterWithResponse with typed request body
  • Extracting response via JSON201 with nil check
  • Fallback to raw resty request for invalid JSON testing
  • Using test.GetAccessTokenFromContext helper for auth

Comment on lines +81 to +83
GIT_SHA ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
GIT_DIRTY ?= $(shell git diff --quiet 2>/dev/null || echo "-modified")
build_version:=$(GIT_SHA)$(GIT_DIRTY)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Minor edge case: GIT_DIRTY may show false positive in non-git environments.

When git is unavailable (e.g., building from a tarball), git diff --quiet fails and triggers the fallback echo "-modified", resulting in unknown-modified version strings. Consider guarding the dirty check:

Suggested fix
-GIT_DIRTY ?= $(shell git diff --quiet 2>/dev/null || echo "-modified")
+GIT_DIRTY ?= $(shell git rev-parse --git-dir >/dev/null 2>&1 && { git diff --quiet 2>/dev/null || echo "-modified"; } || echo "")
🤖 Prompt for AI Agents
In @Makefile around lines 81 - 83, GIT_DIRTY fallback produces false positives
when git is unavailable; update the Makefile so GIT_DIRTY is only set when git
exists and we're inside a work tree: check that git is callable and that `git
rev-parse --is-inside-work-tree` (or existence of .git) succeeds before running
`git diff --quiet`; otherwise set GIT_DIRTY to empty. Keep the existing GIT_SHA
and build_version concatenation but ensure GIT_DIRTY is "" (not "-modified") in
non-git environments so build_version becomes just the SHA or "unknown".

Comment on lines +303 to +307
$(container_tool) build \
--platform linux/amd64 \
--build-arg GIT_SHA=$(GIT_SHA) \
--build-arg GIT_DIRTY=$(GIT_DIRTY) \
-t $(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG) .
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, find the Dockerfile
find . -name "Dockerfile" -type f | head -20

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 91


🏁 Script executed:

#!/bin/bash
# Verify Dockerfile accepts GIT_SHA and GIT_DIRTY build arguments
echo "Checking Dockerfile for ARG declarations..."
rg -n "^ARG (GIT_SHA|GIT_DIRTY|BASE_IMAGE)" Dockerfile
echo ""
echo "Checking how these args are used in the build:"
rg -n "GIT_SHA|GIT_DIRTY" Dockerfile

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 311


🏁 Script executed:

#!/bin/bash
# Read the full Dockerfile to see actual usage of the build args
cat -n Dockerfile | head -40
echo ""
echo "Searching for variable interpolation of these args:"
rg -n '\$\{?GIT_SHA\}?|\$\{?GIT_DIRTY\}?' Dockerfile

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 1257


🏁 Script executed:

#!/bin/bash
# Check if there's more content in Dockerfile
wc -l Dockerfile
echo ""
echo "Get the rest of the file:"
tail -n 20 Dockerfile

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 789


GIT_SHA and GIT_DIRTY build arguments are declared but unused in the Dockerfile.

The Dockerfile declares ARG GIT_SHA and ARG GIT_DIRTY (lines 6-7), but these arguments are never referenced anywhere in the build process. They are not embedded in ENV statements, LABEL entries, or used in any RUN commands. This means the version information passed from the Makefile is lost and won't be embedded in the container image. Add usage of these arguments (e.g., in a LABEL or ENV statement) to properly embed version metadata in the built image.

🤖 Prompt for AI Agents
In @Makefile around lines 303 - 307, The build passes GIT_SHA and GIT_DIRTY as
build args but the Dockerfile's ARG GIT_SHA and ARG GIT_DIRTY are never
consumed, so embed them into the image by referencing those args in the
Dockerfile (e.g., after ARG GIT_SHA / ARG GIT_DIRTY add a LABEL like
org.opencontainers.image.revision="$GIT_SHA" and a label or ENV for dirty state
such as org.example.git.dirty="$GIT_DIRTY"); update the Dockerfile to consume
ARG GIT_SHA and ARG GIT_DIRTY in a LABEL or ENV so the values supplied by the
Makefile build command are persisted in the image metadata.

Comment on lines 533 to +538

// List clusters without orderBy parameter - should default to created_time desc
list, _, err := client.DefaultAPI.GetClusters(ctx).Execute()
listResp, err := client.GetClustersWithResponse(ctx, nil, test.WithAuthToken(ctx))
Expect(err).NotTo(HaveOccurred(), "Failed to list clusters")
list := listResp.JSON200
Expect(list).NotTo(BeNil())
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential nil dereference when building createdClusters list.

Line 528 appends *resp.JSON201 to createdClusters. While the test expects StatusCreated, if the response unexpectedly contains a nil JSON201, this would panic. Consider adding a nil check for safety, consistent with patterns used elsewhere in this file.

🐛 Suggested fix
 		resp, err := client.PostClusterWithResponse(ctx, openapi.PostClusterJSONRequestBody(clusterInput), test.WithAuthToken(ctx))
 		Expect(err).NotTo(HaveOccurred(), "Failed to create cluster %d", i)
+		Expect(resp.JSON201).NotTo(BeNil(), "Expected JSON201 response for cluster %d", i)
 		createdClusters = append(createdClusters, *resp.JSON201)
🤖 Prompt for AI Agents
In @test/integration/clusters_test.go around lines 533 - 538, The test may
append a nil pointer when building createdClusters by dereferencing
resp.JSON201; update the logic around where createdClusters is appended (the
code that does createdClusters = append(createdClusters, *resp.JSON201) after
creating clusters) to first assert or guard that resp != nil and resp.JSON201 !=
nil (use Expect(resp).NotTo(BeNil()) and Expect(resp.JSON201).NotTo(BeNil()) or
an if check) and only then append the dereferenced value, mirroring the
nil-safety pattern used elsewhere in this test file.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/api/presenters/cluster_test.go (1)

394-399: Pointer comparison at line 396 may not produce expected results.

Comparing result.Kind (returned from PresentCluster) directly to originalReq.Kind (from test input) compares pointer addresses, not string values. Since these are different allocations, this comparison might fail unexpectedly.

🔧 Suggested fix: Dereference pointers for value comparison
 	// Verify data integrity
 	Expect(*result.Id).To(Equal("cluster-roundtrip-123"))
-	Expect(result.Kind).To(Equal(originalReq.Kind))
+	Expect(*result.Kind).To(Equal(*originalReq.Kind))
 	Expect(result.Name).To(Equal(originalReq.Name))
🤖 Fix all issues with AI agents
In @Dockerfile:
- Line 19: The Dockerfile currently forces CGO_DISABLED by running the build
with "CGO_ENABLED=0", which prevents enabling boringcrypto for FIPS; update the
build invocation used to produce the binary (the RUN line that executes make
build) to export CGO_ENABLED=1 and set GOEXPERIMENT=boringcrypto so the Go build
can use cgo/boringcrypto for FIPS-compliant crypto, and ensure the Docker base
image is changed to one with glibc (not distroless/static) to support dynamic
linking; alternatively, if FIPS is not required, update the coding guidelines to
reflect CGO_ENABLED=0 as acceptable.

In @openapi/oapi-codegen.yaml:
- Around line 1-17: This file (oapi-codegen.yaml) uses oapi-codegen options like
generate.models and output-options.old-aliasing and must be removed and replaced
by a TypeSpec-based workflow: stop using oapi-codegen.yaml, add a TypeSpec API
spec at openapi/openapi.yaml (the only editable source of truth), configure
codegen to use openapi-generator-cli v7.16.0 in your build/CI scripts (replacing
any oapi-codegen invocation), and update generation settings to produce the
client/server/models equivalent to generate.models and client from the old
config; also remove or migrate any code that depended on oapi-codegen-specific
behaviors (e.g., old-merge-schemas/old-aliasing) so the project builds with the
new generator.

In @test/integration/clusters_test.go:
- Around line 301-303: The test accesses getResp.JSON200.Spec without ensuring
getResp.JSON200 is non-nil; add a nil check after the call to
GetClusterByIdWithResponse (check getResp and getResp.JSON200) and fail the test
or Expect them to be non-nil before asserting len(getResp.JSON200.Spec) == 100.
Specifically, after GetClusterByIdWithResponse and the existing err check, add
Expect(getResp).NotTo(BeNil()) and Expect(getResp.JSON200).NotTo(BeNil()) (or an
if guard that calls Fail/Expect) so accessing getResp.JSON200.Spec is safe.
- Around line 526-528: The test dereferences resp.JSON201 without verifying the
HTTP status or that JSON201 is non-nil, which can panic if the POST fails; after
the client.PostClusterWithResponse call and Err check, assert the response
status is 201 (or use resp.StatusCode/resp.Status) and add
Expect(resp.JSON201).NotTo(BeNil()) before appending, then safely append
*resp.JSON201 to createdClusters; reference resp, resp.JSON201 and
client.PostClusterWithResponse in the changes.
- Around line 233-236: The test accesses getResp.JSON200.Name without ensuring
JSON200 is non-nil; update the assertion after calling
GetClusterByIdWithResponse (in the block using GetClusterByIdWithResponse,
getResp and id1) to first verify getResp.JSON200 is not nil (e.g.,
Expect(getResp.JSON200).NotTo(BeNil())) before asserting on getResp.JSON200.Name
to avoid nil dereference.
- Around line 202-205: After calling GetClustersWithResponse, add a nil check
for resp.JSON200 before accessing Items to avoid a nil pointer dereference;
specifically, in the test after resp, err = client.GetClustersWithResponse(...),
confirm resp != nil and resp.JSON200 != nil (or handle non-200 cases) and only
then assert on len(resp.JSON200.Items) or use
Expect(resp.StatusCode()).To(Equal(200)) prior to inspecting JSON200 so the test
safely handles non-200 responses.
🧹 Nitpick comments (5)
pkg/handlers/validation_test.go (1)

119-127: Consider consistency and adding a nil test case.

Two observations:

  1. Style inconsistency: Uses &kind while other test functions use util.PtrString(). While safe in Go 1.22+, using util.PtrString(kind) would be more consistent.

  2. Missing edge case: There's no test for Kind: nil. A nil pointer (field not provided) is semantically different from a pointer to an empty string (field explicitly set to empty), and the validator may need to handle both.

Suggested improvements
 	for _, kind := range invalidKinds {
 		req := openapi.ClusterCreateRequest{
-			Kind: &kind,
+			Kind: util.PtrString(kind),
 		}

Consider adding a separate test for nil:

func TestValidateKind_Nil(t *testing.T) {
	RegisterTestingT(t)

	req := openapi.ClusterCreateRequest{
		Kind: nil,
	}
	validator := validateKind(&req, "Kind", "kind", "Cluster")
	err := validator()
	Expect(err).ToNot(BeNil())
	Expect(err.Reason).To(ContainSubstring("required"))
}
Dockerfile (1)

6-7: Unused build arguments.

GIT_SHA and GIT_DIRTY are declared but never used in the build. Either remove them or pass them to the build command (e.g., via ldflags for version embedding).

♻️ Suggested fix if version embedding is intended
 # Build binary
-RUN CGO_ENABLED=0 GOOS=linux make build
+RUN CGO_ENABLED=0 GOOS=linux GIT_SHA=${GIT_SHA} GIT_DIRTY=${GIT_DIRTY} make build

Or remove the unused ARGs if not needed.

pkg/api/presenters/adapter_status.go (1)

114-139: Consider extracting the inline metadata struct to reduce duplication.

The inline struct is defined twice (lines 114-121 and 124-131). While this works, extracting it to a local named type would improve readability.

♻️ Optional refactor to reduce duplication
+	type metadataPayload struct {
+		Attempt       *int32     `json:"attempt,omitempty"`
+		CompletedTime *time.Time `json:"completed_time,omitempty"`
+		Duration      *string    `json:"duration,omitempty"`
+		JobName       *string    `json:"job_name,omitempty"`
+		JobNamespace  *string    `json:"job_namespace,omitempty"`
+		StartedTime   *time.Time `json:"started_time,omitempty"`
+	}
+
-	var openapiMetadata *struct {
-		Attempt       *int32     `json:"attempt,omitempty"`
-		CompletedTime *time.Time `json:"completed_time,omitempty"`
-		Duration      *string    `json:"duration,omitempty"`
-		JobName       *string    `json:"job_name,omitempty"`
-		JobNamespace  *string    `json:"job_namespace,omitempty"`
-		StartedTime   *time.Time `json:"started_time,omitempty"`
-	}
+	var openapiMetadata *metadataPayload

	if metadata != nil {
-		openapiMetadata = &struct {
-			Attempt       *int32     `json:"attempt,omitempty"`
-			CompletedTime *time.Time `json:"completed_time,omitempty"`
-			Duration      *string    `json:"duration,omitempty"`
-			JobName       *string    `json:"job_name,omitempty"`
-			JobNamespace  *string    `json:"job_namespace,omitempty"`
-			StartedTime   *time.Time `json:"started_time,omitempty"`
-		}{
+		openapiMetadata = &metadataPayload{
			Attempt:       metadata.Attempt,
			CompletedTime: metadata.CompletedTime,
			Duration:      metadata.Duration,
			JobName:       metadata.JobName,
			JobNamespace:  metadata.JobNamespace,
			StartedTime:   metadata.StartedTime,
		}
	}
pkg/api/presenters/adapter_status_test.go (1)

261-270: Consider extracting repeated inline struct definition to a type alias or helper.

The inline struct for Metadata is defined identically in multiple test locations (lines 25-34, 86-88, and here). While acceptable for tests, a local type alias could reduce duplication and make future changes easier.

💡 Optional: Extract metadata struct type
// At package level or in a test helper file
type testAdapterStatusMetadata struct {
    Attempt       *int32     `json:"attempt,omitempty"`
    CompletedTime *time.Time `json:"completed_time,omitempty"`
    Duration      *string    `json:"duration,omitempty"`
    JobName       *string    `json:"job_name,omitempty"`
    JobNamespace  *string    `json:"job_namespace,omitempty"`
    StartedTime   *time.Time `json:"started_time,omitempty"`
}
test/integration/clusters_test.go (1)

584-587: Consider adding status check for cluster creation in loop.

While the response is discarded here, adding a status check would catch creation failures early.

💡 Optional: Add status assertion
 		_, err := client.PostClusterWithResponse(ctx, openapi.PostClusterJSONRequestBody(clusterInput), test.WithAuthToken(ctx))
 		Expect(err).NotTo(HaveOccurred(), "Failed to create cluster %s", name)
+		// Consider: Expect(resp.StatusCode()).To(Equal(http.StatusCreated))
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e31497 and 8fba87c.

⛔ Files ignored due to path filters (2)
  • .bingo/oapi-codegen.sum is excluded by !**/*.sum
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (41)
  • .bingo/Variables.mk
  • .bingo/oapi-codegen.mod
  • .bingo/variables.env
  • .claude/settings.local.json
  • .dockerignore
  • Dockerfile
  • Dockerfile.openapi
  • Dockerfile.openapi.dockerignore
  • Makefile
  • go.mod
  • openapi/oapi-codegen.yaml
  • openapi/openapi.yaml
  • openapitools.json
  • pkg/api/adapter_status_types.go
  • pkg/api/openapi_embed.go
  • pkg/api/presenters/adapter_status.go
  • pkg/api/presenters/adapter_status_test.go
  • pkg/api/presenters/cluster.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/kind.go
  • pkg/api/presenters/node_pool.go
  • pkg/api/presenters/node_pool_test.go
  • pkg/api/presenters/object_reference.go
  • pkg/api/presenters/path.go
  • pkg/errors/errors.go
  • pkg/handlers/cluster.go
  • pkg/handlers/cluster_nodepools.go
  • pkg/handlers/cluster_nodepools_test.go
  • pkg/handlers/node_pool.go
  • pkg/handlers/openapi.go
  • pkg/handlers/validation_test.go
  • pkg/util/utils.go
  • test/factories/clusters.go
  • test/factories/node_pools.go
  • test/helper.go
  • test/integration/adapter_status_test.go
  • test/integration/api_contract_test.go
  • test/integration/clusters_test.go
  • test/integration/node_pools_test.go
  • test/integration/search_field_mapping_test.go
  • test/registration.go
💤 Files with no reviewable changes (4)
  • Dockerfile.openapi.dockerignore
  • Dockerfile.openapi
  • pkg/api/openapi_embed.go
  • openapitools.json
✅ Files skipped from review due to trivial changes (1)
  • .claude/settings.local.json
🚧 Files skipped from review as they are similar to previous changes (10)
  • test/integration/api_contract_test.go
  • pkg/api/presenters/object_reference.go
  • .bingo/Variables.mk
  • .dockerignore
  • pkg/api/adapter_status_types.go
  • pkg/handlers/openapi.go
  • pkg/handlers/node_pool.go
  • pkg/util/utils.go
  • test/registration.go
  • pkg/handlers/cluster_nodepools.go
🧰 Additional context used
📓 Path-based instructions (9)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)
Use structured logging via logger.NewOCMLogger(ctx) with context-aware log fields including operation ID, account ID, and transaction ID

Files:

  • pkg/handlers/cluster.go
  • pkg/errors/errors.go
  • test/factories/clusters.go
  • test/factories/node_pools.go
  • test/integration/adapter_status_test.go
  • test/integration/search_field_mapping_test.go
  • test/helper.go
  • pkg/handlers/validation_test.go
  • pkg/handlers/cluster_nodepools_test.go
  • pkg/api/presenters/node_pool_test.go
  • pkg/api/presenters/adapter_status_test.go
  • test/integration/clusters_test.go
  • test/integration/node_pools_test.go
  • pkg/api/presenters/path.go
  • pkg/api/presenters/adapter_status.go
  • pkg/api/presenters/kind.go
  • pkg/api/presenters/node_pool.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/cluster.go
pkg/handlers/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

pkg/handlers/**/*.go: HTTP handlers must follow the pattern: parse request → call service/DAO → handle errors → send response with appropriate HTTP status codes
Database transactions are automatically managed by TransactionMiddleware for all HTTP requests; store session in context and auto-commit on success, rollback on error
Accept resource creation/update/delete requests via REST endpoints, validate, and persist to PostgreSQL
Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table
Serve resource data to Sentinel via GET /{resourceType} endpoints with pagination and filtering support
Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes
Prometheus metrics are exposed at GET /metrics endpoint for monitoring; configure metric collection via --label-metrics-inclusion-duration

Files:

  • pkg/handlers/cluster.go
  • pkg/handlers/validation_test.go
  • pkg/handlers/cluster_nodepools_test.go
pkg/{dao,handlers}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

List operations must support pagination via ListArgs struct with limit, offset, and search parameters

Files:

  • pkg/handlers/cluster.go
  • pkg/handlers/validation_test.go
  • pkg/handlers/cluster_nodepools_test.go
pkg/{handlers,services,dao}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)

Files:

  • pkg/handlers/cluster.go
  • pkg/handlers/validation_test.go
  • pkg/handlers/cluster_nodepools_test.go
pkg/{handlers,services,db}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use context values for passing request-scoped data (session, operation ID, user info) rather than function parameters or global state

Files:

  • pkg/handlers/cluster.go
  • pkg/handlers/validation_test.go
  • pkg/handlers/cluster_nodepools_test.go
test/factories/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use test data factories in test/factories/ to provide consistent, reusable test data with builder pattern (e.g., NewClusterBuilder().WithName().Build())

Files:

  • test/factories/clusters.go
  • test/factories/node_pools.go
test/integration/**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

test/integration/**/*_test.go: Integration tests must use Testcontainers to create isolated PostgreSQL instances for each test suite to ensure no state leakage
All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation

Files:

  • test/integration/adapter_status_test.go
  • test/integration/search_field_mapping_test.go
  • test/integration/clusters_test.go
  • test/integration/node_pools_test.go
pkg/api/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment

Files:

  • pkg/api/presenters/node_pool_test.go
  • pkg/api/presenters/adapter_status_test.go
  • pkg/api/presenters/path.go
  • pkg/api/presenters/adapter_status.go
  • pkg/api/presenters/kind.go
  • pkg/api/presenters/node_pool.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/cluster.go
openapi/**/*.yaml

📄 CodeRabbit inference engine (AGENTS.md)

openapi/**/*.yaml: Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0
Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Files:

  • openapi/oapi-codegen.yaml
  • openapi/openapi.yaml
🧠 Learnings (27)
📓 Common learnings
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/errors/errors.go:9-9
Timestamp: 2026-01-08T09:40:10.138Z
Learning: In openshift-hyperfleet/hyperfleet-api, pkg/api/openapi is a generated directory (excluded in .gitignore) created by `make generate` using openapi-generator-cli via Docker; linters that run before code generation will report false-positive import errors for this package.
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/telemetry/otel.go:10-10
Timestamp: 2026-01-13T10:10:24.211Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository (PR #31), the team has decided to keep the OpenTelemetry semantic conventions package at v1.37.0 (go.opentelemetry.io/otel/semconv/v1.37.0) while using the SDK at v1.38.0 in pkg/telemetry/otel.go.
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: go.mod:32-36
Timestamp: 2026-01-13T04:19:50.012Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository, the team has decided to keep OpenTelemetry core packages (go.opentelemetry.io/otel, go.opentelemetry.io/otel/sdk, go.opentelemetry.io/otel/trace, go.opentelemetry.io/otel/exporters/stdout/stdouttrace) at v1.38.0 rather than upgrading to v1.39.0 in PR #31.
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Use Podman to run openapi-generator-cli v7.16.0 via make generate to ensure version consistency and avoid environment-specific issues
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress
📚 Learning: 2026-01-13T04:16:08.743Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/middleware/masking.go:28-36
Timestamp: 2026-01-13T04:16:08.743Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository, NewOCMLogger(ctx) is deprecated. Switch to the slog-based logger and use logger.With(ctx, ...) to produce structured, context-aware logs. Replace occurrences of NewOCMLogger(ctx) with logger.With(ctx, ...). Update imports to use the new logger and adjust any tests to expect structured logging behavior.

Applied to files:

  • pkg/handlers/cluster.go
  • pkg/errors/errors.go
  • test/factories/clusters.go
  • test/factories/node_pools.go
  • test/integration/adapter_status_test.go
  • test/integration/search_field_mapping_test.go
  • test/helper.go
  • pkg/handlers/validation_test.go
  • pkg/handlers/cluster_nodepools_test.go
  • pkg/api/presenters/node_pool_test.go
  • pkg/api/presenters/adapter_status_test.go
  • test/integration/clusters_test.go
  • test/integration/node_pools_test.go
  • pkg/api/presenters/path.go
  • pkg/api/presenters/adapter_status.go
  • pkg/api/presenters/kind.go
  • pkg/api/presenters/node_pool.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/cluster.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{handlers,services,dao}/**/*.go : Errors must use structured ServiceError type from pkg/errors/ with HttpCode, Code, and Reason fields; send via errors.SendError(w, r, err)

Applied to files:

  • pkg/errors/errors.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/openapi/model_*.go : Generated Go models from openapi-generator-cli include JSON tags and validation metadata; do not manually edit generated model_*.go files

Applied to files:

  • pkg/errors/errors.go
  • .bingo/variables.env
  • go.mod
  • test/helper.go
  • .bingo/oapi-codegen.mod
  • pkg/api/presenters/node_pool_test.go
  • pkg/api/presenters/path.go
  • openapi/oapi-codegen.yaml
  • pkg/api/presenters/kind.go
  • Makefile
  • pkg/api/presenters/cluster_test.go
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Use TypeSpec for API specification, which compiles to OpenAPI 3.0.3, then generates Go models via openapi-generator-cli v7.16.0

Applied to files:

  • pkg/errors/errors.go
  • .bingo/variables.env
  • go.mod
  • .bingo/oapi-codegen.mod
  • pkg/api/presenters/node_pool_test.go
  • openapi/oapi-codegen.yaml
  • pkg/api/presenters/kind.go
  • Makefile
  • pkg/api/presenters/cluster_test.go
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/api/**/*.go : Embed OpenAPI specification at compile time using Go 1.16+ //go:embed directive for self-contained binary deployment

Applied to files:

  • pkg/errors/errors.go
  • .bingo/variables.env
  • go.mod
  • test/helper.go
  • .bingo/oapi-codegen.mod
  • pkg/api/presenters/node_pool_test.go
  • test/integration/clusters_test.go
  • pkg/api/presenters/path.go
  • openapi/oapi-codegen.yaml
  • pkg/api/presenters/kind.go
  • Makefile
  • pkg/api/presenters/cluster_test.go
  • Dockerfile
📚 Learning: 2026-01-08T09:40:10.138Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/errors/errors.go:9-9
Timestamp: 2026-01-08T09:40:10.138Z
Learning: In openshift-hyperfleet/hyperfleet-api, pkg/api/openapi is a generated directory (excluded in .gitignore) created by `make generate` using openapi-generator-cli via Docker; linters that run before code generation will report false-positive import errors for this package.

Applied to files:

  • pkg/errors/errors.go
  • .bingo/variables.env
  • go.mod
  • .bingo/oapi-codegen.mod
  • pkg/api/presenters/node_pool_test.go
  • test/integration/clusters_test.go
  • pkg/api/presenters/path.go
  • openapi/oapi-codegen.yaml
  • Makefile
  • pkg/api/presenters/cluster_test.go
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/serve/**/*.go : API server runs on port 8000, metrics endpoint on 8080, health check on 8083; these are configurable via CLI flags

Applied to files:

  • pkg/errors/errors.go
  • test/integration/clusters_test.go
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/migrate/**/*.go : Use GORM AutoMigrate at startup via ./bin/hyperfleet-api migrate command; migrations are idempotent and track applied migrations

Applied to files:

  • pkg/errors/errors.go
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to test/factories/**/*.go : Use test data factories in test/factories/ to provide consistent, reusable test data with builder pattern (e.g., NewClusterBuilder().WithName().Build())

Applied to files:

  • test/factories/clusters.go
  • test/factories/node_pools.go
  • test/integration/clusters_test.go
  • pkg/api/presenters/cluster_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to cmd/hyperfleet/environments/**/*.go : Environment-based configuration: use OCM_ENV variable to select development, unit_testing, integration_testing, or production configuration

Applied to files:

  • .bingo/variables.env
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to **/*.go : Use Go 1.24.9 with FIPS-compliant crypto enabled (CGO_ENABLED=1, GOEXPERIMENT=boringcrypto)

Applied to files:

  • .bingo/variables.env
  • go.mod
  • Makefile
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Use Podman to run openapi-generator-cli v7.16.0 via make generate to ensure version consistency and avoid environment-specific issues

Applied to files:

  • .bingo/variables.env
  • Makefile
  • Dockerfile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{db/migrations,dao}/**/*.go : NodePool owner_references.id must enforce foreign key relationship to parent cluster to maintain referential integrity

Applied to files:

  • test/factories/node_pools.go
  • pkg/handlers/cluster_nodepools_test.go
  • pkg/api/presenters/node_pool_test.go
  • test/integration/node_pools_test.go
  • pkg/api/presenters/node_pool.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/handlers/**/*.go : Accept status updates from adapters via POST /{resourceType}/{id}/statuses and store in adapter_statuses table

Applied to files:

  • test/integration/adapter_status_test.go
  • pkg/api/presenters/adapter_status_test.go
  • pkg/api/presenters/adapter_status.go
  • openapi/openapi.yaml
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/services/**/*.go : Calculate aggregate status from adapter conditions and return in status.phase field (Ready, Failed, NotReady)

Applied to files:

  • test/integration/adapter_status_test.go
  • test/integration/search_field_mapping_test.go
  • pkg/api/presenters/node_pool_test.go
  • pkg/api/presenters/adapter_status_test.go
  • pkg/api/presenters/adapter_status.go
  • pkg/api/presenters/node_pool.go
  • pkg/api/presenters/cluster_test.go
  • openapi/openapi.yaml
  • pkg/api/presenters/cluster.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/services/**/*.go : Status aggregation: Phase is 'Ready' if all adapters report Ready=True, 'Failed' if any adapter reports Ready=False, 'NotReady' otherwise

Applied to files:

  • test/integration/adapter_status_test.go
  • test/integration/search_field_mapping_test.go
  • pkg/api/presenters/node_pool_test.go
  • pkg/api/presenters/adapter_status_test.go
  • pkg/api/presenters/adapter_status.go
  • pkg/api/presenters/cluster_test.go
  • pkg/api/presenters/cluster.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to test/integration/**/*_test.go : All API endpoints must have integration test coverage in test/integration/ including CRUD operations, pagination, search, error cases, and status aggregation

Applied to files:

  • test/integration/adapter_status_test.go
  • test/integration/search_field_mapping_test.go
  • test/integration/clusters_test.go
  • test/integration/node_pools_test.go
  • pkg/api/presenters/cluster_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,services}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control and track reconciliation progress

Applied to files:

  • go.mod
  • .bingo/oapi-codegen.mod
  • openapi/oapi-codegen.yaml
  • Makefile
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/db/**/*.go : Use PostgreSQL 14.2 with GORM ORM for database operations

Applied to files:

  • go.mod
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,handlers}/**/*.go : List operations must support pagination via ListArgs struct with limit, offset, and search parameters

Applied to files:

  • .bingo/oapi-codegen.mod
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/**/*{auth,middleware}*.go : JWT authentication validates tokens from Red Hat SSO and extracts account ID and username from claims for authorization

Applied to files:

  • test/integration/clusters_test.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/{dao,db}/**/*.go : Use polymorphic status tables with owner_type + owner_id to support multiple resource types without creating separate status tables

Applied to files:

  • pkg/api/presenters/adapter_status.go
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to openapi/**/*.yaml : Only edit openapi/openapi.yaml as the source of truth; pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Applied to files:

  • openapi/oapi-codegen.yaml
  • Makefile
  • Dockerfile
  • openapi/openapi.yaml
📚 Learning: 2026-01-08T01:23:20.647Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T01:23:20.647Z
Learning: Applies to pkg/handlers/**/*.go : Health check endpoint at GET /healthcheck returns 200 OK when database is accessible; used by Kubernetes liveness/readiness probes

Applied to files:

  • pkg/api/presenters/cluster_test.go
📚 Learning: 2026-01-13T10:10:24.211Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/telemetry/otel.go:10-10
Timestamp: 2026-01-13T10:10:24.211Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository (PR #31), the team has decided to keep the OpenTelemetry semantic conventions package at v1.37.0 (go.opentelemetry.io/otel/semconv/v1.37.0) while using the SDK at v1.38.0 in pkg/telemetry/otel.go.

Applied to files:

  • openapi/openapi.yaml
📚 Learning: 2026-01-13T04:19:50.012Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: go.mod:32-36
Timestamp: 2026-01-13T04:19:50.012Z
Learning: In the openshift-hyperfleet/hyperfleet-api repository, the team has decided to keep OpenTelemetry core packages (go.opentelemetry.io/otel, go.opentelemetry.io/otel/sdk, go.opentelemetry.io/otel/trace, go.opentelemetry.io/otel/exporters/stdout/stdouttrace) at v1.38.0 rather than upgrading to v1.39.0 in PR #31.

Applied to files:

  • openapi/openapi.yaml
🧬 Code graph analysis (13)
pkg/handlers/cluster.go (1)
pkg/api/presenters/cluster.go (1)
  • ConvertCluster (15-56)
pkg/errors/errors.go (1)
pkg/util/utils.go (1)
  • PtrString (59-59)
test/factories/node_pools.go (1)
pkg/api/metadata_types.go (1)
  • Meta (37-42)
test/integration/search_field_mapping_test.go (1)
test/helper.go (1)
  • WithAuthToken (328-336)
pkg/handlers/validation_test.go (1)
pkg/util/utils.go (1)
  • PtrString (59-59)
pkg/api/presenters/node_pool_test.go (1)
pkg/api/presenters/node_pool.go (1)
  • ConvertNodePool (13-54)
pkg/api/presenters/adapter_status_test.go (2)
pkg/api/metadata_types.go (1)
  • Metadata (28-34)
pkg/api/status_types.go (3)
  • ConditionTrue (20-20)
  • ConditionFalse (21-21)
  • ConditionUnknown (22-22)
test/integration/clusters_test.go (2)
test/helper.go (2)
  • WithAuthToken (328-336)
  • GetAccessTokenFromContext (320-325)
pkg/util/utils.go (1)
  • PtrString (59-59)
test/integration/node_pools_test.go (1)
test/helper.go (2)
  • WithAuthToken (328-336)
  • GetAccessTokenFromContext (320-325)
pkg/api/presenters/path.go (1)
pkg/util/utils.go (1)
  • PtrString (59-59)
pkg/api/presenters/kind.go (1)
pkg/util/utils.go (1)
  • PtrString (59-59)
pkg/api/presenters/node_pool.go (2)
pkg/api/status_types.go (2)
  • ConditionStatus (17-17)
  • ResourcePhase (7-7)
pkg/api/node_pool_types.go (1)
  • NodePool (12-43)
pkg/api/presenters/cluster_test.go (2)
pkg/util/utils.go (1)
  • PtrString (59-59)
pkg/api/presenters/cluster.go (1)
  • ConvertCluster (15-56)
🔇 Additional comments (77)
pkg/handlers/validation_test.go (3)

8-8: LGTM!

Import addition is appropriate for accessing the util.PtrString helper.


98-107: LGTM!

Correctly adapts to the pointer-typed Kind field using the utility helper.


129-151: LGTM!

Both tests correctly adapt to the pointer-typed Kind field and maintain proper error message assertions.

.bingo/variables.env (2)

17-18: LGTM - oapi-codegen tool addition aligns with PR objectives.

The addition of oapi-codegen-v2.5.1 to the bingo toolchain is appropriate for replacing the Java-based OpenAPI Generator with a Go-native solution.


11-11: No action required for golangci-lint v2.7.0 upgrade.

The repository's .golangci.yml already uses v2 configuration format (declared with version: 2) and is fully compatible with golangci-lint v2.7.0.

test/factories/node_pools.go (1)

34-41: LGTM - Test factory updated with required metadata fields.

The addition of CreatedBy and UpdatedBy fields with test email values aligns with the OpenAPI type changes introduced by oapi-codegen. This ensures test data includes the new mandatory metadata fields.

pkg/errors/errors.go (2)

186-192: LGTM - Consistent migration to util.PtrString.

The CodeStr and Href helpers now use util.PtrString instead of openapi.PtrString, aligning with the broader migration pattern across presenters.


155-183: The anonymous struct approach is correct and idiomatic. The OpenAPI specification defines the details field as an array of inline objects without a named type, so using an anonymous struct is the appropriate Go pattern. There is no ErrorDetailsInner type to use instead, and the current implementation is already type-safe and maintainable.

pkg/api/presenters/kind.go (2)

6-8: LGTM - Clean migration to util package for pointer helpers.

Moving from openapi.PtrString to util.PtrString properly decouples presenter logic from generated code, which improves maintainability when regenerating OpenAPI types.


29-44: LGTM - ObjectKind function unchanged except for pointer helper.

The function logic is preserved; only the pointer-wrapping helper source changed. This is consistent with the broader refactoring pattern across presenters.

go.mod (1)

23-23: Version compatibility confirmed.

The oapi-codegen/runtime v1.1.2 is appropriate for oapi-codegen v2.5.1. The v2.x generator produces code that uses the separate runtime module, and runtime v1.1.2 is the compatible version for generated imports. The Go version (1.24.0) meets the v2.5.1 requirement of Go >= 1.21.

pkg/api/presenters/path.go (1)

7-7: LGTM!

Good refactor to use a local util.PtrString helper instead of relying on generated code. This decouples presenters from the OpenAPI generator implementation details and improves maintainability.

Also applies to: 34-34

Dockerfile (1)

3-4: Go version inconsistency with project requirements.

The Dockerfile uses golang:1.25, but the coding guidelines specify Go 1.24.9. Ensure this is intentional and update either the Dockerfile or guidelines for consistency.

pkg/api/presenters/node_pool_test.go (1)

9-9: LGTM!

The test file is properly updated to use oapi-codegen's semantic types (openapi_types.Email) and the new PascalCase enum values (openapi.Ready, openapi.True, openapi.NotReady). The changes correctly reflect the shift from the old generator's conventions to oapi-codegen's Go-idiomatic output.

Also applies to: 212-213, 227-227, 231-231

test/helper.go (3)

265-277: LGTM!

Clean implementation of the new oapi-codegen client pattern. The helper correctly constructs the server URL from configuration and uses T.Fatalf for immediate test failure on client creation errors.


308-336: Well-designed authentication helper pattern.

The context-based token storage with type-safe key and the WithAuthToken RequestEditorFn follow oapi-codegen's recommended patterns for request customization.

Minor note: On line 329, the inner context parameter _ is correctly ignored since the token comes from the outer ctx captured in the closure.


584-592: Improved error handling API.

Changing OpenapiError to accept []byte instead of error is a better design - it directly handles the response body from failed API calls without requiring the caller to extract the body from an error type first.

.bingo/oapi-codegen.mod (1)

1-5: oapi-codegen v2.5.1 is the latest stable version — no action needed.

The Go version in the bingo module (1.25.0) differs from the project requirement (1.24.9 with FIPS crypto), but this is acceptable since bingo-managed tool modules are isolated containers used only during code generation and don't affect the main project's build or compliance posture.

test/integration/search_field_mapping_test.go (6)

34-44: LGTM! New API client pattern correctly implemented.

The transition to GetClustersWithResponse with SearchParams type conversion, status code checking via resp.StatusCode(), and nil-guarded JSON200 payload access follows the oapi-codegen client pattern correctly.


86-96: LGTM! Time-based search query correctly formatted.

RFC3339 formatting for date-time comparison and proper response handling pattern.


136-146: LGTM! Labels query and assertion pattern is correct.

Safe nil-check on item.Labels before dereferencing, and proper use of HaveKeyWithValue matcher.

Also applies to: 155-157


175-184: LGTM! Error response validation is correct.

The test correctly expects err to be nil (HTTP transport succeeded) while checking resp.StatusCode() for the application-level 400 error.


230-248: LGTM! Combined query test correctly validates AND condition behavior.


275-293: LGTM! NodePool field mapping tests are comprehensive.

Tests cover both status.phase and labels mapping for NodePools, maintaining consistency with Cluster test patterns.

Also applies to: 306-316

pkg/api/presenters/adapter_status.go (3)

43-47: LGTM! Pointer dereference for Data is correct.

Safe handling of the pointer-based req.Data with nil check before dereference.


88-94: LGTM! Condition status conversion is correct.

Direct type conversion between api.ConditionStatus and openapi.ConditionStatus is valid since both are string-based with matching enum values.


97-103: LGTM! Data handling correctly returns nil-pointer for empty data.

When adapterStatus.Data is empty, returning &data (pointer to nil map) serializes to null in JSON, which aligns with the optional data field in the OpenAPI spec.

Also applies to: 156-156

openapi/openapi.yaml (10)

1-4: LGTM! Version bump reflects schema refactoring.

Version 1.0.2 appropriately reflects the significant schema changes in this PR.


22-27: LGTM! SearchParams placement is consistent across all list endpoints.

Also applies to: 118-122, 266-270, 335-339, 359-363


427-455: LGTM! AdapterCondition schema is well-defined.

Explicit field definitions with clear descriptions and appropriate required fields.


456-548: LGTM! AdapterStatus schema is comprehensive with helpful examples.


549-597: LGTM! AdapterStatusCreateRequest properly requires observed_time.

Making observed_time required ensures adapters provide accurate timing information for status reports.


627-651: LGTM! List schemas have consistent pagination structure.

All list schemas (AdapterStatusList, ClusterList, NodePoolList) share a uniform pagination pattern with kind, page, size, total, and items.

Also applies to: 819-842, 1132-1155


695-783: LGTM! Cluster schemas correctly separate required fields.

Cluster response requires server-generated fields (timestamps, status, generation), while ClusterCreateRequest only requires user-provided fields (name, spec).

Also applies to: 784-818


857-859: LGTM! ClusterStatus.phase directly references ResourcePhase.

Clean direct reference instead of allOf inheritance improves code generation.


946-1041: LGTM! NodePool schemas follow consistent patterns with Cluster schemas.

Also applies to: 1042-1075, 1076-1131, 1162-1197


1219-1264: LGTM! ResourceCondition includes appropriate API-managed tracking fields.

ResourceCondition correctly includes observed_generation, created_time, and last_updated_time for tracking adapter-reported state, distinct from AdapterCondition which is the input format.

test/factories/clusters.go (2)

24-25: LGTM! CreatedBy and UpdatedBy fields properly initialized in test factory.

Test data factory correctly sets these new required fields with a consistent test email.


64-141: LGTM! Helper factory functions correctly manage test data creation.

Functions properly create clusters via service, then use direct DB updates for test-specific field manipulation, and reload to ensure consistency.

pkg/handlers/cluster_nodepools_test.go (2)

59-67: LGTM! Mock NodePool updated with new required fields.

Test correctly populates all new required fields (Spec, Labels, StatusConditions, CreatedBy, UpdatedBy) needed for the presenter to generate valid responses.


181-189: LGTM! Test assertions appropriately verify handler behavior.

Assertions focus on verifying the handler correctly retrieves and presents the NodePool. Full payload validation is delegated to integration tests.

pkg/handlers/cluster.go (1)

42-42: System user identifier correctly updated to email format.

The change from "system" to "[email protected]" aligns with the OpenAPI spec's format: email constraint for created_by and updated_by fields.

This identifier is used in 3 handler locations (cluster, node_pool, cluster_nodepools). Consider extracting to a package-level constant for maintainability:

const SystemUserEmail = "[email protected]"
pkg/api/presenters/node_pool.go (2)

112-124: LGTM! Condition mapping correctly updated for new OpenAPI types.

The conversion from domain ResourceCondition to openapi.ResourceCondition now includes all required fields (LastTransitionTime, ObservedGeneration, Reason, Status, Type) with proper type casting for ConditionStatus.


126-151: LGTM! Complete NodePool construction with proper pointer handling.

The result construction correctly:

  • Uses toEmail helper for email-typed fields
  • Handles pointer fields (Href, Id, Kind, Labels) appropriately
  • Constructs OwnerReferences with proper pointer semantics
  • Maps status fields including Phase with type conversion
test/integration/adapter_status_test.go (3)

16-25: LGTM! Clean helper function for test setup.

The newAdapterStatusRequest helper consolidates test setup and ensures consistent ObservedTime initialization using time.Now().


376-402: LGTM! Pagination consistency test properly validates no duplicates across pages.

The test correctly iterates through pages, collecting all adapters and verifying uniqueness. The safety limit at page 10 prevents infinite loops.


27-62: LGTM! Test properly validates cluster status creation with new API patterns.

The test correctly uses the new PostClusterStatusesWithResponse method and validates the response via resp.JSON201 and typed status constants (openapi.True).

pkg/api/presenters/cluster.go (3)

58-61: LGTM! Simple and effective email type conversion helper.

The toEmail helper provides a clean abstraction for converting string to openapi_types.Email. Being unexported is appropriate as it's only used within the presenters package.


38-45: LGTM! Proper default Kind handling for cluster creation.

The code correctly defaults to "Cluster" when req.Kind is nil, matching the pattern used in ConvertNodePool.


127-146: LGTM! Complete Cluster construction with consistent patterns.

The result construction correctly mirrors the PresentNodePool pattern, using appropriate type helpers (toEmail, util.PtrString) and pointer semantics for optional fields.

Makefile (3)

81-83: LGTM! Robust version info extraction with fallbacks.

The GIT_SHA and GIT_DIRTY variables handle edge cases gracefully:

  • GIT_SHA falls back to "unknown" if git fails
  • GIT_DIRTY only sets the suffix if there are uncommitted changes

243-245: Good backward compatibility for generate-vendor target.

Maintaining this as an alias to generate ensures existing scripts/documentation continue to work while the underlying implementation changes.


227-231: LGTM! Clean migration to oapi-codegen for OpenAPI generation.

The generate target now uses the bingo-managed $(OAPI_CODEGEN) tool (v2.5.1) with proper configuration. This removes the Docker/Java dependency and simplifies the build process. The openapi/oapi-codegen.yaml configuration file is in place with appropriate settings for code generation.

test/integration/node_pools_test.go (5)

61-77: LGTM! NodePool creation test properly updated for new API patterns.

The test correctly:

  • Uses a local kind variable with pointer reference (&kind)
  • Migrates to CreateNodePoolWithResponse with test.WithAuthToken(ctx)
  • Validates response via resp.JSON201 and resp.StatusCode()

115-128: LGTM! Paging test correctly uses new typed query parameters.

The test properly constructs GetNodePoolsParams with typed Page and PageSize parameters and validates all pagination fields in the response.


140-152: LGTM! Search test properly validates filtering by ID.

The test correctly uses openapi.SearchParams type and validates that the search returns exactly the expected nodepool.


179-231: LGTM! Comprehensive test coverage for nodepool retrieval by cluster and ID.

The test thoroughly validates:

  • Successful retrieval (200 OK)
  • Non-existent nodepool (404)
  • Non-existent cluster (404)
  • Cross-cluster access prevention (404)

This ensures proper cluster-scoped authorization.


234-270: LGTM! Validation test correctly verifies empty kind rejection.

Using raw resty to send malformed JSON that the generated client wouldn't allow is the right approach for testing server-side validation. The test properly validates the error response contains the expected message.

pkg/api/presenters/adapter_status_test.go (5)

22-44: LGTM - Test data construction correctly adapted to new oapi-codegen types.

The changes properly handle:

  • Data as *map[string]interface{} (pointer to map)
  • Metadata as an inline anonymous struct pointer matching the generated type
  • Status enum updated from uppercase (TRUE) to PascalCase (True)

86-91: Inline struct for metadata unmarshaling is appropriate.

The struct matches the generated type shape and properly validates that JobName is preserved through the conversion.


299-302: Pointer dereferencing for Data map is correct.

The nil check on line 299 guards against nil pointer dereference before accessing map contents.


205-234: Condition status conversion tests correctly updated for new enum values.

The test cases align with the domain types (api.ConditionTrue = "True") from pkg/api/status_types.go and the new oapi-codegen generated enum values.


451-459: Round-trip test correctly verifies data and metadata preservation.

The pointer dereferencing and type assertions are appropriate given the preceding nil checks and test setup.

pkg/api/presenters/cluster_test.go (5)

8-12: New imports correctly added for openapi_types and util packages.

The imports align with the new type requirements:

  • openapi_types for Email type used in CreatedBy/UpdatedBy assertions
  • util for PtrString helper used in Kind field construction

16-28: Test request construction correctly adapted to pointer-based fields.

The changes properly use:

  • &labels for the Labels pointer field
  • util.PtrString("Cluster") for the optional Kind field

This matches the relevant code snippet showing ConvertCluster handles nil Kind with a default value.


217-218: Email type assertions correctly match the new openapi_types.Email wrapper.

The PresentCluster function converts domain string fields to openapi_types.Email, and tests appropriately wrap expected values.


227-231: Status phase and condition status enum values correctly updated.

The new enum values (openapi.Ready, openapi.True) align with oapi-codegen conventions.


40-49: Domain object assertions correctly use plain strings.

The ConvertCluster function returns *api.Cluster with CreatedBy/UpdatedBy as strings (see relevant snippet lines 14-55). The Email type wrapping happens only in PresentCluster.

test/integration/clusters_test.go (9)

14-20: Imports correctly updated for new client patterns.

The addition of util package import supports the PtrString helper for pointer-based Kind field construction.


29-52: TestClusterGet correctly migrated to WithResponse pattern.

The test properly:

  • Uses GetClusterByIdWithResponse with status code checks
  • Extracts typed response via resp.JSON200
  • Includes nil check before accessing response fields
  • Dereferences pointer fields (*clusterOutput.Kind)

60-87: TestClusterPost correctly handles creation flow and auth fallback.

The test properly uses:

  • PostClusterWithResponse for typed response
  • util.PtrString("Cluster") for Kind field
  • test.GetAccessTokenFromContext(ctx) for resty requests

113-127: Paging parameters correctly constructed using type aliases.

The use of openapi.QueryParamsPage and openapi.QueryParamsPageSize type aliases ensures type safety with the generated client.


138-150: Search test correctly uses SearchParams type alias.

The pattern is consistent with other parameterized queries.


339-343: LGTM - Status code check before JSON201 access is appropriate.

The pattern of checking StatusCode() == 201 before accessing JSON201 is correct and ensures the typed response is populated.


443-450: Error details iteration correctly handles nil pointer.

The nil check on errorResponse.Details at line 443 before iterating prevents nil pointer dereference.


674-741: LGTM - Kind validation tests are comprehensive.

The tests properly verify that empty and wrong kind values return 400 with appropriate error messages. Using resty allows testing invalid JSON structures that can't be constructed with the typed client.


22-52: Integration test coverage follows coding guidelines.

The tests cover CRUD operations, pagination, search, and error cases as required by the coding guidelines for test/integration/**/*_test.go.


# Build binary
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o hyperfleet-api ./cmd/hyperfleet-api
RUN CGO_ENABLED=0 GOOS=linux make build
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

CGO_ENABLED=0 conflicts with FIPS-compliant crypto requirements.

The coding guidelines specify CGO_ENABLED=1, GOEXPERIMENT=boringcrypto for FIPS-compliant crypto. Setting CGO_ENABLED=0 disables cgo, which prevents boringcrypto from being used.

If FIPS compliance is required for production, this needs to be updated. If FIPS is not required, the coding guidelines should be updated for consistency.

🔧 Proposed fix for FIPS compliance
-RUN CGO_ENABLED=0 GOOS=linux make build
+RUN CGO_ENABLED=1 GOOS=linux GOEXPERIMENT=boringcrypto make build

Note: This also requires a base image with glibc (not distroless/static) since CGO requires dynamic linking.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
RUN CGO_ENABLED=0 GOOS=linux make build
RUN CGO_ENABLED=1 GOOS=linux GOEXPERIMENT=boringcrypto make build
🤖 Prompt for AI Agents
In @Dockerfile at line 19, The Dockerfile currently forces CGO_DISABLED by
running the build with "CGO_ENABLED=0", which prevents enabling boringcrypto for
FIPS; update the build invocation used to produce the binary (the RUN line that
executes make build) to export CGO_ENABLED=1 and set GOEXPERIMENT=boringcrypto
so the Go build can use cgo/boringcrypto for FIPS-compliant crypto, and ensure
the Docker base image is changed to one with glibc (not distroless/static) to
support dynamic linking; alternatively, if FIPS is not required, update the
coding guidelines to reflect CGO_ENABLED=0 as acceptable.

Comment on lines +1 to +17
# oapi-codegen configuration
# See: https://github.com/oapi-codegen/oapi-codegen

package: openapi
output: pkg/api/openapi/openapi.gen.go
generate:
models: true
chi-server: false
client: true
embedded-spec: true
output-options:
skip-prune: false
compatibility:
# Use old allOf merge behavior where schemas are inlined
old-merge-schemas: true
# Use old behavior generating type definitions instead of aliases
old-aliasing: true
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check for existing code generation configurations
git ls-files | grep -E "(codegen|openapi|spec)" | head -20

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 259


🏁 Script executed:

# Check the output directory structure mentioned in the config
find . -type d -name "openapi" 2>/dev/null | head -10

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 88


🏁 Script executed:

# Look for TypeSpec files
fd -e "tsp" -o -name "*spec*" 2>/dev/null | head -20

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 61


🏁 Script executed:

# Check for existing references to openapi-generator or oapi-codegen in build/config files
rg "openapi-generator|oapi-codegen" --type yaml --type toml --type json -l

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 104


🏁 Script executed:

# Check the contents of the .bingo directory and how oapi-codegen is pinned
cat .bingo/oapi-codegen.mod

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 242


🏁 Script executed:

# Check Makefile or build scripts for code generation
fd -e "Makefile" -o -e "makefile" -e "*.mk" | xargs grep -l "codegen\|openapi" 2>/dev/null

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 197


🏁 Script executed:

# Check what currently exists in the pkg/api/openapi directory
find pkg/api/openapi -type f 2>/dev/null | head -20

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 61


🏁 Script executed:

# Check the openapi.yaml file to understand the spec structure
head -50 openapi/openapi.yaml

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 1687


🏁 Script executed:

# Try to find build files more directly
find . -name "Makefile" -o -name "*.mk" 2>/dev/null | head -5

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 111


🏁 Script executed:

# Check if oapi-codegen.yaml is new or modified
git status openapi/oapi-codegen.yaml 2>/dev/null || echo "File status unknown"
git log --oneline openapi/oapi-codegen.yaml 2>/dev/null | head -3 || echo "No git history"

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 170


🏁 Script executed:

# Search for how code generation is invoked in build files
rg "oapi-codegen|openapi-generator" --type go --type sh -A 2 -B 2 2>/dev/null | head -40

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 1140


🏁 Script executed:

# Check README for setup/build instructions
find . -maxdepth 2 -name "README*" -o -name "CONTRIBUTING*" | xargs grep -l "codegen\|generate\|build" 2>/dev/null

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 109


🏁 Script executed:

# Check the Makefile for code generation setup
cat Makefile | grep -A 10 -B 2 "codegen\|generate\|openapi"

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 2974


🏁 Script executed:

# Look at the README to understand project structure and build process
cat README.md | head -100

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 2910


🏁 Script executed:

# Check .bingo/Variables.mk to see how oapi-codegen is invoked
cat .bingo/Variables.mk

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 3026


Diverges from coding guidelines: Project must migrate from oapi-codegen to openapi-generator-cli v7.16.0 with TypeSpec.

This configuration uses oapi-codegen v2.5.1 and raw OpenAPI 3.0.0, but the coding guidelines specify:

  • API specification must use TypeSpec
  • Code generation must use openapi-generator-cli v7.16.0
  • Only openapi/openapi.yaml is editable as the source of truth

The project has drifted from this prescribed toolchain. The oapi-codegen.yaml configuration should be replaced with TypeSpec sources and openapi-generator-cli v7.16.0 setup as per guidelines.

🤖 Prompt for AI Agents
In @openapi/oapi-codegen.yaml around lines 1 - 17, This file (oapi-codegen.yaml)
uses oapi-codegen options like generate.models and output-options.old-aliasing
and must be removed and replaced by a TypeSpec-based workflow: stop using
oapi-codegen.yaml, add a TypeSpec API spec at openapi/openapi.yaml (the only
editable source of truth), configure codegen to use openapi-generator-cli
v7.16.0 in your build/CI scripts (replacing any oapi-codegen invocation), and
update generation settings to produce the client/server/models equivalent to
generate.models and client from the old config; also remove or migrate any code
that depended on oapi-codegen-specific behaviors (e.g.,
old-merge-schemas/old-aliasing) so the project builds with the new generator.

Comment on lines +202 to 205
resp, err = client.GetClustersWithResponse(ctx, params, test.WithAuthToken(ctx))
Expect(err).NotTo(HaveOccurred())
Expect(len(validList.Items)).To(BeNumerically(">=", 0))
Expect(len(resp.JSON200.Items)).To(BeNumerically(">=", 0))
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential nil pointer dereference at line 204.

After GetClustersWithResponse, resp.JSON200 could be nil if the response status is not 200. While err == nil is checked, a non-200 status doesn't set JSON200.

🔧 Suggested fix: Add nil check before accessing JSON200
 	resp, err = client.GetClustersWithResponse(ctx, params, test.WithAuthToken(ctx))
 	Expect(err).NotTo(HaveOccurred())
-	Expect(len(resp.JSON200.Items)).To(BeNumerically(">=", 0))
+	Expect(resp.JSON200).NotTo(BeNil())
+	Expect(len(resp.JSON200.Items)).To(BeNumerically(">=", 0))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
resp, err = client.GetClustersWithResponse(ctx, params, test.WithAuthToken(ctx))
Expect(err).NotTo(HaveOccurred())
Expect(len(validList.Items)).To(BeNumerically(">=", 0))
Expect(len(resp.JSON200.Items)).To(BeNumerically(">=", 0))
}
resp, err = client.GetClustersWithResponse(ctx, params, test.WithAuthToken(ctx))
Expect(err).NotTo(HaveOccurred())
Expect(resp.JSON200).NotTo(BeNil())
Expect(len(resp.JSON200.Items)).To(BeNumerically(">=", 0))
}
🤖 Prompt for AI Agents
In @test/integration/clusters_test.go around lines 202 - 205, After calling
GetClustersWithResponse, add a nil check for resp.JSON200 before accessing Items
to avoid a nil pointer dereference; specifically, in the test after resp, err =
client.GetClustersWithResponse(...), confirm resp != nil and resp.JSON200 != nil
(or handle non-200 cases) and only then assert on len(resp.JSON200.Items) or use
Expect(resp.StatusCode()).To(Equal(200)) prior to inspecting JSON200 so the test
safely handles non-200 responses.

Comment on lines +233 to 236
getResp, err := client.GetClusterByIdWithResponse(ctx, id1, nil, test.WithAuthToken(ctx))
Expect(err).NotTo(HaveOccurred())
Expect(retrieved1.Name).To(Equal("duplicate-name-test"))
Expect(getResp.JSON200.Name).To(Equal("duplicate-name-test"))
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing nil check before accessing JSON200 at line 235.

For consistency and defensive coding, add a nil check on getResp.JSON200 before accessing .Name.

🔧 Suggested fix: Add nil check
 	getResp, err := client.GetClusterByIdWithResponse(ctx, id1, nil, test.WithAuthToken(ctx))
 	Expect(err).NotTo(HaveOccurred())
+	Expect(getResp.JSON200).NotTo(BeNil())
 	Expect(getResp.JSON200.Name).To(Equal("duplicate-name-test"))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
getResp, err := client.GetClusterByIdWithResponse(ctx, id1, nil, test.WithAuthToken(ctx))
Expect(err).NotTo(HaveOccurred())
Expect(retrieved1.Name).To(Equal("duplicate-name-test"))
Expect(getResp.JSON200.Name).To(Equal("duplicate-name-test"))
}
getResp, err := client.GetClusterByIdWithResponse(ctx, id1, nil, test.WithAuthToken(ctx))
Expect(err).NotTo(HaveOccurred())
Expect(getResp.JSON200).NotTo(BeNil())
Expect(getResp.JSON200.Name).To(Equal("duplicate-name-test"))
}
🤖 Prompt for AI Agents
In @test/integration/clusters_test.go around lines 233 - 236, The test accesses
getResp.JSON200.Name without ensuring JSON200 is non-nil; update the assertion
after calling GetClusterByIdWithResponse (in the block using
GetClusterByIdWithResponse, getResp and id1) to first verify getResp.JSON200 is
not nil (e.g., Expect(getResp.JSON200).NotTo(BeNil())) before asserting on
getResp.JSON200.Name to avoid nil dereference.

Comment on lines +301 to +303
getResp, err := client.GetClusterByIdWithResponse(ctx, *resp.JSON201.Id, nil, test.WithAuthToken(ctx))
Expect(err).NotTo(HaveOccurred())
Expect(len(retrieved.Spec)).To(Equal(100))
Expect(len(getResp.JSON200.Spec)).To(Equal(100))
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing nil check before accessing JSON200.Spec at line 303.

🔧 Suggested fix: Add nil check
 	getResp, err := client.GetClusterByIdWithResponse(ctx, *resp.JSON201.Id, nil, test.WithAuthToken(ctx))
 	Expect(err).NotTo(HaveOccurred())
+	Expect(getResp.JSON200).NotTo(BeNil())
 	Expect(len(getResp.JSON200.Spec)).To(Equal(100))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
getResp, err := client.GetClusterByIdWithResponse(ctx, *resp.JSON201.Id, nil, test.WithAuthToken(ctx))
Expect(err).NotTo(HaveOccurred())
Expect(len(retrieved.Spec)).To(Equal(100))
Expect(len(getResp.JSON200.Spec)).To(Equal(100))
getResp, err := client.GetClusterByIdWithResponse(ctx, *resp.JSON201.Id, nil, test.WithAuthToken(ctx))
Expect(err).NotTo(HaveOccurred())
Expect(getResp.JSON200).NotTo(BeNil())
Expect(len(getResp.JSON200.Spec)).To(Equal(100))
🤖 Prompt for AI Agents
In @test/integration/clusters_test.go around lines 301 - 303, The test accesses
getResp.JSON200.Spec without ensuring getResp.JSON200 is non-nil; add a nil
check after the call to GetClusterByIdWithResponse (check getResp and
getResp.JSON200) and fail the test or Expect them to be non-nil before asserting
len(getResp.JSON200.Spec) == 100. Specifically, after GetClusterByIdWithResponse
and the existing err check, add Expect(getResp).NotTo(BeNil()) and
Expect(getResp.JSON200).NotTo(BeNil()) (or an if guard that calls Fail/Expect)
so accessing getResp.JSON200.Spec is safe.

Comment on lines +526 to +528
resp, err := client.PostClusterWithResponse(ctx, openapi.PostClusterJSONRequestBody(clusterInput), test.WithAuthToken(ctx))
Expect(err).NotTo(HaveOccurred(), "Failed to create cluster %d", i)
createdClusters = append(createdClusters, *cluster)
createdClusters = append(createdClusters, *resp.JSON201)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing status and nil check before accessing JSON201.

The loop creates clusters and appends *resp.JSON201. If a POST fails with non-201 status, JSON201 would be nil, causing a panic.

🔧 Suggested fix: Add status and nil check
 		resp, err := client.PostClusterWithResponse(ctx, openapi.PostClusterJSONRequestBody(clusterInput), test.WithAuthToken(ctx))
 		Expect(err).NotTo(HaveOccurred(), "Failed to create cluster %d", i)
+		Expect(resp.StatusCode()).To(Equal(http.StatusCreated))
+		Expect(resp.JSON201).NotTo(BeNil())
 		createdClusters = append(createdClusters, *resp.JSON201)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
resp, err := client.PostClusterWithResponse(ctx, openapi.PostClusterJSONRequestBody(clusterInput), test.WithAuthToken(ctx))
Expect(err).NotTo(HaveOccurred(), "Failed to create cluster %d", i)
createdClusters = append(createdClusters, *cluster)
createdClusters = append(createdClusters, *resp.JSON201)
resp, err := client.PostClusterWithResponse(ctx, openapi.PostClusterJSONRequestBody(clusterInput), test.WithAuthToken(ctx))
Expect(err).NotTo(HaveOccurred(), "Failed to create cluster %d", i)
Expect(resp.StatusCode()).To(Equal(http.StatusCreated))
Expect(resp.JSON201).NotTo(BeNil())
createdClusters = append(createdClusters, *resp.JSON201)
🤖 Prompt for AI Agents
In @test/integration/clusters_test.go around lines 526 - 528, The test
dereferences resp.JSON201 without verifying the HTTP status or that JSON201 is
non-nil, which can panic if the POST fails; after the
client.PostClusterWithResponse call and Err check, assert the response status is
201 (or use resp.StatusCode/resp.Status) and add
Expect(resp.JSON201).NotTo(BeNil()) before appending, then safely append
*resp.JSON201 to createdClusters; reference resp, resp.JSON201 and
client.PostClusterWithResponse in the changes.

@yasun1
Copy link
Contributor

yasun1 commented Jan 14, 2026

/lgtm

@openshift-ci openshift-ci bot added the lgtm label Jan 14, 2026
@openshift-ci
Copy link

openshift-ci bot commented Jan 14, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: yasun1

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-merge-bot openshift-merge-bot bot merged commit 66df4e6 into openshift-hyperfleet:main Jan 14, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants