Skip to content

Conversation

@rafabene
Copy link
Contributor

@rafabene rafabene commented Jan 14, 2026

Summary

  • Implement RFC 9457 Problem Details format for all API error responses
  • Add HYPERFLEET-CAT-NUM error codes (VAL, AUT, AUZ, NTF, CNF, LMT, INT, SVC)
  • Include extension fields: code, timestamp, trace_id
  • Add field-level validation errors array with field, value, constraint, message

Test plan

  • All 318 unit tests passing
  • Lint passes with 0 issues
  • Manual testing of error responses
  • Verify Content-Type is application/problem+json
  • Verify error structure matches RFC 9457

Breaking Change

This is a breaking change for API consumers. The error response format has changed from:

{"kind": "Error", "id": "7", "href": "...", "code": "hyperfleet-7", "reason": "..."}

To RFC 9457 format:

{
  "type": "https://api.hyperfleet.io/errors/not-found",
  "title": "Resource Not Found",
  "status": 404,
  "detail": "...",
  "instance": "/api/hyperfleet/v1/clusters/123",
  "code": "HYPERFLEET-NTF-001",
  "timestamp": "2024-01-15T10:30:00Z",
  "trace_id": "abc123"
}

Resolves: https://issues.redhat.com/browse/HYPERFLEET-452

Summary by CodeRabbit

  • New Features

    • Error responses now follow RFC 9457 Problem Details, including a structured errors array for field-level validation items and a new ValidationError schema.
  • Bug Fixes

    • Consistent error payload fields across the API: type, title, status, detail, instance, traceId, timestamp, and errors (replacing previous names).
  • Chores

    • API version bumped to 1.0.3 and default error Content-Type standardized to application/problem+json with centralized problem-details response handling.

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

@openshift-ci openshift-ci bot requested review from mbrudnoy and vkareh January 14, 2026 19:44
@coderabbitai
Copy link

coderabbitai bot commented Jan 14, 2026

Walkthrough

Migrates API error handling to RFC 9457 Problem Details. OpenAPI bumped to 1.0.3; the Error schema replaced with Problem Details and a new ValidationError schema; default error content-type switched to application/problem+json. Server code updated across pkg/errors, pkg/api, middleware, auth, validators, handlers and tests to produce and consume Problem Details (AsProblemDetails, WriteProblemDetailsResponse) including instance and trace context. Many tests and factories updated for renamed fields and RFC9457-style error codes.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Handler
    participant ErrorsPkg as Errors Package
    participant Response as Response Writer
    participant Logger

    Client->>Handler: HTTP request
    Handler->>ErrorsPkg: Find/construct ServiceError (code, details)
    ErrorsPkg-->>Handler: ServiceError
    Handler->>ErrorsPkg: AsProblemDetails(instance, traceID)
    ErrorsPkg-->>Handler: openapi.Error (Problem Details)
    Handler->>Response: WriteProblemDetailsResponse(w, r, httpCode, openapi.Error)
    Response->>Logger: logResponseError(ctx, r, code, msg, err?)
    Response-->>Client: HTTP response (application/problem+json)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

lgtm, approved

Suggested reviewers

  • vkareh
  • mbrudnoy
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 43.14% 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 and specifically describes the main change: implementing RFC 9457 Problem Details error model. It is concise and directly related to the primary objective of this changeset.

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

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b0738ee and d0c2bfb.

📒 Files selected for processing (1)
  • pkg/errors/errors.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Retrieve database sessions from context via db.NewContext(ctx) rather than creating new GORM connections
Use context.Context for all operations to enable proper transaction lifecycle and cleanup
Use structured logging via logger.NewOCMLogger(ctx) with contextual information like operation ID, account ID, and transaction ID
Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Files:

  • pkg/errors/errors.go
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Applied to files:

  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses

Applied to files:

  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/{services,dao}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control

Applied to files:

  • pkg/errors/errors.go
📚 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:

  • pkg/errors/errors.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/errors/errors.go
🧬 Code graph analysis (1)
pkg/errors/errors.go (2)
pkg/logger/logger.go (3)
  • With (276-281)
  • Error (265-267)
  • WithError (284-289)
pkg/logger/fields.go (1)
  • FieldErrorCode (52-52)
🪛 Gitleaks (8.30.0)
pkg/errors/errors.go

[high] 39-39: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 40-40: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 41-41: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 44-44: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 45-45: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 golangci-lint (2.5.0)
pkg/errors/errors.go

[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)

(typecheck)

🔇 Additional comments (9)
pkg/errors/errors.go (9)

13-72: RFC 9457 type URIs and code taxonomy look consistent.

Clear categorization and naming make the new error model easy to reason about.


76-98: ServiceError/ValidationDetail structs are well-aligned with Problem Details.

Field layout cleanly supports RFC 9457 and validation extensions.


100-178: Centralized errorDefinitions + Find/Errors provide a solid source of truth.

Nice consolidation of defaults and lookup helpers.


180-203: New now safely handles formatted vs raw reasons.

The conditional formatting avoids fmt.Sprintf pitfalls while preserving flexibility.


206-224: Helper predicates and Error() output align with RFC 9457 types.

This keeps classification logic consistent across the codebase.


226-246: Constraint validation mapping is clean and defensive.

The explicit map + helper keeps OpenAPI enums safe.


248-287: Problem Details construction looks robust.

Conditional instance/trace fields and validation details mapping are well handled.


289-353: Constructors are consistent and easy to compose.

DatabaseAdvisoryLock logging + generic message is a good security-safe default.


3-10: The pkg/api/openapi package is present and available for import. The package is generated via make generate (documented in AGENTS.md) and correctly excluded in .gitignore since it's a build artifact. Any typecheck errors from golangci-lint are expected false positives that occur when linters run before the codegen step. The build/CI process should run make generate before executing typecheck to resolve this.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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

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

Caution

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

⚠️ Outside diff range comments (3)
pkg/db/transaction_middleware.go (1)

38-52: Refactor to match handlers pattern for proper error visibility and HTTP compliance.

This writeProblemDetailsResponse duplicates the function in pkg/handlers/helpers.go but lacks critical functionality:

  • Missing Vary: Authorization header
  • Silent error handling instead of structured logging

The middleware has the request context available at the call site (line 22), so refactor the function signature to accept *http.Request and pass it through, matching the handlers implementation for consistent structured logging and proper HTTP semantics.

♻️ Refactor function signature to include request context
-func writeProblemDetailsResponse(w http.ResponseWriter, code int, payload interface{}) {
+func writeProblemDetailsResponse(w http.ResponseWriter, r *http.Request, code int, payload interface{}) {
 	w.Header().Set("Content-Type", "application/problem+json")
+	w.Header().Set("Vary", "Authorization")
 	w.WriteHeader(code)

 	if payload != nil {
 		response, err := json.Marshal(payload)
 		if err != nil {
-			// Log error but don't expose to client since headers already sent
+			logger.With(r.Context(),
+				logger.HTTPPath(r.URL.Path),
+				logger.HTTPMethod(r.Method),
+				logger.HTTPStatusCode(code),
+			).WithError(err).Error("Failed to marshal Problem Details response payload")
 			return
 		}
 		if _, err := w.Write(response); err != nil {
-			// Response writing failed, nothing we can do at this point
+			logger.With(r.Context(),
+				logger.HTTPPath(r.URL.Path),
+				logger.HTTPMethod(r.Method),
+				logger.HTTPStatusCode(code),
+			).WithError(err).Error("Failed to write Problem Details response body")
 			return
 		}
 	}
 }

Then update the call site at line 22:

-writeProblemDetailsResponse(w, serviceErr.HttpCode, serviceErr.AsProblemDetails(r.URL.Path, traceID))
+writeProblemDetailsResponse(w, r, serviceErr.HttpCode, serviceErr.AsProblemDetails(r.URL.Path, traceID))
test/integration/clusters_test.go (2)

733-741: Same inconsistency: test expects reason field instead of RFC 9457 detail.

Similar to the previous test, this assertion uses the legacy reason field name.

🔧 Suggested fix
-	reason, ok := errorResponse["reason"].(string)
-	Expect(ok).To(BeTrue())
-	Expect(reason).To(ContainSubstring("kind must be 'Cluster'"))
+	detail, ok := errorResponse["detail"].(string)
+	Expect(ok).To(BeTrue())
+	Expect(detail).To(ContainSubstring("kind must be 'Cluster'"))

697-706: Update error field assertion from reason to detail to match RFC 9457 format.

The endpoint returns error responses in RFC 9457 Problem Details format with a detail field, not reason. These tests will fail because they're checking for a non-existent field.

-	reason, ok := errorResponse["reason"].(string)
-	Expect(ok).To(BeTrue())
-	Expect(reason).To(ContainSubstring("kind is required"))
+	detail, ok := errorResponse["detail"].(string)
+	Expect(ok).To(BeTrue())
+	Expect(detail).To(ContainSubstring("kind is required"))

Also update the identical assertions at line 738 in TestClusterPost_WrongKind.

🤖 Fix all issues with AI agents
In `@openapi/openapi.yaml`:
- Around line 917-995: The reported changes to the Error and ValidationError
schemas must not be applied directly to openapi/openapi.yaml; instead update the
TypeSpec source in the hyperfleet-api-spec repo (modify the TypeSpec definitions
that produce the Error and ValidationError schemas), recompile the spec to
regenerate openapi.yaml, and then copy the generated openapi.yaml into this
repository so the compiled YAML matches the TypeSpec source.
🧹 Nitpick comments (4)
pkg/handlers/helpers.go (1)

41-67: LGTM with optional refactor suggestion.

The implementation correctly sets application/problem+json per RFC 9457 and includes appropriate error handling with structured logging.

Consider extracting the common JSON response logic to reduce duplication with writeJSONResponse:

♻️ Optional: Extract common response logic
func writeResponse(w http.ResponseWriter, r *http.Request, contentType string, code int, payload interface{}) {
	w.Header().Set("Content-Type", contentType)
	w.Header().Set("Vary", "Authorization")
	w.WriteHeader(code)

	if payload != nil {
		response, err := json.Marshal(payload)
		if err != nil {
			logger.With(r.Context(),
				logger.HTTPPath(r.URL.Path),
				logger.HTTPMethod(r.Method),
				logger.HTTPStatusCode(code),
			).WithError(err).Error("Failed to marshal response payload")
			return
		}
		if _, err := w.Write(response); err != nil {
			logger.With(r.Context(),
				logger.HTTPPath(r.URL.Path),
				logger.HTTPMethod(r.Method),
				logger.HTTPStatusCode(code),
			).WithError(err).Error("Failed to write response body")
			return
		}
	}
}

func writeJSONResponse(w http.ResponseWriter, r *http.Request, code int, payload interface{}) {
	writeResponse(w, r, "application/json", code, payload)
}

func writeProblemDetailsResponse(w http.ResponseWriter, r *http.Request, code int, payload interface{}) {
	writeResponse(w, r, "application/problem+json", code, payload)
}
pkg/errors/errors.go (2)

132-146: Clarify the semantic distinction between ErrorUnauthorized and ErrorUnauthenticated.

Line 140 maps ErrorUnauthorized to http.StatusForbidden (403), while Line 141 maps ErrorUnauthenticated to http.StatusUnauthorized (401). The naming is potentially confusing:

  • ErrorUnauthorized (name suggests 401) → returns 403
  • ErrorUnauthenticated (name suggests identity issue) → returns 401

This is technically correct per HTTP semantics (401 = "who are you?", 403 = "you can't do this"), but the naming may cause confusion for developers. Consider adding inline comments to clarify, or renaming ErrorUnauthorized to something like ErrorInsufficientPermissions.


277-284: Remove duplicate function.

NotImplementedError and NotImplemented are identical. Consider removing one to reduce API surface area.

♻️ Suggested simplification
-func NotImplementedError(reason string, values ...interface{}) *ServiceError {
-	return New(ErrorNotImplemented, reason, values...)
-}
-
-// NotImplemented is an alias for NotImplementedError for backwards compatibility
 func NotImplemented(reason string, values ...interface{}) *ServiceError {
 	return New(ErrorNotImplemented, reason, values...)
 }
pkg/auth/helpers.go (1)

31-46: Consider logging errors in silent failure paths.

The error handling for json.Marshal and w.Write failures is correct (nothing can be done after headers are sent), but silently swallowing these errors may make debugging harder in production.

♻️ Optional: Add debug logging for observability
 func writeProblemDetailsResponse(w http.ResponseWriter, code int, payload interface{}) {
 	w.Header().Set("Content-Type", "application/problem+json")
 	w.WriteHeader(code)

 	if payload != nil {
 		response, err := json.Marshal(payload)
 		if err != nil {
 			// Headers already sent, can't change status code
+			// Log for observability - this indicates a bug in payload construction
 			return
 		}
 		if _, err := w.Write(response); err != nil {
 			// Writing failed, nothing we can do at this point
+			// Log for observability - likely client disconnect
 			return
 		}
 	}
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f4c655 and da15c80.

📒 Files selected for processing (16)
  • openapi/openapi.yaml
  • pkg/api/error.go
  • pkg/api/error_types.go
  • pkg/api/presenters/error.go
  • pkg/auth/auth_middleware.go
  • pkg/auth/helpers.go
  • pkg/db/transaction_middleware.go
  • pkg/errors/errors.go
  • pkg/handlers/framework.go
  • pkg/handlers/helpers.go
  • pkg/middleware/schema_validation.go
  • pkg/middleware/schema_validation_test.go
  • pkg/services/generic_test.go
  • pkg/validators/schema_validator.go
  • pkg/validators/schema_validator_test.go
  • test/integration/clusters_test.go
💤 Files with no reviewable changes (1)
  • pkg/api/error_types.go
🧰 Additional context used
📓 Path-based instructions (8)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Retrieve database sessions from context via db.NewContext(ctx) rather than creating new GORM connections
Use context.Context for all operations to enable proper transaction lifecycle and cleanup
Use structured logging via logger.NewOCMLogger(ctx) with contextual information like operation ID, account ID, and transaction ID
Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Files:

  • pkg/middleware/schema_validation_test.go
  • pkg/handlers/helpers.go
  • pkg/api/error.go
  • pkg/services/generic_test.go
  • pkg/middleware/schema_validation.go
  • pkg/validators/schema_validator_test.go
  • pkg/db/transaction_middleware.go
  • pkg/handlers/framework.go
  • pkg/auth/helpers.go
  • pkg/api/presenters/error.go
  • pkg/validators/schema_validator.go
  • test/integration/clusters_test.go
  • pkg/errors/errors.go
  • pkg/auth/auth_middleware.go
pkg/handlers/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

pkg/handlers/**/*.go: All HTTP handlers must use the pattern: parse request → call service/DAO → handle errors → send response
Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses
Database sessions are stored in request context via middleware - always retrieve from context, never create new connections

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

Increment the generation field on each spec update to enable optimistic concurrency control

Files:

  • pkg/services/generic_test.go
openapi/openapi.yaml

📄 CodeRabbit inference engine (AGENTS.md)

openapi/openapi.yaml: Do not manually edit openapi/openapi.yaml - it is generated from TypeSpec. Only edit the source file in hyperfleet-api-spec repository
Only edit the source openapi/openapi.yaml file; the fully resolved pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Files:

  • openapi/openapi.yaml
pkg/db/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Configure database connection pooling via db.DB().SetMaxOpenConns() and SetMaxIdleConns()

Files:

  • pkg/db/transaction_middleware.go
test/integration/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

All integration tests must use Testcontainers to create isolated PostgreSQL instances for each test

Files:

  • test/integration/clusters_test.go
test/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use test factories in test/factories/ to provide consistent test data instead of creating test data inline

Files:

  • test/integration/clusters_test.go
pkg/**/auth*.go

📄 CodeRabbit inference engine (AGENTS.md)

Validate JWT tokens from Red Hat SSO and extract account ID and username from claims for authentication

Files:

  • pkg/auth/auth_middleware.go
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured error type from pkg/errors with HttpCode, Code, and Reason fields
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses
📚 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/middleware/schema_validation_test.go
  • pkg/handlers/helpers.go
  • pkg/api/error.go
  • pkg/services/generic_test.go
  • pkg/middleware/schema_validation.go
  • pkg/validators/schema_validator_test.go
  • pkg/db/transaction_middleware.go
  • pkg/handlers/framework.go
  • pkg/auth/helpers.go
  • pkg/api/presenters/error.go
  • pkg/validators/schema_validator.go
  • test/integration/clusters_test.go
  • pkg/errors/errors.go
  • pkg/auth/auth_middleware.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Applied to files:

  • pkg/api/error.go
  • pkg/middleware/schema_validation.go
  • pkg/handlers/framework.go
  • pkg/auth/helpers.go
  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses

Applied to files:

  • pkg/api/error.go
  • pkg/middleware/schema_validation.go
  • pkg/db/transaction_middleware.go
  • pkg/handlers/framework.go
  • pkg/auth/helpers.go
  • pkg/api/presenters/error.go
  • pkg/errors/errors.go
  • pkg/auth/auth_middleware.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/api/*embed*.go : Embed the OpenAPI specification at compile time using //go:embed directive

Applied to files:

  • pkg/api/error.go
📚 Learning: 2026-01-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to test/**/*.go : Use test factories in test/factories/ to provide consistent test data instead of creating test data inline

Applied to files:

  • pkg/services/generic_test.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/{services,dao}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control

Applied to files:

  • pkg/services/generic_test.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to openapi/openapi.yaml : Do not manually edit openapi/openapi.yaml - it is generated from TypeSpec. Only edit the source file in hyperfleet-api-spec repository

Applied to files:

  • openapi/openapi.yaml
📚 Learning: 2026-01-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to openapi/openapi.yaml : Only edit the source openapi/openapi.yaml file; the fully resolved pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Applied to files:

  • openapi/openapi.yaml
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : All HTTP handlers must use the pattern: parse request → call service/DAO → handle errors → send response

Applied to files:

  • pkg/handlers/framework.go
  • pkg/auth/helpers.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with contextual information like operation ID, account ID, and transaction ID

Applied to files:

  • pkg/handlers/framework.go
📚 Learning: 2026-01-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to pkg/**/auth*.go : Validate JWT tokens from Red Hat SSO and extract account ID and username from claims for authentication

Applied to files:

  • pkg/auth/auth_middleware.go
🧬 Code graph analysis (9)
pkg/handlers/helpers.go (2)
pkg/logger/logger.go (3)
  • With (276-281)
  • WithError (284-289)
  • Error (265-267)
pkg/logger/http.go (3)
  • HTTPPath (24-26)
  • HTTPMethod (19-21)
  • HTTPStatusCode (29-31)
pkg/middleware/schema_validation.go (3)
pkg/errors/errors.go (1)
  • ServiceError (105-120)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/logger/logger.go (3)
  • With (276-281)
  • WithError (284-289)
  • Warn (259-261)
pkg/db/transaction_middleware.go (2)
pkg/errors/errors.go (1)
  • GeneralError (261-263)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/handlers/framework.go (2)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/logger/logger.go (3)
  • With (276-281)
  • Info (253-255)
  • Error (265-267)
pkg/auth/helpers.go (3)
pkg/errors/errors.go (2)
  • ServiceErrorCode (75-75)
  • New (179-199)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/logger/logger.go (3)
  • WithError (284-289)
  • Warn (259-261)
  • Error (265-267)
pkg/api/presenters/error.go (1)
pkg/errors/errors.go (1)
  • ServiceError (105-120)
pkg/validators/schema_validator.go (1)
pkg/errors/errors.go (1)
  • ValidationDetail (97-102)
test/integration/clusters_test.go (1)
pkg/errors/errors.go (1)
  • Errors (163-176)
pkg/auth/auth_middleware.go (1)
pkg/errors/errors.go (1)
  • ErrorUnauthorized (86-86)
🪛 golangci-lint (2.5.0)
pkg/errors/errors.go

[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)

(typecheck)

🔇 Additional comments (22)
pkg/services/generic_test.go (1)

32-36: LGTM!

The error message format correctly updated to the new HYPERFLEET-CAT-NUM convention (HYPERFLEET-VAL-005), aligning with the RFC 9457 implementation. Test assertions remain valid.

pkg/api/error.go (4)

16-47: LGTM!

The SendNotFound function correctly implements RFC 9457 Problem Details format with proper header ordering (Content-Type before WriteHeader), UTC timestamp, and trace ID for correlation.


95-121: Pre-built panic body lacks runtime context.

The panicBody is built at init time and will not include timestamp or trace_id fields for specific error occurrences. This is acceptable for panic situations (where stability is prioritized), but worth noting for observability.


123-125: LGTM!

Simple and correct pointer helper.


49-79: This function is currently unused in the codebase.

SendUnauthorized has no call sites anywhere. The concern about hardcoded error codes cannot be verified against actual usage patterns, since the function is not being invoked anywhere yet. If this is new code awaiting integration, the concern may be valid for future implementation. However, the review comment's premise—that verification of call sites would demonstrate the issue—cannot be substantiated at this time.

Likely an incorrect or invalid review comment.

openapi/openapi.yaml (1)

40-40: Content-Type updates align with RFC 9457.

The application/problem+json content type is correctly applied to all error response definitions across endpoints. This is the standard media type for RFC 9457 Problem Details.

Reminder: ensure these changes are reflected in the TypeSpec source.

pkg/errors/errors.go (4)

13-27: LGTM! Well-structured RFC 9457 type URIs.

The error type URI constants follow a clean hierarchy with a consistent base URL pattern. This aligns well with RFC 9457's recommendation to use URIs as problem type identifiers.


29-72: Well-organized error code taxonomy.

The HYPERFLEET-CAT-NUM format provides clear categorization (VAL, AUT, AUZ, NTF, CNF, LMT, INT, SVC) that maps logically to HTTP status code ranges. This will aid in debugging and log correlation.


221-253: AsProblemDetails implementation correctly follows RFC 9457.

The method properly populates all required fields (type, title, status) and optional fields (detail, instance) with HyperFleet extensions (code, timestamp, trace_id). The validation errors array conversion is handled correctly.

One minor observation: the timestamp is generated at conversion time (line 223). If the error is created much earlier and converted later, the timestamp reflects conversion time rather than error occurrence time. This is likely acceptable for most use cases.


9-9: Static analysis false positive - ignore import error.

The golangci-lint error about the missing openapi module is a sandbox environment issue, not a real problem. The module exists in the actual project.

pkg/auth/helpers.go (1)

12-29: LGTM! Clean RFC 9457 error handling.

The function correctly:

  • Extracts trace ID with a sensible fallback
  • Safely handles nil request when extracting instance path
  • Applies appropriate log levels based on HTTP status code
  • Uses the new AsProblemDetails method for RFC 9457 compliance
pkg/auth/auth_middleware.go (1)

29-29: LGTM! Correctly passes request for RFC 9457 instance field.

The addition of r parameter enables the handleError function to extract the URL path for the Problem Details instance field, improving error traceability.

pkg/validators/schema_validator.go (1)

139-149: LGTM! Field name updates align with ValidationDetail struct.

The changes correctly map to the new Message field in ValidationDetail. The Constraint and Value fields could optionally be populated for richer validation feedback, but the current implementation is sufficient for the RFC 9457 migration.

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

8-11: PresentError is a new function with no current callers—the breaking change premise is not applicable.

The implementation correctly delegates to AsProblemDetails, which is properly called with instance and traceID parameters throughout the codebase. Since PresentError itself has no callers, there are no existing usages to update. This appears to be a new presenter function that can be adopted when needed, rather than a change affecting existing code.

pkg/handlers/framework.go (1)

31-49: LGTM! RFC 9457 error handling implementation looks correct.

The error handling follows the new Problem Details format properly:

  • Uses structured logging with logger.With() per the coding guidelines
  • Correctly differentiates log levels between client errors (Info) and server errors (Error)
  • Passes instance (request path) and traceID to AsProblemDetails() as required by RFC 9457

One minor note: the variable is named traceID but is retrieved via GetRequestID(). This semantic mismatch is acceptable since the underlying context key remains the same, but consider adding a brief comment clarifying this mapping for future maintainers.

pkg/middleware/schema_validation.go (1)

15-37: LGTM! Validation error handling correctly implements RFC 9457 Problem Details.

The implementation properly:

  • Sets Content-Type: application/problem+json as required by RFC 9457
  • Uses request path as the instance field
  • Logs validation errors at Warn level (appropriate for client errors)
  • Handles encoding failures gracefully with error logging
pkg/middleware/schema_validation_test.go (2)

108-113: LGTM! Test assertions correctly updated for RFC 9457 field names.

The change from Reason to Detail aligns with the RFC 9457 Problem Details specification where detail is the standard field for human-readable error explanation.


347-352: LGTM! Assertion updated to use RFC 9457 Detail field.

Correctly validates that the error message about invalid spec type is present in the Detail field.

pkg/validators/schema_validator_test.go (1)

186-188: LGTM! Test updated to use renamed Message field in ValidationDetail.

The assertion correctly references Details[0].Message instead of the previous Details[0].Error, aligning with the RFC 9457 ValidationError schema that uses message for the human-readable validation error description.

test/integration/clusters_test.go (3)

365-371: LGTM! Test assertion updated for RFC 9457 Detail field.

Correctly validates that error responses include the Detail field when schema validation rejects invalid spec types.


437-451: LGTM! Test assertions updated for RFC 9457 error format.

The changes correctly validate:

  • Error code format changed to HYPERFLEET-VAL-000 (RFC 9457 style)
  • Field-level errors accessed via Errors array instead of Details
  • Iteration over validation errors uses the new structure

491-508: LGTM! Comprehensive RFC 9457 Problem Details validation.

The test now properly validates all RFC 9457 fields:

  • Type and Title for error classification
  • Detail for human-readable explanation
  • Instance for the request path
  • TraceId for correlation
  • Acceptable error codes include both validation (VAL-000) and malformed request (VAL-006)

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@rafabene
Copy link
Contributor Author

/retest

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

Caution

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

⚠️ Outside diff range comments (4)
pkg/api/error.go (1)

81-93: Missing WriteHeader call results in HTTP 200 status for panic responses.

SendPanic sets the Content-Type header but never calls WriteHeader(http.StatusInternalServerError). When w.Write(panicBody) is called, Go's http.ResponseWriter will implicitly send HTTP 200 OK. This contradicts the Status: 500 in the JSON body and violates RFC 9457, which requires the HTTP status code to match the status member.

🐛 Proposed fix
 func SendPanic(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/problem+json")
+	w.WriteHeader(http.StatusInternalServerError)
 	_, err := w.Write(panicBody)
pkg/auth/helpers.go (1)

31-46: Consolidate duplicate writeProblemDetailsResponse and adopt structured logging.

This function is nearly identical to the one in pkg/db/transaction_middleware.go. Additionally, the implementation in pkg/handlers/helpers.go demonstrates the preferred pattern with structured logging and contextual information (via logger.With(r.Context())), which aligns with the coding guidelines requiring structured logging. Consider consolidating these implementations and updating to use structured logging with contextual details.

test/integration/clusters_test.go (2)

698-706: Inconsistent with RFC 9457 migration: still uses reason field.

This test checks for the old reason field, but the API now returns RFC 9457 Problem Details with detail. This will likely fail at runtime.

🔧 Proposed fix to align with RFC 9457
 	// Parse error response
-	var errorResponse map[string]interface{}
-	err = json.Unmarshal(restyResp.Body(), &errorResponse)
+	var errorResponse openapi.Error
+	err = json.Unmarshal(restyResp.Body(), &errorResponse)
 	Expect(err).ToNot(HaveOccurred())
 
 	// Verify error message contains "kind is required"
-	reason, ok := errorResponse["reason"].(string)
-	Expect(ok).To(BeTrue())
-	Expect(reason).To(ContainSubstring("kind is required"))
+	Expect(errorResponse.Detail).ToNot(BeNil())
+	Expect(*errorResponse.Detail).To(ContainSubstring("kind is required"))

733-741: Inconsistent with RFC 9457 migration: still uses reason field.

Same issue as TestClusterPost_EmptyKind - this test checks for the old reason field instead of RFC 9457's detail.

🔧 Proposed fix to align with RFC 9457
 	// Parse error response
-	var errorResponse map[string]interface{}
-	err = json.Unmarshal(restyResp.Body(), &errorResponse)
+	var errorResponse openapi.Error
+	err = json.Unmarshal(restyResp.Body(), &errorResponse)
 	Expect(err).ToNot(HaveOccurred())
 
 	// Verify error message contains "kind must be 'Cluster'"
-	reason, ok := errorResponse["reason"].(string)
-	Expect(ok).To(BeTrue())
-	Expect(reason).To(ContainSubstring("kind must be 'Cluster'"))
+	Expect(errorResponse.Detail).ToNot(BeNil())
+	Expect(*errorResponse.Detail).To(ContainSubstring("kind must be 'Cluster'"))
🤖 Fix all issues with AI agents
In `@pkg/errors/errors.go`:
- Around line 244-247: detail.Constraint is being blindly cast to
openapi.ValidationErrorConstraint and assigned to validationErrors[i].Constraint
which can introduce invalid enum values; update the code that assigns
validationErrors[i].Constraint to first validate detail.Constraint against the
allowed openapi.ValidationErrorConstraint values (e.g., use a switch/lookup or
an IsValid helper for openapi.ValidationErrorConstraint), and only set the
pointer when the value is known-valid (otherwise leave it nil or set a safe
default like an "unknown" enum); ensure you reference detail.Constraint,
openapi.ValidationErrorConstraint, and validationErrors[i].Constraint when
making the change.
- Line 139: The ErrorNotImplemented entry uses the wrong HTTP status; update the
tuple for ErrorNotImplemented (referencing ErrorNotImplemented,
CodeNotImplemented, ErrorTypeNotImpl) to use http.StatusNotImplemented (501)
instead of http.StatusMethodNotAllowed (405) so the error correctly represents
unimplemented functionality.
♻️ Duplicate comments (1)
openapi/openapi.yaml (1)

917-995: Ensure changes were made in the TypeSpec source repository.

As noted in the coding guidelines, openapi/openapi.yaml is generated from TypeSpec in the hyperfleet-api-spec repository and should not be manually edited. Please confirm these RFC 9457 schema changes (Error, ValidationError) were made in the TypeSpec source first, then the compiled YAML was copied here.

🧹 Nitpick comments (2)
pkg/db/transaction_middleware.go (1)

38-52: Code duplication with pkg/handlers/helpers.go.

This writeProblemDetailsResponse is similar to the one in pkg/handlers/helpers.go but lacks:

  1. The Vary: Authorization header
  2. Error logging when marshal/write fails

Consider extracting a shared helper to a common package (e.g., pkg/api/response) to avoid divergence. If extraction isn't feasible due to import cycles, at minimum add error logging for consistency:

♻️ Suggested improvement for error logging
 func writeProblemDetailsResponse(w http.ResponseWriter, code int, payload interface{}) {
 	w.Header().Set("Content-Type", "application/problem+json")
+	w.Header().Set("Vary", "Authorization")
 	w.WriteHeader(code)
 
 	if payload != nil {
 		response, err := json.Marshal(payload)
 		if err != nil {
-			// Log error but don't expose to client since headers already sent
+			logger.Error(context.Background(), "Failed to marshal Problem Details response payload")
 			return
 		}
 		if _, err := w.Write(response); err != nil {
-			// Response writing failed, nothing we can do at this point
+			logger.Error(context.Background(), "Failed to write Problem Details response body")
 			return
 		}
 	}
 }
pkg/handlers/framework.go (1)

32-33: Consider handling missing traceID consistently.

When logger.GetRequestID returns ok=false, the traceID will be an empty string. In pkg/auth/helpers.go (line 15), a missing traceID defaults to "unknown". Consider applying the same fallback here for consistency across the codebase.

♻️ Suggested fix
-	traceID, _ := logger.GetRequestID(r.Context())
+	traceID, ok := logger.GetRequestID(r.Context())
+	if !ok {
+		traceID = "unknown"
+	}
 	instance := r.URL.Path
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da15c80 and afac28b.

📒 Files selected for processing (16)
  • openapi/openapi.yaml
  • pkg/api/error.go
  • pkg/api/error_types.go
  • pkg/api/presenters/error.go
  • pkg/auth/auth_middleware.go
  • pkg/auth/helpers.go
  • pkg/db/transaction_middleware.go
  • pkg/errors/errors.go
  • pkg/handlers/framework.go
  • pkg/handlers/helpers.go
  • pkg/middleware/schema_validation.go
  • pkg/middleware/schema_validation_test.go
  • pkg/services/generic_test.go
  • pkg/validators/schema_validator.go
  • pkg/validators/schema_validator_test.go
  • test/integration/clusters_test.go
💤 Files with no reviewable changes (1)
  • pkg/api/error_types.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/validators/schema_validator_test.go
  • pkg/middleware/schema_validation_test.go
  • pkg/middleware/schema_validation.go
🧰 Additional context used
📓 Path-based instructions (8)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Retrieve database sessions from context via db.NewContext(ctx) rather than creating new GORM connections
Use context.Context for all operations to enable proper transaction lifecycle and cleanup
Use structured logging via logger.NewOCMLogger(ctx) with contextual information like operation ID, account ID, and transaction ID
Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Files:

  • pkg/handlers/framework.go
  • pkg/db/transaction_middleware.go
  • pkg/auth/auth_middleware.go
  • pkg/auth/helpers.go
  • pkg/services/generic_test.go
  • pkg/api/presenters/error.go
  • pkg/validators/schema_validator.go
  • test/integration/clusters_test.go
  • pkg/api/error.go
  • pkg/handlers/helpers.go
  • pkg/errors/errors.go
pkg/handlers/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

pkg/handlers/**/*.go: All HTTP handlers must use the pattern: parse request → call service/DAO → handle errors → send response
Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses
Database sessions are stored in request context via middleware - always retrieve from context, never create new connections

Files:

  • pkg/handlers/framework.go
  • pkg/handlers/helpers.go
pkg/db/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Configure database connection pooling via db.DB().SetMaxOpenConns() and SetMaxIdleConns()

Files:

  • pkg/db/transaction_middleware.go
pkg/**/auth*.go

📄 CodeRabbit inference engine (AGENTS.md)

Validate JWT tokens from Red Hat SSO and extract account ID and username from claims for authentication

Files:

  • pkg/auth/auth_middleware.go
openapi/openapi.yaml

📄 CodeRabbit inference engine (AGENTS.md)

openapi/openapi.yaml: Do not manually edit openapi/openapi.yaml - it is generated from TypeSpec. Only edit the source file in hyperfleet-api-spec repository
Only edit the source openapi/openapi.yaml file; the fully resolved pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Files:

  • openapi/openapi.yaml
pkg/{services,dao}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Increment the generation field on each spec update to enable optimistic concurrency control

Files:

  • pkg/services/generic_test.go
test/integration/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

All integration tests must use Testcontainers to create isolated PostgreSQL instances for each test

Files:

  • test/integration/clusters_test.go
test/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use test factories in test/factories/ to provide consistent test data instead of creating test data inline

Files:

  • test/integration/clusters_test.go
🧠 Learnings (14)
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses

Applied to files:

  • pkg/handlers/framework.go
  • pkg/db/transaction_middleware.go
  • pkg/auth/auth_middleware.go
  • pkg/auth/helpers.go
  • pkg/api/presenters/error.go
  • pkg/api/error.go
  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Applied to files:

  • pkg/handlers/framework.go
  • pkg/auth/helpers.go
  • pkg/api/error.go
  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured logging via logger.NewOCMLogger(ctx) with contextual information like operation ID, account ID, and transaction ID

Applied to files:

  • pkg/handlers/framework.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : All HTTP handlers must use the pattern: parse request → call service/DAO → handle errors → send response

Applied to files:

  • pkg/handlers/framework.go
  • pkg/auth/helpers.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/framework.go
  • pkg/db/transaction_middleware.go
  • pkg/auth/auth_middleware.go
  • pkg/auth/helpers.go
  • pkg/services/generic_test.go
  • pkg/api/presenters/error.go
  • pkg/validators/schema_validator.go
  • test/integration/clusters_test.go
  • pkg/api/error.go
  • pkg/handlers/helpers.go
  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to pkg/**/auth*.go : Validate JWT tokens from Red Hat SSO and extract account ID and username from claims for authentication

Applied to files:

  • pkg/auth/auth_middleware.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to openapi/openapi.yaml : Do not manually edit openapi/openapi.yaml - it is generated from TypeSpec. Only edit the source file in hyperfleet-api-spec repository

Applied to files:

  • openapi/openapi.yaml
📚 Learning: 2026-01-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to openapi/openapi.yaml : Only edit the source openapi/openapi.yaml file; the fully resolved pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Applied to files:

  • openapi/openapi.yaml
📚 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:

  • openapi/openapi.yaml
📚 Learning: 2026-01-13T10:10:34.485Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/telemetry/otel.go:10-10
Timestamp: 2026-01-13T10:10:34.485Z
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-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to test/**/*.go : Use test factories in test/factories/ to provide consistent test data instead of creating test data inline

Applied to files:

  • pkg/services/generic_test.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/{services,dao}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control

Applied to files:

  • pkg/services/generic_test.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/api/*embed*.go : Embed the OpenAPI specification at compile time using //go:embed directive

Applied to files:

  • pkg/api/error.go
🧬 Code graph analysis (10)
pkg/handlers/framework.go (2)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/logger/logger.go (3)
  • With (276-281)
  • Info (253-255)
  • Error (265-267)
pkg/db/transaction_middleware.go (2)
pkg/errors/errors.go (1)
  • GeneralError (261-263)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/auth/auth_middleware.go (1)
pkg/errors/errors.go (1)
  • ErrorUnauthorized (86-86)
pkg/auth/helpers.go (3)
pkg/errors/errors.go (2)
  • ServiceErrorCode (75-75)
  • New (179-199)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/logger/logger.go (3)
  • WithError (284-289)
  • Warn (259-261)
  • Error (265-267)
pkg/api/presenters/error.go (1)
pkg/errors/errors.go (1)
  • ServiceError (105-120)
pkg/validators/schema_validator.go (2)
pkg/errors/errors.go (1)
  • ValidationDetail (97-102)
pkg/logger/logger.go (1)
  • Error (265-267)
test/integration/clusters_test.go (1)
pkg/errors/errors.go (1)
  • Errors (163-176)
pkg/api/error.go (3)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/logger/logger.go (2)
  • Error (265-267)
  • WithError (284-289)
pkg/errors/errors.go (6)
  • ErrorTypeNotFound (19-19)
  • CodeNotFoundGeneric (48-48)
  • ErrorTypeAuth (17-17)
  • CodeAuthNoCredentials (39-39)
  • ErrorTypeInternal (22-22)
  • CodeInternalGeneral (60-60)
pkg/handlers/helpers.go (2)
pkg/logger/logger.go (3)
  • With (276-281)
  • WithError (284-289)
  • Error (265-267)
pkg/logger/http.go (3)
  • HTTPPath (24-26)
  • HTTPMethod (19-21)
  • HTTPStatusCode (29-31)
pkg/errors/errors.go (2)
pkg/logger/logger.go (2)
  • With (276-281)
  • Error (265-267)
pkg/logger/fields.go (1)
  • FieldErrorCode (52-52)
🪛 golangci-lint (2.5.0)
pkg/errors/errors.go

[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)

(typecheck)

🔇 Additional comments (18)
pkg/services/generic_test.go (1)

29-50: LGTM! Error message expectations correctly updated for RFC 9457 error codes.

The test expectations have been properly updated to reflect the new HYPERFLEET-VAL-005 validation error code format. The tests correctly verify both the error code (errors.ErrorBadRequest) and the full error message string, ensuring the new error format is properly validated.

pkg/handlers/helpers.go (1)

41-67: LGTM! Well-structured RFC 9457 response helper.

The implementation correctly:

  • Sets Content-Type: application/problem+json per RFC 9457
  • Includes proper structured logging with context on marshal/write failures
  • Mirrors the existing writeJSONResponse pattern for consistency
pkg/db/transaction_middleware.go (1)

20-22: Approve error handling update to RFC 9457 format.

The transition to AsProblemDetails(r.URL.Path, traceID) correctly provides:

  • Request path as the instance field per RFC 9457
  • Trace ID for distributed tracing correlation
openapi/openapi.yaml (1)

40-41: Content-Type migration to application/problem+json looks correct.

The default error responses across all endpoints now correctly use application/problem+json as required by RFC 9457.

pkg/errors/errors.go (3)

9-9: Ignore static analysis import error.

The pkg/api/openapi package is generated via make generate and isn't available until code generation runs. Based on learnings, this is a known false positive from linters running before generation.


221-253: Well-designed RFC 9457 Problem Details conversion.

The AsProblemDetails method correctly:

  • Populates all RFC 9457 required fields (type, title, status)
  • Includes HyperFleet extensions (code, timestamp, trace_id)
  • Converts validation details to the nested errors array
  • Uses pointer types for optional fields per OpenAPI spec

132-146: Error catalog is well-organized.

The errorDefinitions map provides a clean single source of truth for all error types with consistent structure. This approach simplifies maintenance and ensures RFC 9457 compliance across all error responses.

pkg/validators/schema_validator.go (1)

139-149: LGTM! Field mapping updated for RFC 9457 alignment.

The ValidationDetail now correctly uses the Message field (instead of the previous Error field), matching the updated struct definition in pkg/errors/errors.go. The mapping logic remains correct:

  • SchemaError.ReasonValidationDetail.Message
  • Generic error string → ValidationDetail.Message
pkg/auth/auth_middleware.go (1)

29-29: LGTM!

The addition of the request parameter r to handleError correctly enables RFC 9457 Problem Details to include the instance field (request path) and traceID for better error traceability.

pkg/handlers/framework.go (1)

35-48: LGTM!

The logging correctly uses the new RFC9457Code format, and the response is properly written using writeProblemDetailsResponse with the Problem Details payload. The client/server error distinction for log levels is preserved.

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

8-11: LGTM!

The updated signature correctly accepts instance and traceID parameters for RFC 9457 compliance, and the implementation cleanly delegates to AsProblemDetails. This aligns with the broader error handling refactor.

pkg/auth/helpers.go (1)

12-29: LGTM!

The updated handleError function correctly:

  • Falls back to "unknown" when traceID is unavailable
  • Safely handles nil request with the guard at line 19
  • Uses the new writeProblemDetailsResponse for RFC 9457 compliant responses
pkg/api/error.go (3)

16-47: LGTM!

SendNotFound correctly implements RFC 9457 Problem Details with all required fields: Type, Title, Status, Detail, Instance, Code, Timestamp, and TraceId. Headers are set before WriteHeader, which is the correct order.


49-79: LGTM!

SendUnauthorized correctly implements RFC 9457 Problem Details with appropriate auth-specific type and code values.


99-125: LGTM!

The static panicBody initialization correctly excludes Timestamp and TraceId since these require runtime context. The ptrString helper is a common Go pattern for creating string pointers.

test/integration/clusters_test.go (3)

365-371: LGTM!

The assertion correctly validates the Detail field per RFC 9457 Problem Details format.


437-451: LGTM!

The validation correctly checks for:

  • RFC 9457-style error code (HYPERFLEET-VAL-000)
  • Field-level validation errors in the Errors array
  • Proper nil-safety when iterating over errors

491-508: LGTM!

Thorough validation of the RFC 9457 Problem Details structure including Type, Title, Detail, Instance, and TraceId fields. The flexible acceptance of both validation error codes is appropriate.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

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: 0

Caution

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

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

81-93: Missing WriteHeader call will return HTTP 200 instead of 500.

SendPanic sets the Content-Type but never calls WriteHeader(http.StatusInternalServerError) before writing the body. Go's http.ResponseWriter defaults to 200 OK when Write is called without WriteHeader. The response body will contain "status": 500, but the actual HTTP status code will be 200, creating an inconsistency that violates RFC 9457 and confuses clients.

🐛 Proposed fix
 func SendPanic(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/problem+json")
+	w.WriteHeader(http.StatusInternalServerError)
 	_, err := w.Write(panicBody)
♻️ Duplicate comments (2)
openapi/openapi.yaml (1)

917-995: Confirm these changes originate from the TypeSpec source.

As noted in the previous review, this file should be generated from TypeSpec in the hyperfleet-api-spec repository. Please confirm the RFC 9457 Error and ValidationError schema changes were made in the TypeSpec source first, then compiled and copied here.

Based on learnings, do not manually edit openapi/openapi.yaml.

pkg/errors/errors.go (1)

139-139: Use http.StatusNotImplemented (501) instead of http.StatusMethodNotAllowed (405).

The ErrorNotImplemented error is used for operations that are not implemented (e.g., unimplemented DAO methods, DELETE operations). Per RFC 7231:

  • 405 Method Not Allowed: The server recognizes the method but the target resource doesn't allow it
  • 501 Not Implemented: The server doesn't support the functionality required

Since this error represents "not implemented functionality," 501 is semantically correct.

🔧 Suggested fix
-	ErrorNotImplemented:       {ErrorNotImplemented, CodeNotImplemented, ErrorTypeNotImpl, "Not Implemented", "HTTP Method not implemented for this endpoint", http.StatusMethodNotAllowed},
+	ErrorNotImplemented:       {ErrorNotImplemented, CodeNotImplemented, ErrorTypeNotImpl, "Not Implemented", "HTTP Method not implemented for this endpoint", http.StatusNotImplemented},
🧹 Nitpick comments (1)
pkg/auth/helpers.go (1)

31-46: Consider adding error logging for debugging purposes.

The silent error handling on lines 37-44 is technically correct (headers are already sent), but logging these failures could aid debugging in production.

🔧 Optional: Add error logging
 func writeProblemDetailsResponse(w http.ResponseWriter, code int, payload interface{}) {
 	w.Header().Set("Content-Type", "application/problem+json")
 	w.WriteHeader(code)

 	if payload != nil {
 		response, err := json.Marshal(payload)
 		if err != nil {
-			// Headers already sent, can't change status code
+			// Headers already sent, can't change status code - log for debugging
+			logger.Error(context.Background(), "Failed to marshal problem details response")
 			return
 		}
 		if _, err := w.Write(response); err != nil {
-			// Writing failed, nothing we can do at this point
+			// Writing failed - log for debugging
+			logger.Error(context.Background(), "Failed to write problem details response")
 			return
 		}
 	}
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between afac28b and dfe8b77.

📒 Files selected for processing (17)
  • openapi/openapi.yaml
  • pkg/api/error.go
  • pkg/api/error_types.go
  • pkg/api/presenters/error.go
  • pkg/auth/auth_middleware.go
  • pkg/auth/helpers.go
  • pkg/db/transaction_middleware.go
  • pkg/errors/errors.go
  • pkg/handlers/framework.go
  • pkg/handlers/helpers.go
  • pkg/middleware/schema_validation.go
  • pkg/middleware/schema_validation_test.go
  • pkg/services/generic_test.go
  • pkg/validators/schema_validator.go
  • pkg/validators/schema_validator_test.go
  • test/integration/clusters_test.go
  • test/integration/node_pools_test.go
💤 Files with no reviewable changes (1)
  • pkg/api/error_types.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • pkg/validators/schema_validator_test.go
  • pkg/db/transaction_middleware.go
  • pkg/handlers/framework.go
  • pkg/handlers/helpers.go
🧰 Additional context used
📓 Path-based instructions (6)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Retrieve database sessions from context via db.NewContext(ctx) rather than creating new GORM connections
Use context.Context for all operations to enable proper transaction lifecycle and cleanup
Use structured logging via logger.NewOCMLogger(ctx) with contextual information like operation ID, account ID, and transaction ID
Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Files:

  • pkg/services/generic_test.go
  • test/integration/node_pools_test.go
  • pkg/validators/schema_validator.go
  • pkg/auth/auth_middleware.go
  • pkg/api/presenters/error.go
  • pkg/middleware/schema_validation_test.go
  • pkg/api/error.go
  • pkg/auth/helpers.go
  • pkg/middleware/schema_validation.go
  • test/integration/clusters_test.go
  • pkg/errors/errors.go
pkg/{services,dao}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Increment the generation field on each spec update to enable optimistic concurrency control

Files:

  • pkg/services/generic_test.go
test/integration/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

All integration tests must use Testcontainers to create isolated PostgreSQL instances for each test

Files:

  • test/integration/node_pools_test.go
  • test/integration/clusters_test.go
test/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use test factories in test/factories/ to provide consistent test data instead of creating test data inline

Files:

  • test/integration/node_pools_test.go
  • test/integration/clusters_test.go
pkg/**/auth*.go

📄 CodeRabbit inference engine (AGENTS.md)

Validate JWT tokens from Red Hat SSO and extract account ID and username from claims for authentication

Files:

  • pkg/auth/auth_middleware.go
openapi/openapi.yaml

📄 CodeRabbit inference engine (AGENTS.md)

openapi/openapi.yaml: Do not manually edit openapi/openapi.yaml - it is generated from TypeSpec. Only edit the source file in hyperfleet-api-spec repository
Only edit the source openapi/openapi.yaml file; the fully resolved pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Files:

  • openapi/openapi.yaml
🧠 Learnings (13)
📚 Learning: 2026-01-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to test/**/*.go : Use test factories in test/factories/ to provide consistent test data instead of creating test data inline

Applied to files:

  • pkg/services/generic_test.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/{services,dao}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control

Applied to files:

  • pkg/services/generic_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/services/generic_test.go
  • test/integration/node_pools_test.go
  • pkg/validators/schema_validator.go
  • pkg/auth/auth_middleware.go
  • pkg/api/presenters/error.go
  • pkg/middleware/schema_validation_test.go
  • pkg/api/error.go
  • pkg/auth/helpers.go
  • pkg/middleware/schema_validation.go
  • test/integration/clusters_test.go
  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to pkg/**/auth*.go : Validate JWT tokens from Red Hat SSO and extract account ID and username from claims for authentication

Applied to files:

  • pkg/auth/auth_middleware.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses

Applied to files:

  • pkg/auth/auth_middleware.go
  • pkg/api/presenters/error.go
  • pkg/api/error.go
  • pkg/auth/helpers.go
  • pkg/middleware/schema_validation.go
  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to openapi/openapi.yaml : Do not manually edit openapi/openapi.yaml - it is generated from TypeSpec. Only edit the source file in hyperfleet-api-spec repository

Applied to files:

  • openapi/openapi.yaml
📚 Learning: 2026-01-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to openapi/openapi.yaml : Only edit the source openapi/openapi.yaml file; the fully resolved pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Applied to files:

  • openapi/openapi.yaml
📚 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:

  • openapi/openapi.yaml
📚 Learning: 2026-01-13T10:10:34.485Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/telemetry/otel.go:10-10
Timestamp: 2026-01-13T10:10:34.485Z
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-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Applied to files:

  • pkg/api/error.go
  • pkg/auth/helpers.go
  • pkg/middleware/schema_validation.go
  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/api/*embed*.go : Embed the OpenAPI specification at compile time using //go:embed directive

Applied to files:

  • pkg/api/error.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : All HTTP handlers must use the pattern: parse request → call service/DAO → handle errors → send response

Applied to files:

  • pkg/auth/helpers.go
🧬 Code graph analysis (7)
pkg/validators/schema_validator.go (1)
pkg/errors/errors.go (1)
  • ValidationDetail (97-102)
pkg/auth/auth_middleware.go (1)
pkg/errors/errors.go (1)
  • ErrorUnauthorized (86-86)
pkg/api/presenters/error.go (1)
pkg/errors/errors.go (1)
  • ServiceError (105-120)
pkg/api/error.go (3)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/logger/logger.go (2)
  • Error (265-267)
  • WithError (284-289)
pkg/errors/errors.go (6)
  • ErrorTypeNotFound (19-19)
  • CodeNotFoundGeneric (48-48)
  • ErrorTypeAuth (17-17)
  • CodeAuthNoCredentials (39-39)
  • ErrorTypeInternal (22-22)
  • CodeInternalGeneral (60-60)
pkg/auth/helpers.go (3)
pkg/errors/errors.go (2)
  • ServiceErrorCode (75-75)
  • New (179-199)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/logger/logger.go (3)
  • WithError (284-289)
  • Warn (259-261)
  • Error (265-267)
pkg/middleware/schema_validation.go (3)
pkg/errors/errors.go (1)
  • ServiceError (105-120)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/logger/logger.go (3)
  • With (276-281)
  • WithError (284-289)
  • Warn (259-261)
test/integration/clusters_test.go (1)
pkg/errors/errors.go (1)
  • Errors (163-176)
🪛 Gitleaks (8.30.0)
pkg/errors/errors.go

[high] 39-39: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 40-40: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 41-41: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 44-44: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 45-45: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 golangci-lint (2.5.0)
pkg/errors/errors.go

[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)

(typecheck)

🔇 Additional comments (26)
pkg/api/error.go (3)

16-47: LGTM! Well-structured RFC 9457 Problem Details implementation.

The SendNotFound function correctly implements the RFC 9457 format with proper Content-Type, trace ID extraction, timestamp, and all required fields.


49-79: LGTM!

Consistent implementation with SendNotFound, properly using the authentication error type and code constants.


99-125: LGTM!

Pre-building panicBody at startup is a sound design choice for a last-resort error response. The ptrString helper is clean.

pkg/services/generic_test.go (1)

29-37: LGTM!

Test expectations correctly updated to use the new HYPERFLEET-VAL-005 error code format, aligning with the RFC 9457 error catalog migration.

pkg/auth/auth_middleware.go (1)

29-29: LGTM!

Passing the request r to handleError enables extraction of the URL path and trace ID for the RFC 9457 Problem Details response.

pkg/validators/schema_validator.go (1)

139-149: LGTM!

Field assignments correctly updated to use Message instead of Error, aligning with the ValidationDetail struct definition and RFC 9457 conventions.

pkg/middleware/schema_validation.go (2)

15-37: LGTM! RFC 9457 Problem Details implementation looks correct.

The handleValidationError function properly:

  • Retrieves traceID from context with appropriate fallback
  • Sets the correct Content-Type: application/problem+json
  • Uses AsProblemDetails(r.URL.Path, traceID) to build the RFC 9457 compliant response
  • Logs appropriately at warn level for client errors

Based on learnings, this correctly uses logger.With(ctx, ...) for structured logging.


39-109: Middleware correctly integrates RFC 9457 error responses.

All error paths consistently use handleValidationError which produces RFC 9457 Problem Details responses. The body restoration pattern (line 62) ensures downstream handlers still have access to the request body.

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

8-11: LGTM! Clean RFC 9457 presenter implementation.

The updated signature correctly accepts instance and traceID parameters and delegates to AsProblemDetails. This aligns with the PR-wide migration to RFC 9457 Problem Details.

test/integration/node_pools_test.go (2)

266-269: LGTM! Test correctly updated for RFC 9457 compliance.

The assertion now properly checks the detail field per RFC 9457 specification instead of the legacy reason field.


305-308: LGTM! Consistent with RFC 9457 migration.

Same pattern as above—correctly validates the detail field for the wrong kind error message.

pkg/middleware/schema_validation_test.go (2)

112-112: Potential inconsistency: missing pointer dereference.

Line 112 uses errorResponse.Detail directly with ToNot(BeNil()), while line 351 dereferences with *errorResponse.Detail. If Detail is a pointer field in openapi.Error (which appears to be the case based on line 351), this assertion may need adjustment for consistency.

However, ToNot(BeNil()) works correctly on pointer types, so this is functionally correct—just a minor stylistic inconsistency.


351-351: LGTM! Test correctly validates RFC 9457 detail field.

The assertion properly dereferences the pointer and checks that the detail contains the expected error message.

pkg/auth/helpers.go (1)

12-29: LGTM! RFC 9457 error handling implemented correctly.

The function properly:

  • Derives traceID from context with fallback
  • Sets instance from request path when available
  • Differentiates logging levels for client (4xx) vs server (5xx) errors
  • Uses AsProblemDetails(instance, traceID) for RFC 9457 compliance

Based on learnings, this correctly uses the structured error type from pkg/errors with HttpCode, Code, and Reason fields.

test/integration/clusters_test.go (5)

368-368: LGTM!

The assertion correctly validates the Detail field (RFC 9457's replacement for Reason) is present in validation error responses.


438-451: LGTM!

The test assertions properly validate the RFC 9457 Problem Details format:

  • Uses HYPERFLEET-VAL-000 code format
  • Checks Errors array for field-level validation details
  • Correctly accesses detail.Field from the ValidationError structure

491-507: LGTM!

Comprehensive validation of RFC 9457 Problem Details structure:

  • Verifies Type and Title presence
  • Accepts both HYPERFLEET-VAL-000 and HYPERFLEET-VAL-006 as valid validation error codes
  • Validates Detail, Instance, and TraceId fields

702-705: LGTM!

Correctly updated to extract the detail field (RFC 9457) instead of the legacy reason field for error message validation.


737-740: LGTM!

Consistent with the other test updates, correctly uses the detail field from RFC 9457 Problem Details format.

pkg/errors/errors.go (7)

13-27: LGTM!

Well-structured RFC 9457 error type URIs with a common base URL and clear categorization. The constant naming is consistent and follows Go conventions.


29-72: Gitleaks false positives - error codes are not API keys.

The static analysis tool incorrectly flagged lines 39-45 as "Generic API Key" detections. These are clearly error code constants (e.g., CodeAuthNoCredentials = "HYPERFLEET-AUT-001") following the RFC 9457 naming convention, not actual secrets.

The error code structure with HYPERFLEET-CAT-NUM format is well-organized and covers all necessary categories.


96-120: LGTM!

The ValidationDetail and ServiceError structs are well-designed for RFC 9457 compliance:

  • ValidationDetail captures field-level errors with optional value, constraint, and message
  • ServiceError includes both legacy (Code) and RFC 9457 (RFC9457Code, Type, Title) fields for backwards compatibility

221-241: LGTM - Addresses previous review concern.

The validConstraints map and isValidConstraint helper function properly validate constraint strings before converting to the openapi.ValidationErrorConstraint enum, preventing invalid enum values from being set.


243-276: LGTM!

The AsProblemDetails method correctly implements RFC 9457 Problem Details conversion:

  • Populates all required fields (Type, Title, Status)
  • Includes extension fields (Code, Timestamp, TraceId)
  • Uses the validated constraint conversion for field-level errors
  • Returns the struct by value which is appropriate for this size

300-307: Good backwards compatibility approach.

Providing both NotImplementedError and NotImplemented (as an alias) maintains backwards compatibility while following clearer naming conventions.


337-339: LGTM!

The DatabaseAdvisoryLock function correctly uses format string "%s" with err.Error() to safely pass the error message.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

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 `@pkg/auth/auth_middleware.go`:
- Around line 28-30: The JWT parsing failure currently calls handleError with
errors.ErrorUnauthorized (producing a 403) but should use
errors.ErrorUnauthenticated (401); update the error passed in the handleError
call in the jwt payload parsing block (the line calling handleError(ctx, w, r,
... "Unable to get payload details from JWT token: ...")) to
errors.ErrorUnauthenticated so authentication failures return 401 instead of
403.
♻️ Duplicate comments (1)
openapi/openapi.yaml (1)

917-995: Confirm this file was generated from TypeSpec source.

Per coding guidelines and past review comments, openapi/openapi.yaml should not be manually edited—it must be generated from TypeSpec definitions in the hyperfleet-api-spec repository. Please confirm these RFC 9457 schema changes (Error and ValidationError) were made in the TypeSpec source first, then compiled and copied here.

The schema changes themselves look correct for RFC 9457 compliance (required fields: type, title, status; proper ValidationError structure with constraint enum).

🧹 Nitpick comments (3)
test/integration/clusters_test.go (2)

697-706: Consider using typed error response for consistency.

This test uses map[string]interface{} while other tests use openapi.Error. Using the typed struct would provide compile-time safety and consistency with other tests in this file.

Suggested change
 	// Parse error response
-	var errorResponse map[string]interface{}
-	err = json.Unmarshal(restyResp.Body(), &errorResponse)
+	var errorResponse openapi.Error
+	err = json.Unmarshal(restyResp.Body(), &errorResponse)
 	Expect(err).ToNot(HaveOccurred())

 	// Verify error message contains "kind is required" (RFC 9457 uses "detail" field)
-	detail, ok := errorResponse["detail"].(string)
-	Expect(ok).To(BeTrue())
-	Expect(detail).To(ContainSubstring("kind is required"))
+	Expect(errorResponse.Detail).ToNot(BeNil())
+	Expect(*errorResponse.Detail).To(ContainSubstring("kind is required"))

732-741: Same suggestion: consider using openapi.Error for type safety.

This test could also benefit from using the typed openapi.Error struct for consistency with other tests in this file.

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

8-11: Nil check suggestion aligns with defensive programming but conflicts with codebase patterns.

The function is currently unused in the codebase. The existing error handling in handleError (pkg/handlers/framework.go) calls err.AsProblemDetails(instance, traceID) directly without nil checks, and AsProblemDetails itself performs field accesses without guarding against nil. This pattern suggests the design assumes err is always non-nil, consistent with Go convention where passing nil to error handlers is a caller bug. If err is nil, it indicates an issue upstream in error creation or validation, not in the error presenter.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dfe8b77 and 8648244.

📒 Files selected for processing (17)
  • openapi/openapi.yaml
  • pkg/api/error.go
  • pkg/api/error_types.go
  • pkg/api/presenters/error.go
  • pkg/auth/auth_middleware.go
  • pkg/auth/helpers.go
  • pkg/db/transaction_middleware.go
  • pkg/errors/errors.go
  • pkg/handlers/framework.go
  • pkg/handlers/helpers.go
  • pkg/middleware/schema_validation.go
  • pkg/middleware/schema_validation_test.go
  • pkg/services/generic_test.go
  • pkg/validators/schema_validator.go
  • pkg/validators/schema_validator_test.go
  • test/integration/clusters_test.go
  • test/integration/node_pools_test.go
💤 Files with no reviewable changes (1)
  • pkg/api/error_types.go
🚧 Files skipped from review as they are similar to previous changes (7)
  • pkg/handlers/framework.go
  • test/integration/node_pools_test.go
  • pkg/handlers/helpers.go
  • pkg/validators/schema_validator.go
  • pkg/db/transaction_middleware.go
  • pkg/validators/schema_validator_test.go
  • pkg/services/generic_test.go
🧰 Additional context used
📓 Path-based instructions (5)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Retrieve database sessions from context via db.NewContext(ctx) rather than creating new GORM connections
Use context.Context for all operations to enable proper transaction lifecycle and cleanup
Use structured logging via logger.NewOCMLogger(ctx) with contextual information like operation ID, account ID, and transaction ID
Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Files:

  • pkg/auth/helpers.go
  • pkg/api/error.go
  • test/integration/clusters_test.go
  • pkg/api/presenters/error.go
  • pkg/middleware/schema_validation.go
  • pkg/middleware/schema_validation_test.go
  • pkg/auth/auth_middleware.go
  • pkg/errors/errors.go
test/integration/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

All integration tests must use Testcontainers to create isolated PostgreSQL instances for each test

Files:

  • test/integration/clusters_test.go
test/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use test factories in test/factories/ to provide consistent test data instead of creating test data inline

Files:

  • test/integration/clusters_test.go
pkg/**/auth*.go

📄 CodeRabbit inference engine (AGENTS.md)

Validate JWT tokens from Red Hat SSO and extract account ID and username from claims for authentication

Files:

  • pkg/auth/auth_middleware.go
openapi/openapi.yaml

📄 CodeRabbit inference engine (AGENTS.md)

openapi/openapi.yaml: Do not manually edit openapi/openapi.yaml - it is generated from TypeSpec. Only edit the source file in hyperfleet-api-spec repository
Only edit the source openapi/openapi.yaml file; the fully resolved pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Files:

  • openapi/openapi.yaml
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses

Applied to files:

  • pkg/auth/helpers.go
  • pkg/api/error.go
  • pkg/api/presenters/error.go
  • pkg/middleware/schema_validation.go
  • pkg/auth/auth_middleware.go
  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Applied to files:

  • pkg/auth/helpers.go
  • pkg/api/error.go
  • pkg/middleware/schema_validation.go
  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : All HTTP handlers must use the pattern: parse request → call service/DAO → handle errors → send response

Applied to files:

  • pkg/auth/helpers.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/auth/helpers.go
  • pkg/api/error.go
  • test/integration/clusters_test.go
  • pkg/api/presenters/error.go
  • pkg/middleware/schema_validation.go
  • pkg/middleware/schema_validation_test.go
  • pkg/auth/auth_middleware.go
  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/api/*embed*.go : Embed the OpenAPI specification at compile time using //go:embed directive

Applied to files:

  • pkg/api/error.go
📚 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:

  • test/integration/clusters_test.go
  • openapi/openapi.yaml
📚 Learning: 2026-01-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to pkg/**/auth*.go : Validate JWT tokens from Red Hat SSO and extract account ID and username from claims for authentication

Applied to files:

  • pkg/auth/auth_middleware.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to openapi/openapi.yaml : Do not manually edit openapi/openapi.yaml - it is generated from TypeSpec. Only edit the source file in hyperfleet-api-spec repository

Applied to files:

  • openapi/openapi.yaml
📚 Learning: 2026-01-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to openapi/openapi.yaml : Only edit the source openapi/openapi.yaml file; the fully resolved pkg/api/openapi/api/openapi.yaml is auto-generated and will be overwritten

Applied to files:

  • openapi/openapi.yaml
📚 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:

  • openapi/openapi.yaml
📚 Learning: 2026-01-13T10:10:34.485Z
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/telemetry/otel.go:10-10
Timestamp: 2026-01-13T10:10:34.485Z
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
🧬 Code graph analysis (6)
pkg/api/error.go (3)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/logger/logger.go (2)
  • Error (265-267)
  • WithError (284-289)
pkg/errors/errors.go (6)
  • ErrorTypeNotFound (19-19)
  • CodeNotFoundGeneric (48-48)
  • ErrorTypeAuth (17-17)
  • CodeAuthNoCredentials (39-39)
  • ErrorTypeInternal (22-22)
  • CodeInternalGeneral (60-60)
test/integration/clusters_test.go (1)
pkg/errors/errors.go (1)
  • Errors (163-176)
pkg/api/presenters/error.go (1)
pkg/errors/errors.go (1)
  • ServiceError (105-120)
pkg/middleware/schema_validation.go (3)
pkg/errors/errors.go (1)
  • ServiceError (105-120)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/logger/logger.go (3)
  • With (276-281)
  • WithError (284-289)
  • Warn (259-261)
pkg/auth/auth_middleware.go (1)
pkg/errors/errors.go (1)
  • ErrorUnauthorized (86-86)
pkg/errors/errors.go (2)
pkg/logger/logger.go (2)
  • With (276-281)
  • Error (265-267)
pkg/logger/fields.go (1)
  • FieldErrorCode (52-52)
🪛 Gitleaks (8.30.0)
pkg/errors/errors.go

[high] 39-39: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 40-40: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 41-41: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 44-44: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 45-45: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 golangci-lint (2.5.0)
pkg/errors/errors.go

[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)

(typecheck)

🔇 Additional comments (19)
pkg/errors/errors.go (5)

13-72: LGTM! Well-structured RFC 9457 error constants.

The error type URIs and HYPERFLEET-CAT-NUM format codes are well-organized by category (VAL, AUT, AUZ, NTF, CNF, LMT, INT, SVC). This provides clear, machine-readable error identification for API consumers.

Note: The Gitleaks warnings on lines 39-45 are false positives—these are error code constants (e.g., HYPERFLEET-AUT-001), not API keys.


132-146: Good centralized error catalog with correct HTTP status codes.

The error definitions are well-organized. Note that ErrorNotImplemented now correctly uses http.StatusNotImplemented (501) instead of the previous 405, which properly reflects RFC 7231 semantics for unimplemented functionality.


221-241: Good defensive handling for constraint validation.

The validConstraints map and isValidConstraint helper properly address the enum validation concern. Unknown constraints are now silently omitted rather than potentially causing serialization issues with invalid enum values.


243-276: LGTM! RFC 9457 Problem Details conversion.

The AsProblemDetails method correctly populates all RFC 9457 fields (type, title, status, detail, instance) plus the HyperFleet extensions (code, timestamp, trace_id). The validation error conversion properly uses the isValidConstraint check before setting constraint values.


300-307: LGTM! Good backwards compatibility approach.

Providing both NotImplementedError and the NotImplemented alias maintains backwards compatibility while following the naming convention of other constructors.

pkg/auth/helpers.go (2)

12-29: LGTM! Clean RFC 9457 error handling implementation.

The handleError function properly:

  • Extracts trace ID from context with fallback to "unknown"
  • Derives instance URI from the request path (with null safety)
  • Differentiates client (4xx) vs server (5xx) error logging
  • Converts to Problem Details format via AsProblemDetails

31-45: LGTM! Correct Content-Type for RFC 9457.

The writeProblemDetailsResponse function correctly sets application/problem+json as required by RFC 9457. The silent error handling after headers are sent is appropriate since there's nothing more that can be done at that point.

pkg/middleware/schema_validation_test.go (2)

112-112: LGTM! Test updated for RFC 9457 field naming.

The assertion correctly changed from Reason to Detail to match the RFC 9457 Problem Details structure where the human-readable explanation is in the detail field.


351-351: LGTM! Proper pointer dereference for Detail field.

The test correctly dereferences *errorResponse.Detail since Detail is an optional field (*string) in the OpenAPI Error schema per RFC 9457.

pkg/middleware/schema_validation.go (3)

15-37: LGTM!

The handleValidationError function correctly:

  • Sets Content-Type: application/problem+json per RFC 9457
  • Uses AsProblemDetails(r.URL.Path, traceID) for consistent error formatting
  • Logs validation errors at warn level (appropriate for client errors)
  • Handles JSON encoding failures gracefully

39-109: LGTM!

The middleware correctly handles request body buffering, JSON parsing, and spec validation with proper error responses in RFC 9457 format throughout.


111-133: LGTM!

Path matching logic correctly identifies cluster and nodepool requests. The more specific /nodepools check is correctly placed before the broader /clusters check.

pkg/api/error.go (4)

16-48: LGTM!

SendNotFound correctly implements RFC 9457 Problem Details with all required fields. The implementation properly:

  • Sets Content-Type: application/problem+json
  • Includes Type, Title, Status, Detail, Instance, Code, Timestamp, and TraceId
  • Falls back to SendPanic on marshal failure

50-81: LGTM!

SendUnauthorized follows the same correct pattern as SendNotFound, properly formatting 401 responses in RFC 9457 Problem Details format.


83-96: LGTM!

SendPanic correctly uses a pre-built response body to avoid potential failures during error scenarios. The static panicBody appropriately omits dynamic fields like TraceId and Timestamp since this is a last-resort fallback.


102-128: LGTM!

The init() function correctly pre-builds the panic response body at startup, and ptrString is a clean helper for creating string pointers. Exiting on marshal failure is appropriate since this is critical initialization.

test/integration/clusters_test.go (3)

362-371: LGTM!

Test correctly updated to verify RFC 9457 Detail field instead of the old Reason field.


437-451: LGTM!

Test assertions correctly updated for RFC 9457:

  • Expects HYPERFLEET-VAL-000 code format
  • Uses Errors field for field-level validation details
  • Properly iterates over the errors array to find specific field violations

491-508: LGTM!

Comprehensive verification of RFC 9457 Problem Details structure:

  • Validates presence of Type, Title, Detail, Instance, and TraceId
  • Correctly accepts both validation error codes (HYPERFLEET-VAL-000 and HYPERFLEET-VAL-006)
  • Good debug logging for troubleshooting

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Refactor error handling to use RFC 9457 Problem Details format with
HyperFleet extension fields for consistent, standards-compliant API errors.

Changes:
- Update OpenAPI spec with ProblemDetails schema and application/problem+json
- Add error codes in HYPERFLEET-CAT-NUM format (VAL, AUT, AUZ, NTF, CNF, etc.)
- Add AsProblemDetails() method with type, title, status, detail, instance
- Include extension fields: code, timestamp, trace_id
- Add errors array for field-level validation details
- Update all handlers and middleware to use new error format
- Update tests for new error structure
- Remove legacy ServiceErrorCode type and numeric error constants
- Use RFC 9457 codes (HYPERFLEET-XXX-NNN) as map keys directly
- Consolidate WriteProblemDetailsResponse into pkg/api/response
- Fix SendPanic to include trace_id and timestamp dynamically
- Fix CodeAuthExpiredToken to return 401 instead of 403
- Remove unused NotImplementedError function
- Use error code constants in tests instead of hardcoded strings
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 `@pkg/errors/errors.go`:
- Around line 29-72: The error constants (e.g., CodeValidationRequired,
CodeValidationInvalid, CodeValidationFormat, CodeValidationRange,
CodeNotFoundCluster, CodeNotFoundNodePool, CodeConflictVersion,
CodeRateLimitExceeded, CodeServiceUnavailable, CodeServiceTimeout) are declared
but missing from the errorDefinitions map used by New/Find, causing
undefined/500 fallbacks; update the errorDefinitions variable in
pkg/errors/errors.go to include entries for each missing constant mapping to the
appropriate ErrorDefinition (status code, error type/category, human message,
and any metadata) so New/Find can resolve them correctly, or remove unused
constant declarations if they are not needed; reference the errorDefinitions map
and the New/Find functions when adding these mappings.
🧹 Nitpick comments (1)
pkg/api/response/problem_details.go (1)

12-28: Consider reordering WriteHeader after marshaling to avoid partial responses on error.

Currently, WriteHeader(code) is called before marshaling the payload (Line 16). If marshaling fails on Line 19-22, the client receives the status code but no body, resulting in an incomplete response. Moving WriteHeader after successful marshaling would allow for a fallback error response.

♻️ Suggested improvement
 func WriteProblemDetailsResponse(w http.ResponseWriter, r *http.Request, code int, payload interface{}) {
 	w.Header().Set("Content-Type", "application/problem+json")
 	w.Header().Set("Vary", "Authorization")
 
-	w.WriteHeader(code)
-
 	if payload != nil {
 		response, err := json.Marshal(payload)
 		if err != nil {
 			logResponseError(r.Context(), r, code, "Failed to marshal Problem Details response payload", err)
+			w.WriteHeader(http.StatusInternalServerError)
 			return
 		}
+		w.WriteHeader(code)
 		if _, err := w.Write(response); err != nil {
 			logResponseError(r.Context(), r, code, "Failed to write Problem Details response body", err)
 			return
 		}
+	} else {
+		w.WriteHeader(code)
 	}
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 931ff97 and fa9484a.

📒 Files selected for processing (10)
  • pkg/api/error.go
  • pkg/api/response/problem_details.go
  • pkg/auth/auth_middleware.go
  • pkg/auth/helpers.go
  • pkg/db/transaction_middleware.go
  • pkg/errors/errors.go
  • pkg/errors/errors_test.go
  • pkg/handlers/framework.go
  • pkg/services/generic_test.go
  • test/factories/node_pools.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/handlers/framework.go
🧰 Additional context used
📓 Path-based instructions (5)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Retrieve database sessions from context via db.NewContext(ctx) rather than creating new GORM connections
Use context.Context for all operations to enable proper transaction lifecycle and cleanup
Use structured logging via logger.NewOCMLogger(ctx) with contextual information like operation ID, account ID, and transaction ID
Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Files:

  • pkg/db/transaction_middleware.go
  • pkg/api/response/problem_details.go
  • test/factories/node_pools.go
  • pkg/api/error.go
  • pkg/auth/helpers.go
  • pkg/services/generic_test.go
  • pkg/errors/errors_test.go
  • pkg/errors/errors.go
  • pkg/auth/auth_middleware.go
pkg/db/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Configure database connection pooling via db.DB().SetMaxOpenConns() and SetMaxIdleConns()

Files:

  • pkg/db/transaction_middleware.go
test/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use test factories in test/factories/ to provide consistent test data instead of creating test data inline

Files:

  • test/factories/node_pools.go
pkg/{services,dao}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Increment the generation field on each spec update to enable optimistic concurrency control

Files:

  • pkg/services/generic_test.go
pkg/**/auth*.go

📄 CodeRabbit inference engine (AGENTS.md)

Validate JWT tokens from Red Hat SSO and extract account ID and username from claims for authentication

Files:

  • pkg/auth/auth_middleware.go
🧠 Learnings (16)
📓 Common learnings
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/telemetry/otel.go:10-10
Timestamp: 2026-01-13T10:10:34.485Z
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`.
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use context.Context for all operations to enable proper transaction lifecycle and cleanup

Applied to files:

  • pkg/db/transaction_middleware.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses

Applied to files:

  • pkg/db/transaction_middleware.go
  • pkg/api/error.go
  • pkg/auth/helpers.go
  • pkg/errors/errors.go
  • pkg/auth/auth_middleware.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/dao/**/*.go : All DAO methods must take context.Context as the first parameter for transaction propagation

Applied to files:

  • pkg/db/transaction_middleware.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Database sessions are stored in request context via middleware - always retrieve from context, never create new connections

Applied to files:

  • pkg/db/transaction_middleware.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Retrieve database sessions from context via db.NewContext(ctx) rather than creating new GORM connections

Applied to files:

  • pkg/db/transaction_middleware.go
📚 Learning: 2026-01-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to pkg/db/**/*.go : Configure database connection pooling via db.DB().SetMaxOpenConns() and SetMaxIdleConns()

Applied to files:

  • pkg/db/transaction_middleware.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/db/migrations/**/*.go : Store resource spec and conditions as JSONB in PostgreSQL for efficient querying

Applied to files:

  • pkg/db/transaction_middleware.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/db/transaction_middleware.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/db/transaction_middleware.go
  • pkg/api/response/problem_details.go
  • test/factories/node_pools.go
  • pkg/api/error.go
  • pkg/auth/helpers.go
  • pkg/services/generic_test.go
  • pkg/errors/errors_test.go
  • pkg/errors/errors.go
  • pkg/auth/auth_middleware.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Applied to files:

  • pkg/api/response/problem_details.go
  • pkg/api/error.go
  • pkg/auth/helpers.go
  • pkg/services/generic_test.go
  • pkg/errors/errors_test.go
  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/api/*embed*.go : Embed the OpenAPI specification at compile time using //go:embed directive

Applied to files:

  • pkg/api/error.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : All HTTP handlers must use the pattern: parse request → call service/DAO → handle errors → send response

Applied to files:

  • pkg/auth/helpers.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/{services,dao}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control

Applied to files:

  • pkg/services/generic_test.go
📚 Learning: 2026-01-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to test/**/*.go : Use test factories in test/factories/ to provide consistent test data instead of creating test data inline

Applied to files:

  • pkg/services/generic_test.go
📚 Learning: 2026-01-14T18:28:02.325Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.325Z
Learning: Applies to pkg/**/auth*.go : Validate JWT tokens from Red Hat SSO and extract account ID and username from claims for authentication

Applied to files:

  • pkg/auth/auth_middleware.go
🧬 Code graph analysis (6)
pkg/db/transaction_middleware.go (3)
pkg/errors/errors.go (1)
  • GeneralError (260-262)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/api/response/problem_details.go (1)
  • WriteProblemDetailsResponse (12-29)
pkg/api/error.go (3)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/logger/logger.go (2)
  • Error (265-267)
  • WithError (284-289)
pkg/errors/errors.go (6)
  • ErrorTypeNotFound (19-19)
  • CodeNotFoundGeneric (48-48)
  • ErrorTypeAuth (17-17)
  • CodeAuthNoCredentials (39-39)
  • ErrorTypeInternal (22-22)
  • CodeInternalGeneral (60-60)
pkg/auth/helpers.go (3)
pkg/logger/context.go (1)
  • GetRequestID (66-69)
pkg/errors/errors.go (1)
  • New (156-175)
pkg/api/response/problem_details.go (1)
  • WriteProblemDetailsResponse (12-29)
pkg/services/generic_test.go (1)
pkg/errors/errors.go (2)
  • CodeBadRequest (68-68)
  • ErrorTypeBadRequest (24-24)
pkg/errors/errors.go (2)
pkg/logger/logger.go (2)
  • With (276-281)
  • Error (265-267)
pkg/logger/fields.go (1)
  • FieldErrorCode (52-52)
pkg/auth/auth_middleware.go (1)
pkg/errors/errors.go (1)
  • CodeAuthNoCredentials (39-39)
🪛 Gitleaks (8.30.0)
pkg/errors/errors.go

[high] 39-39: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 40-40: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 41-41: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 44-44: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 45-45: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 golangci-lint (2.5.0)
pkg/errors/errors.go

[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)

(typecheck)

🔇 Additional comments (19)
pkg/errors/errors_test.go (2)

9-12: LGTM — updated error construction aligns with RFC 9457 codes.


15-25: LGTM — assertions now match Type and RFC9457Code semantics.

pkg/errors/errors.go (6)

13-27: RFC 9457 type URIs are clean and consistent.


76-98: ServiceError and ValidationDetail shape looks solid.


125-152: Find/Errors helpers are straightforward and consistent.


155-195: New/Error/Is updates align with the new RFC 9457 surface.*


197-251: Constraint validation + Problem Details projection looks good.


256-313: Constructor helpers look consistent with the new codes.

pkg/services/generic_test.go (1)

28-49: LGTM — assertions now align with CodeBadRequest and ErrorTypeBadRequest.

test/factories/node_pools.go (1)

43-47: LGTM — RFC9457Code check matches the new error model.

pkg/auth/auth_middleware.go (1)

27-30: LGTM — authentication failure now maps to CodeAuthNoCredentials.

pkg/db/transaction_middleware.go (1)

20-23: LGTM! Clean migration to RFC 9457 Problem Details format.

The error handling correctly uses the centralized WriteProblemDetailsResponse with proper trace ID extraction and Problem Details conversion. The use of GeneralError("") with an empty reason appropriately avoids exposing internal details to users.

pkg/api/response/problem_details.go (1)

31-37: LGTM! Good use of structured logging.

The helper correctly uses logger.With(ctx, ...) with structured fields as per the coding guidelines, replacing the deprecated NewOCMLogger. Based on learnings, this is the recommended approach.

pkg/auth/helpers.go (1)

12-28: LGTM! Clean refactoring to use centralized Problem Details response.

The signature update to accept *http.Request and string-based error code aligns with the RFC 9457 migration. The defensive nil check for the request (Line 19) and trace ID fallback (Line 15) are appropriate safety measures. The consolidation to response.WriteProblemDetailsResponse addresses the previous review feedback about code duplication.

pkg/api/error.go (5)

16-48: LGTM! Correct RFC 9457 Problem Details implementation for 404 responses.

The implementation correctly:

  • Sets Content-Type: application/problem+json
  • Includes all required RFC 9457 fields plus HyperFleet extensions (code, timestamp, trace_id)
  • Calls WriteHeader after marshaling, allowing proper fallback to SendPanic on error
  • Uses structured logging per coding guidelines

50-81: LGTM! Consistent implementation for 401 responses.

The implementation follows the same pattern as SendNotFound with appropriate error type (ErrorTypeAuth) and code (CodeAuthNoCredentials).


83-122: LGTM! Robust panic response implementation.

The dynamic trace_id and timestamp generation addresses the previous review feedback. The fallback to panicBody on marshal failure ensures clients always receive a response. Calling WriteHeader early (Line 88) is appropriate here since this is the last-resort error handler where reliability takes precedence.


128-150: LGTM! Appropriate fallback initialization.

The pre-computed panicBody without timestamp and trace_id is intentional for the static fallback scenario. The os.Exit(1) on marshal failure is appropriate since this is a critical startup error that would prevent proper error handling.


152-154: LGTM! Standard Go pointer helper.

Clean implementation of a common Go pattern for creating pointers to string values, needed for the optional fields in openapi.Error.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Add all declared error code constants to errorDefinitions map to prevent
undefined/500 fallbacks when using New/Find:
- CodeValidationRequired, CodeValidationInvalid, CodeValidationFormat, CodeValidationRange
- CodeNotFoundCluster, CodeNotFoundNodePool
- CodeConflictVersion
- CodeRateLimitExceeded
- CodeServiceUnavailable, CodeServiceTimeout

Also reorganized the map with comments grouping codes by category.
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 `@pkg/errors/errors.go`:
- Around line 244-277: In ServiceError.AsProblemDetails, avoid assigning
pointers to empty strings for Instance and TraceId: only set
problemDetails.Instance and problemDetails.TraceId when the input variables
instance and traceID are non-empty (i.e., check if instance != "" then set a
pointer to instance, same for traceID) so nil is preserved and fields are
omitted from JSON; keep the rest of the function (including the validation
errors handling) unchanged.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa9484a and 9ced81c.

📒 Files selected for processing (1)
  • pkg/errors/errors.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Retrieve database sessions from context via db.NewContext(ctx) rather than creating new GORM connections
Use context.Context for all operations to enable proper transaction lifecycle and cleanup
Use structured logging via logger.NewOCMLogger(ctx) with contextual information like operation ID, account ID, and transaction ID
Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Files:

  • pkg/errors/errors.go
🧠 Learnings (4)
📓 Common learnings
Learnt from: yasun1
Repo: openshift-hyperfleet/hyperfleet-api PR: 31
File: pkg/telemetry/otel.go:10-10
Timestamp: 2026-01-13T10:10:34.485Z
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.
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Applied to files:

  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses

Applied to files:

  • pkg/errors/errors.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/errors/errors.go
🪛 Gitleaks (8.30.0)
pkg/errors/errors.go

[high] 39-39: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 40-40: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 41-41: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 44-44: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 45-45: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 golangci-lint (2.5.0)
pkg/errors/errors.go

[error] 9-9: could not import github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi (pkg/errors/errors.go:9:2: no required module provides package github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi; to add it:
go get github.com/openshift-hyperfleet/hyperfleet-api/pkg/api/openapi)

(typecheck)

🔇 Additional comments (7)
pkg/errors/errors.go (7)

13-72: Clear RFC 9457 taxonomy and code grouping.
Nicely centralized and readable.


76-106: ServiceError and ValidationDetail shapes look solid.
Good, concise modeling of RFC 9457 + validation details.


108-148: Definitions map is complete and well-categorized.
Good coverage across error categories.


150-200: Lookup and factory flow is consistent.
The undefined-code fallback and message override are straightforward.


202-220: Helper methods align with new Type-based checks.
Clean and predictable.


222-242: Constraint enum guard is a good safety net.
Nice defensive mapping.


281-339: Constructor helpers are consistent with the new codes.
Good alignment across auth/validation/conflict/etc.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

…tails JSON

Only set Instance and TraceId pointers in AsProblemDetails when the input
values are non-empty, preserving nil to omit fields from JSON output.
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 `@pkg/errors/errors.go`:
- Around line 339-341: DatabaseAdvisoryLock currently returns the raw database
error string to clients (via New(CodeInternalDatabase, "%s", err.Error())),
which can leak sensitive info; change it to log the full err server-side and
return a generic client-safe message instead. Update DatabaseAdvisoryLock to
call the logger (or use an existing logging helper) to record err, then
construct and return a ServiceError using New(CodeInternalDatabase, "internal
database error") or similar generic text; keep New and CodeInternalDatabase
usage but avoid passing err.Error() into the client-facing message.
🧹 Nitpick comments (1)
pkg/errors/errors.go (1)

165-178: Map iteration produces non-deterministic order.

Errors() iterates over errorDefinitions map, which yields non-deterministic ordering in Go. If this is used for documentation generation or API responses where consistent ordering matters, consider sorting the result by code.

♻️ Optional: Sort for deterministic output
 func Errors() ServiceErrors {
 	errors := make(ServiceErrors, 0, len(errorDefinitions))
 	for code, def := range errorDefinitions {
 		errors = append(errors, ServiceError{
 			RFC9457Code: code,
 			Type:        def.Type,
 			Title:       def.Title,
 			Reason:      def.Reason,
 			HttpCode:    def.HttpCode,
 		})
 	}
+	sort.Slice(errors, func(i, j int) bool {
+		return errors[i].RFC9457Code < errors[j].RFC9457Code
+	})
 	return errors
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ced81c and ce045e3.

📒 Files selected for processing (1)
  • pkg/errors/errors.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Retrieve database sessions from context via db.NewContext(ctx) rather than creating new GORM connections
Use context.Context for all operations to enable proper transaction lifecycle and cleanup
Use structured logging via logger.NewOCMLogger(ctx) with contextual information like operation ID, account ID, and transaction ID
Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Files:

  • pkg/errors/errors.go
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured error type from pkg/errors with HttpCode, Code, and Reason fields
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Applied to files:

  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses

Applied to files:

  • pkg/errors/errors.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/errors/errors.go
🧬 Code graph analysis (1)
pkg/errors/errors.go (2)
pkg/logger/logger.go (2)
  • With (276-281)
  • Error (265-267)
pkg/logger/fields.go (1)
  • FieldErrorCode (52-52)
🪛 Gitleaks (8.30.0)
pkg/errors/errors.go

[high] 39-39: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 40-40: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 41-41: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 44-44: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 45-45: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (8)
pkg/errors/errors.go (8)

13-27: Well-structured RFC 9457 error type URIs.

The error type URIs follow the RFC 9457 specification correctly with a consistent base URL and clear categorization. The hierarchical structure makes it easy to identify error families.


38-45: Gitleaks false positives — these are error code constants, not API keys.

The static analysis warnings on these lines are false positives. The strings like "HYPERFLEET-AUT-001" are error code constants following the HYPERFLEET-CAT-NUM naming convention, where "AUT" denotes authentication errors. No actual secrets are exposed.


76-98: LGTM!

The struct definitions are well-documented and properly aligned with RFC 9457 semantics. The ValidationDetail struct correctly uses omitempty for optional fields, and ServiceError has clear field documentation.


108-148: Comprehensive error definitions map.

All declared error codes are properly mapped with appropriate HTTP status codes, types, titles, and reasons. The organization by category improves maintainability.


180-200: LGTM!

The New function correctly uses logger.With for structured logging (per learnings, NewOCMLogger is deprecated) and properly falls back to an internal error when an undefined code is used, preventing 500 responses from leaking undefined error codes.


210-220: LGTM!

The helper methods correctly use the RFC 9457 Type field for classification instead of the legacy numeric code, as requested in prior review feedback.


244-283: LGTM!

The AsProblemDetails method correctly:

  • Only sets Instance and TraceId when non-empty (avoiding empty string serialization)
  • Uses the isValidConstraint helper for safe enum conversion
  • Generates UTC timestamps

This addresses the prior review feedback about empty field emission and constraint type safety.


343-345: LGTM!

The InvalidToken constructor correctly uses CodeAuthExpiredToken which maps to HTTP 401 Unauthorized, aligning with RFC 7235 semantics for invalid authentication credentials.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

DatabaseAdvisoryLock now logs the full error server-side for debugging
and returns a generic "internal database error" message to clients,
preventing sensitive database information from being exposed.
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 `@pkg/errors/errors.go`:
- Around line 180-197: The New function currently always calls
fmt.Sprintf(reason, values...) which panics if reason contains '%' and values is
empty; change the logic in New so that after the exists/err setup you only call
fmt.Sprintf when len(values) > 0, otherwise assign err.Reason = reason directly;
update the block that checks reason != "" to use this conditional formatting
(referencing the New function, the err variable, the reason parameter, and the
values variadic) so unformatted reason strings won't cause fmt.Sprintf errors.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ce045e3 and b0738ee.

📒 Files selected for processing (1)
  • pkg/errors/errors.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Retrieve database sessions from context via db.NewContext(ctx) rather than creating new GORM connections
Use context.Context for all operations to enable proper transaction lifecycle and cleanup
Use structured logging via logger.NewOCMLogger(ctx) with contextual information like operation ID, account ID, and transaction ID
Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Files:

  • pkg/errors/errors.go
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured error type from pkg/errors with HttpCode, Code, and Reason fields
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to **/*.go : Use structured error type from pkg/errors with HttpCode, Code, and Reason fields

Applied to files:

  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/handlers/**/*.go : Use errors.SendError(w, r, serviceErr) to automatically convert errors to OpenAPI error responses

Applied to files:

  • pkg/errors/errors.go
📚 Learning: 2026-01-14T18:28:02.324Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T18:28:02.324Z
Learning: Applies to pkg/{services,dao}/**/*.go : Increment the generation field on each spec update to enable optimistic concurrency control

Applied to files:

  • pkg/errors/errors.go
📚 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:

  • pkg/errors/errors.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/errors/errors.go
🧬 Code graph analysis (1)
pkg/errors/errors.go (2)
pkg/logger/logger.go (3)
  • With (276-281)
  • Error (265-267)
  • WithError (284-289)
pkg/logger/fields.go (1)
  • FieldErrorCode (52-52)
🪛 Gitleaks (8.30.0)
pkg/errors/errors.go

[high] 39-39: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 40-40: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 41-41: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 44-44: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 45-45: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (4)
pkg/errors/errors.go (4)

13-72: Clean RFC 9457 taxonomy and code catalog.

The error type URIs and code groups are well-structured and easy to scan.


108-148: Error definitions map looks consistent.

Mappings align with the declared codes and HTTP status intent.


244-283: Problem Details rendering is solid.

Conditional Instance/TraceId and validated constraints keep the payload RFC 9457-friendly.


339-345: Good: database error sanitization + server-side logging.

This avoids leaking internal details while still keeping traceability in logs.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

…% without values

New function now only calls fmt.Sprintf when len(values) > 0,
otherwise assigns reason directly to avoid panic when reason
contains '%' characters but no format values are provided.
@rh-amarin
Copy link
Contributor

/lgtm

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

openshift-ci bot commented Jan 16, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: rh-amarin

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 145cf54 into openshift-hyperfleet:main Jan 16, 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.

2 participants