Skip to content

SANDBOX-316 | refactor: replace Gin framework with Echo#593

Open
MikelAlejoBR wants to merge 10 commits into
codeready-toolchain:masterfrom
MikelAlejoBR:SANDBOX-316-refactor-replace-echo-with-gin
Open

SANDBOX-316 | refactor: replace Gin framework with Echo#593
MikelAlejoBR wants to merge 10 commits into
codeready-toolchain:masterfrom
MikelAlejoBR:SANDBOX-316-refactor-replace-echo-with-gin

Conversation

@MikelAlejoBR

@MikelAlejoBR MikelAlejoBR commented May 4, 2026

Copy link
Copy Markdown
Contributor

The registration service used both the Echo and Gin frameworks to provide its services, and we wanted to remove the dependency with Echo and just keep Gin to improve maintainability.

Assited-by: claude-4.6 with Cursor

Jira ticket

[SANDBOX-316]

Summary by CodeRabbit

  • Refactor
    • Web framework migrated to a new HTTP framework across the service; logging, authentication, metrics, middleware and tests updated to match. Public endpoints and behavior preserved.
  • Bug Fix / UX
    • Static content now serves index.html directly (no redirect), improving root/static asset handling.

@openshift-ci openshift-ci Bot requested review from fbm3307 and jrosental May 4, 2026 20:19
@openshift-ci

openshift-ci Bot commented May 4, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: MikelAlejoBR
Once this PR has been reviewed and has the lgtm label, please assign rsoaresd for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found 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

@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Replaced Gin with Echo across the codebase: added Echo-aware context helpers, converted handlers/middleware/services/logging/errors to use echo.Context, rewired server/router/static/metrics to Echo, updated assets FS usage, and migrated tests and fakes to use Echo contexts.

Changes

Gin → Echo Framework Migration (single cohesive DAG)

Layer / File(s) Summary
Context helpers / data shape
pkg/context/keys.go
Added RequestContext(ctx echo.Context) gocontext.Context and GetString(ctx echo.Context, key string) string to extract request context and string values from Echo contexts.
Core API surface
pkg/application/service/services.go, pkg/verification/service/verification_service.go, pkg/signup/service/signup_service.go, pkg/verification/captcha/captcha.go, pkg/verification/sender/sender.go, pkg/verification/sender/*.go
Changed exported interfaces and method signatures from *gin.Context to echo.Context across services, captcha, and notification senders; added/updated helpers (e.g., PhoneNumberAlreadyInUse(ctx echo.Context, ...), signup service helpers).
Controllers & handlers
pkg/controller/*.go, pkg/proxy/handlers/*.go, pkg/namespaces/*.go, pkg/signup/*.go
Converted HTTP handlers to accept echo.Context and return error; adjusted binding/validation tags, response emission (ctx.JSON, ctx.NoContent, ctx.String), and internal client calls to use ctx.Request().Context() and new context helpers.
Middleware & logging
pkg/middleware/*.go, pkg/log/log.go
Reworked middleware to Echo types (echo.MiddlewareFunc/echo.HandlerFunc), updated JWT extraction/response and Prometheus instrumentation to Echo semantics, and migrated log helpers to accept echo.Context and extract fields accordingly.
Server & routing
pkg/server/*.go, pkg/server/routes.go, pkg/server/metrics_server.go, pkg/server/routes_test.go
Replaced *gin.Engine with *echo.Echo; rewired middleware registration, static serving via StaticFS/MustSubFS, metrics endpoint using echo.WrapHandler, and adjusted server start wiring and route registration.
Assets / fs
pkg/assets/assets.go
ServeEmbedContent() now returns fs.FS via fs.Sub(StaticContent, "static"); removed custom StaticContentFileSystem wrapper and related imports.
Errors
pkg/errors/error.go
AbortWithError now accepts echo.Context and returns error; added StatusCode(err error) int resolving status from *Error or *echo.HTTPError.
Namespace & proxy wiring
pkg/namespaces/*, pkg/proxy/*
Updated ResetNamespaces and proxy error handling to use Echo context and centralized status-code resolution via crterrors.StatusCode.
Tests & test helpers
**/*_test.go (many files)
Replaced Gin test contexts with Echo fixtures (echo.New().NewContext(...)), added helpers like newEchoTestContext / echoCtx*, and adjusted numerous tests across controllers, services, middleware, and senders.
Misc / test fakes & go.mod
test/fake/proxy.go, go.mod
Updated test fakes to Echo contexts; removed direct Gin/gin-contrib requires from go.mod and adjusted indirect dependency listings.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client (browser/API)
  participant Echo as Echo Router
  participant Middleware as Middleware (JWT/Metrics/Logging)
  participant Controller as Controller/Handler
  participant Service as Application Service
  participant K8s as Namespaced Client (Kubernetes)

  rect rgba(135,206,250,0.5)
  Client->>Echo: HTTP request
  end
  rect rgba(144,238,144,0.5)
  Echo->>Middleware: pass request through middleware chain
  Middleware->>Echo: set context values / metrics
  end
  rect rgba(255,228,181,0.5)
  Echo->>Controller: invoke handler with echo.Context
  Controller->>Service: call service methods (pass echo.Context)
  Service->>K8s: use RequestContext(ctx) to call Kubernetes APIs
  K8s-->>Service: return resources
  Service-->>Controller: return result
  Controller-->>Echo: write response (JSON/NoContent)
  Echo-->>Client: HTTP response
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

refactoring

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

@coderabbitai coderabbitai Bot added dependencies Pull requests that update a dependency file refactoring Refactor code labels May 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

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

⚠️ Outside diff range comments (1)
pkg/proxy/metrics_server.go (1)

16-17: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Stale doc comment still references Echo.

Line 17 still reads "Uses echo web framework" after the migration to Gin.

📝 Proposed fix
 // StartMetricsServer start server with a single `/metrics` endpoint to server the Prometheus metrics
-// Uses echo web framework
+// Uses gin web framework
 func StartMetricsServer(reg *prometheus.Registry, port int) *http.Server {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/proxy/metrics_server.go` around lines 16 - 17, Update the stale
package-level doc comment above StartMetricsServer: replace "Uses echo web
framework" with an accurate description referencing Gin (e.g., "Uses Gin web
framework") so the comment for StartMetricsServer correctly reflects the
migration from Echo to Gin; locate the comment immediately above the
StartMetricsServer function and adjust wording/capitalization accordingly.
🧹 Nitpick comments (1)
pkg/log/log_test.go (1)

61-125: 💤 Low value

LGTM — Gin context setup and InfoGinF assertions look correct.

One optional readability improvement carried over from the original test: the name field in the table-test struct (line 63) is never populated, so t.Run(tc.name, ...) (line 92) generates unnamed subtests (#00, #01, …). Switching to for name, tc := range tt { t.Run(name, ...) } would give each subtest the descriptive map key, making failures easier to identify.

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

In `@pkg/log/log_test.go` around lines 61 - 125, The table-driven test uses
unnamed subtests because the struct includes a redundant "name" field and the
loop does "for _, tc := range tt { t.Run(tc.name, ...)" — change the iteration
to "for name, tc := range tt { t.Run(name, func(t *testing.T) { ... }) }" so
each subtest uses the map key as its name (and remove or ignore the unused
"name" field in the test-case struct); keep all references to the test case as
tc and ensure the inner closure captures tc correctly (no other changes to
InfoGinF, ctx setup, or assertions are necessary).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/log/log.go`:
- Around line 124-126: The package-level wrapper WithValues calls ensureLogger()
but the underlying method (*Logger).WithValues still dereferences the
package-global logger fields (e.g., logger.name) and can nil-panic if Init()
hasn't run; update (*Logger).WithValues to defensively handle an uninitialized
logger by checking for nil or missing internal fields and falling back to the
default/fallback logger behavior (the same behavior ensureLogger() provides),
and apply the same defensive check/fallback to the other similar methods
referenced around lines 205-208 so callers using the package wrappers before
Init() won't dereference nil internals.
- Around line 151-155: The code currently appends ctx.Request.URL (which
contains raw query strings) to ctxFields and can leak sensitive query params;
update the logging to append a sanitized URL instead—use ctx.Request.URL.Path
(or construct ctx.Request.URL.Scheme/Host/Path without RawQuery) or explicitly
strip/redact sensitive query keys like "code", "token", "access_token" before
appending; change the two lines that append ctx.Request.URL to append the
sanitized string and ensure any helper used (e.g., InfoGinF) receives the
sanitized value.

In `@pkg/proxy/proxy.go`:
- Around line 230-233: Logs currently print full origin/target URLs (e.g., in
Proxy.redirectTo which calls log.InfoGinF and other nearby log.InfoGinF calls),
potentially exposing sensitive query parameters; fix this by sanitizing URLs
before logging—parse the URL (or parse ctx.Request.URL/ the "to" string), strip
or clear RawQuery (and Fragment) to produce a redacted URL, use that sanitized
string in the log.InfoGinF calls, but keep the original (unmodified) URL value
when calling http.Redirect or proxying so behavior is unchanged; apply the same
redaction logic to all other log.InfoGinF usages in this file that log request
or target URLs.
- Around line 586-590: The error log in the p.List ban-list lookup should not
include the raw email (PII); update the log.Errorf call inside the block that
calls p.List(ctx.Request.Context(), bannedUsers,
client.InNamespace(p.Namespace),
client.MatchingLabels{toolchainv1alpha1.BannedUserEmailHashLabelKey:
hashedEmail}) to remove the plain email and instead include non-PII context such
as the hashedEmail and the error (e.g., "error retrieving banned users for hash
%s"), and keep the existing ctx.AbortWithStatusJSON(...) behavior so the HTTP
response remains the same.
- Around line 183-185: The unsecured-path check in unsecured currently uses
ctx.Request.URL.RequestURI(), which includes query strings and trailing slashes;
change it to use the normalized ctx.Request.URL.Path (which removeTrailingSlash
already normalizes) so comparisons against proxyHealthEndpoint,
wellKnownOauthConfigEndpoint, and strings.HasPrefix(uri, authEndpoint) work
correctly for variants like /proxyhealth?x=1 or /proxyhealth/; update the
variable name (e.g., uri := ctx.Request.URL.Path) and keep the rest of the logic
in unsecured unchanged.
- Around line 149-153: The routes defined on ginRouter use unnamed catch-all
wildcards which will panic; update the patterns to use named catch-all
parameters (e.g. "/*path") so Gin accepts them: change the
wellKnownOauthConfigEndpoint/openidAuthEndpoint()/authEndpoint patterns to
append a named catch-all (e.g. fmt.Sprintf("%s/*path", openidAuthEndpoint()) and
fmt.Sprintf("%s/*path", authEndpoint)) and change the main proxy route to
"/*path" so p.openidAuth, p.auth and p.handleRequestAndRedirect are registered
with valid Gin routes; keep wellKnownOauthConfigEndpoint as-is if it’s an exact
path, otherwise use a named parameter there too.

---

Outside diff comments:
In `@pkg/proxy/metrics_server.go`:
- Around line 16-17: Update the stale package-level doc comment above
StartMetricsServer: replace "Uses echo web framework" with an accurate
description referencing Gin (e.g., "Uses Gin web framework") so the comment for
StartMetricsServer correctly reflects the migration from Echo to Gin; locate the
comment immediately above the StartMetricsServer function and adjust
wording/capitalization accordingly.

---

Nitpick comments:
In `@pkg/log/log_test.go`:
- Around line 61-125: The table-driven test uses unnamed subtests because the
struct includes a redundant "name" field and the loop does "for _, tc := range
tt { t.Run(tc.name, ...)" — change the iteration to "for name, tc := range tt {
t.Run(name, func(t *testing.T) { ... }) }" so each subtest uses the map key as
its name (and remove or ignore the unused "name" field in the test-case struct);
keep all references to the test case as tc and ensure the inner closure captures
tc correctly (no other changes to InfoGinF, ctx setup, or assertions are
necessary).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 798a2457-dc6a-4c78-b7e7-468338e33d0a

📥 Commits

Reviewing files that changed from the base of the PR and between 3cd3153 and 1f9903a.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (14)
  • go.mod
  • pkg/configuration/configuration.go
  • pkg/context/keys.go
  • pkg/context/public_viewer.go
  • pkg/context/public_viewer_test.go
  • pkg/log/log.go
  • pkg/log/log_test.go
  • pkg/proxy/handlers/spacelister.go
  • pkg/proxy/handlers/spacelister_get.go
  • pkg/proxy/handlers/spacelister_get_test.go
  • pkg/proxy/handlers/spacelister_list.go
  • pkg/proxy/handlers/spacelister_list_test.go
  • pkg/proxy/metrics_server.go
  • pkg/proxy/proxy.go
💤 Files with no reviewable changes (1)
  • go.mod
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test
  • GitHub Check: GolangCI Lint
  • GitHub Check: Build & push operator bundles & dashboard image for e2e tests
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • pkg/context/public_viewer_test.go
  • pkg/context/public_viewer.go
  • pkg/context/keys.go
  • pkg/configuration/configuration.go
  • pkg/proxy/handlers/spacelister_list_test.go
  • pkg/log/log_test.go
  • pkg/proxy/handlers/spacelister.go
  • pkg/proxy/metrics_server.go
  • pkg/log/log.go
  • pkg/proxy/handlers/spacelister_list.go
  • pkg/proxy/handlers/spacelister_get.go
  • pkg/proxy/proxy.go
  • pkg/proxy/handlers/spacelister_get_test.go
🪛 GitHub Check: SonarCloud Code Analysis
pkg/proxy/handlers/spacelister_get.go

[failure] 98-98: Define a constant instead of duplicating this literal "unauthorized access" 3 times.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ30phdgq6rrprTGTex7&open=AZ30phdgq6rrprTGTex7&pullRequest=593

🔇 Additional comments (6)
pkg/context/keys.go (1)

26-27: LGTM — comment correctly updated to reference gin.Context.

pkg/context/public_viewer.go (1)

9-12: LGTMctx.GetBool correctly handles all edge cases (nil key, nil value, non-bool type) via Gin's internal nil-guard and silent type assertion.

pkg/context/public_viewer_test.go (1)

38-53: LGTM&gin.Context{} is sufficient here since only Set/GetBool are exercised; all nil-map and type-assertion edge cases are handled correctly by Gin internals.

pkg/configuration/configuration.go (1)

277-302: LGTM — log calls correctly migrated to logf.Log.Error(err, msg), consistent with the rest of the file.

pkg/proxy/handlers/spacelister_list_test.go (1)

82-102: LGTM — Gin test context setup and handler invocation follow the standard pattern; response assertions via rec.Code/rec.Body are correct.

pkg/proxy/handlers/spacelister_get_test.go (1)

563-607: LGTM — Gin test context setup, path param injection via ctx.Params, and handler invocation pattern are correct and consistent across all test functions in this file.

Comment thread pkg/log/log.go Outdated
Comment thread pkg/log/log.go Outdated
Comment thread pkg/proxy/proxy.go Outdated
Comment thread pkg/proxy/proxy.go Outdated
Comment thread pkg/proxy/proxy.go Outdated
Comment thread pkg/proxy/proxy.go Outdated

@alexeykazakov alexeykazakov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Well.. We actually use Echo in other projects (TARSy, GC, etc). So maybe we should pick Echo and not Gin for reg-service :)

@MikelAlejoBR MikelAlejoBR changed the title SANDBOX-316 | refactor: replace Echo framework with Gin SANDBOX-316 | refactor: replace Gin framework with Echo May 5, 2026
@MikelAlejoBR MikelAlejoBR force-pushed the SANDBOX-316-refactor-replace-echo-with-gin branch from 1f9903a to 984c66c Compare May 5, 2026 13:20
@MikelAlejoBR MikelAlejoBR marked this pull request as draft May 5, 2026 13:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Caution

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

⚠️ Outside diff range comments (2)
pkg/verification/sender/amazon_sns_sender.go (1)

30-65: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Propagate request cancellation to the SNS publish call.

This method receives an Echo context but discards it with _, so the outbound SNS call won't be canceled when the HTTP request is canceled or times out. Use the request context with the context-aware AWS SDK method.

Suggested fix
-func (s *AmazonSNSSender) SendNotification(_ echo.Context, content, phoneNumber, _ string) error {
+func (s *AmazonSNSSender) SendNotification(ctx echo.Context, content, phoneNumber, _ string) error {
@@
-	_, err = svc.Publish(&sns.PublishInput{
+	_, err = svc.PublishWithContext(ctx.Request().Context(), &sns.PublishInput{
 		Message:     &content,
 		PhoneNumber: &phoneNumber,
 		MessageAttributes: map[string]*sns.MessageAttributeValue{
 			"AWS.SNS.SMS.SenderID": senderID,
 			"AWS.SNS.SMS.SMSType":  smsType,
 		},
 	})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/verification/sender/amazon_sns_sender.go` around lines 30 - 65,
SendNotification currently discards the Echo context and calls svc.Publish
without propagation, so SNS requests won't be canceled on HTTP timeouts; change
the signature use of the context parameter to accept and use the incoming
echo.Context (instead of `_`), extract the request context via
ctx.Request().Context(), and call the context-aware AWS SNS method (e.g.,
PublishWithContext) on svc when invoking Publish (replace the svc.Publish call
with the context-aware variant and pass the extracted context), ensuring
MessageAttributes and other inputs remain unchanged.
pkg/proxy/handlers/spacelister.go (1)

30-46: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pass the active Echo context to GetSignupFunc instead of nil.

Line 45 passes nil to s.GetSignupFunc() which now expects an echo.Context. The GetSignup method at line 318 of pkg/signup/service/signup_service.go forwards this context downstream, and multiple code paths (lines 211, 217) call ctx.Request() which will panic when ctx is nil. Since the function already has access to the active context, pass it through.

Proposed fix
 func (s *SpaceLister) GetProvisionedUserSignup(ctx echo.Context) (*signup.Signup, error) {
 	username, _ := ctx.Get(context.UsernameKey).(string)

-	userSignup, err := s.GetSignupFunc(nil, username, false)
+	userSignup, err := s.GetSignupFunc(ctx, username, false)
 	if err != nil {
 		ctx.Logger().Error(errs.Wrap(err, "error retrieving signup"))
 		return nil, err
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/proxy/handlers/spacelister.go` around lines 30 - 46, The call in
GetProvisionedUserSignup uses s.GetSignupFunc with a nil context which causes
downstream panics; update the invocation in GetProvisionedUserSignup to pass the
active Echo context (ctx) instead of nil so that GetSignupFunc (and the
underlying SignupService.GetSignup) receive a valid echo.Context; locate the
call site in the GetProvisionedUserSignup method where s.GetSignupFunc(nil,
username, false) is used and replace the nil first argument with ctx.
♻️ Duplicate comments (1)
pkg/log/log.go (1)

136-149: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Sanitize the request URL before logging it.

ctx.Request().URL still carries the raw query string, so this path can log OAuth codes, tokens, or other sensitive params. Strip RawQuery or log only the path before appending the URL field.

Suggested fix
  ctxFields = append(ctxFields, "url")
-	ctxFields = append(ctxFields, ctx.Request().URL)
+	if req := ctx.Request(); req != nil && req.URL != nil {
+		safeURL := *req.URL
+		safeURL.RawQuery = ""
+		ctxFields = append(ctxFields, safeURL.String())
+	} else {
+		ctxFields = append(ctxFields, "")
+	}

As per coding guidelines, "Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity."

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

In `@pkg/log/log.go` around lines 136 - 149, In Logger.InfoEchof, sanitize the
request URL before logging: replace appending ctx.Request().URL (which may
include sensitive RawQuery) with a safe value such as ctx.Request().URL.Path or
a cloned url where RawQuery and Fragment are cleared, then append that sanitized
string to ctxFields under the "url" key; update the code around the "url" append
(in InfoEchof) to use the sanitized variable instead of ctx.Request().URL.
🧹 Nitpick comments (2)
pkg/errors/error.go (1)

17-25: ⚡ Quick win

AbortWithError bypasses Echo's centralized error handler.

Echo advocates for centralized HTTP error handling by returning errors from middleware and handlers, which allows logging errors from a unified location. The current implementation writes the JSON response directly via ctx.JSON() and returns nil. When a handler has already sent a response via c.JSON() and there is an error in the middleware chain returning from the handler, the error that the global error handler receives will be ignored because the response is already committed.

As a result, any error-observing middleware or a custom e.HTTPErrorHandler configured later will never see these HTTP error responses.

Consider the idiomatic Echo approach: return an *echo.HTTPError and let the error handler write the response, or at minimum keep this pattern documented as intentional.

♻️ Idiomatic alternative
-func AbortWithError(ctx echo.Context, code int, err error, details string) error {
-	return ctx.JSON(code, &Error{
-		Status:  http.StatusText(code),
-		Code:    code,
-		Message: err.Error(),
-		Details: details,
-	})
-}
+// AbortWithError returns an echo.HTTPError that Echo's error handler will process.
+// Callers must register a custom HTTPErrorHandler that formats the Error struct.
+func AbortWithError(_ echo.Context, code int, err error, details string) error {
+	return &echo.HTTPError{
+		Code:    code,
+		Message: &Error{
+			Status:  http.StatusText(code),
+			Code:    code,
+			Message: err.Error(),
+			Details: details,
+		},
+	}
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/errors/error.go` around lines 17 - 25, AbortWithError currently writes
the JSON response directly via ctx.JSON and therefore bypasses Echo's
centralized error handler; change it to construct and return an *echo.HTTPError
(e.g. return echo.NewHTTPError(code, &Error{Status: http.StatusText(code), Code:
code, Message: err.Error(), Details: details})) instead of calling ctx.JSON so
the global e.HTTPErrorHandler can handle logging and response serialization;
update any callers to simply return the error from AbortWithError without
writing to the context.
pkg/verification/captcha/captcha.go (1)

18-20: 🏗️ Heavy lift

Keep the captcha API framework-agnostic.

pkg/verification/captcha now depends on echo.Context, even though this code only needs request-scoped cancellation for the reCAPTCHA call. That leaks the HTTP framework into a lower-level package and makes the next transport migration much larger than it needs to be. Prefer context.Context here and convert once at the HTTP boundary with ctx.Request().Context(). As per coding guidelines, "Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity."

Also applies to: 34-35

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

In `@pkg/verification/captcha/captcha.go` around lines 18 - 20, The Assessor
interface and its CompleteAssessment method currently use echo.Context; change
the signature to use standard context.Context instead (i.e.,
CompleteAssessment(ctx context.Context, cfg
configuration.RegistrationServiceConfig, token string) (*recaptchapb.Assessment,
error)) and update all implementations in pkg/verification/captcha (the methods
that implement Assessor, referenced around the other occurrences you saw) to
accept context.Context; then convert echo.Context to context.Context at the
HTTP/transport boundary by passing ctx.Request().Context() from handlers so the
lower-level captcha package stays framework-agnostic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/controller/signup.go`:
- Around line 157-160: The handler in pkg/controller/signup.go currently only
rejects non-string codes but allows empty strings; update the check after code,
ok := body["code"].(string) to also treat empty string as invalid (e.g., if !ok
|| strings.TrimSpace(code) == "") so it returns 400 and logs the missing
activation code, preventing downstream fallback in
pkg/verification/service/verification_service.go (which calls Signup(ctx)) and
the bypass of social-event validation in pkg/signup/service/signup_service.go;
ensure the log message remains descriptive and use the same ctx/log.Error call
site.

In `@pkg/middleware/jwt_middleware.go`:
- Around line 63-73: The code currently extracts the JWT payload (parts[1] into
rawClaims) and includes it in the log message, which leaks sensitive claim data;
remove the parts/splitting and the rawClaims variable and stop logging the raw
payload. Edit the block around the log.Infof call (references: tokenStr, parts,
rawClaims, token.UserID, token.AccountID, token.PreferredUsername,
token.Subject) so the log only indicates that essential claims are missing and
does not include the raw claims segment (or any full claim values); if you need
contextual info, log non-sensitive identifiers or a masked token identifier
instead, but do not parse or output parts[1].

In `@pkg/middleware/promhttp_middleware.go`:
- Around line 27-31: The metric label currently uses the raw request path
(c.Request().URL.Path) which causes high cardinality; update the labels passed
to counter.With(...) to replace c.Request().URL.Path with the Echo route
template c.Path() so the "path" label uses the route pattern instead of dynamic
values while keeping the other labels (code via
strconv.Itoa(c.Response().Status) and method via c.Request().Method) unchanged.
- Around line 26-33: When recording metrics in the middleware around next(c)
(the block that uses counter.With and reads c.Response().Status), determine the
status code from the returned error first: if err != nil and err is an
*echo.HTTPError use he.Code, otherwise if c.Response().Status != 0 use that
value, and if still zero fall back to http.StatusInternalServerError; then pass
that status into counter.With(prometheus.Labels{ "code": strconv.Itoa(status),
... }). Apply the same fix to the analogous block that records the histogram
(the second block around lines 40-49) so both counter.With and histogram.With
use the resolved status code and not raw c.Response().Status when handlers
return errors.

In `@pkg/server/server_test.go`:
- Around line 66-69: The current goroutine asserts that
srv.HTTPServer().ListenAndServe() returns no error, but ListenAndServe returns
http.ErrServerClosed on graceful shutdown; update the goroutine that calls
srv.HTTPServer().ListenAndServe() to treat http.ErrServerClosed as a non-fatal
case by checking if err != nil && err != http.ErrServerClosed before calling
assert.NoError (or assert.Fail) so only real errors fail the test, and add the
net/http import if missing; reference the anonymous goroutine wrapping
srv.HTTPServer().ListenAndServe() in server_test.go and the s.T() test context.

In `@pkg/server/server.go`:
- Around line 35-64: The JSON log currently builds a string with fmt.Printf
inside the LogValuesFunc of RequestLoggerWithConfig and interpolates
request-derived fields (v.URI, v.UserAgent, errMsg) directly; replace that
manual string construction by creating a struct or map with typed fields and
serializing it via encoding/json (json.Marshal or json.Encoder) so those fields
are properly escaped, then write the marshaled JSON (or handle the marshal
error) instead of using fmt.Printf; update the LogValuesFunc implementation
referenced in RequestLoggerConfig/RequestLoggerWithConfig to use json
serialization for the log object.

In `@pkg/signup/service/signup_service.go`:
- Around line 60-65: DoGetSignup/PollUpdateSignup are using context.TODO() which
ignores request cancellation; replace those uses with the incoming Echo request
context by calling requestContext(ctx) (or ctx.Request().Context()) where cl.Get
and s.Update are invoked in PollUpdateSignup and DoGetSignup so all API calls
respect request cancellation; update both the initial cl.Get and the conditional
s.Update (and the similar occurrences around the 318-346 region) to use
requestContext(ctx) instead of context.TODO().

In `@pkg/verification/service/verification_service.go`:
- Around line 66-68: InitVerification currently calls ServiceImpl.Get with
gocontext.TODO(), which fails to propagate the HTTP request context; replace
gocontext.TODO() with the request-scoped context obtained from the incoming
echo.Context (either ctx.Request().Context() or the existing helper added in the
signup service that converts echo.Context to context.Context) so the Kubernetes
client calls (ServiceImpl.Get/Update/etc. using
signupcommon.EncodeUserIdentifier/NamespacedName) are cancelled when the request
is cancelled; apply the same change to the other read/update blocks referenced
(the similar calls around the other two locations).

---

Outside diff comments:
In `@pkg/proxy/handlers/spacelister.go`:
- Around line 30-46: The call in GetProvisionedUserSignup uses s.GetSignupFunc
with a nil context which causes downstream panics; update the invocation in
GetProvisionedUserSignup to pass the active Echo context (ctx) instead of nil so
that GetSignupFunc (and the underlying SignupService.GetSignup) receive a valid
echo.Context; locate the call site in the GetProvisionedUserSignup method where
s.GetSignupFunc(nil, username, false) is used and replace the nil first argument
with ctx.

In `@pkg/verification/sender/amazon_sns_sender.go`:
- Around line 30-65: SendNotification currently discards the Echo context and
calls svc.Publish without propagation, so SNS requests won't be canceled on HTTP
timeouts; change the signature use of the context parameter to accept and use
the incoming echo.Context (instead of `_`), extract the request context via
ctx.Request().Context(), and call the context-aware AWS SNS method (e.g.,
PublishWithContext) on svc when invoking Publish (replace the svc.Publish call
with the context-aware variant and pass the extracted context), ensuring
MessageAttributes and other inputs remain unchanged.

---

Duplicate comments:
In `@pkg/log/log.go`:
- Around line 136-149: In Logger.InfoEchof, sanitize the request URL before
logging: replace appending ctx.Request().URL (which may include sensitive
RawQuery) with a safe value such as ctx.Request().URL.Path or a cloned url where
RawQuery and Fragment are cleared, then append that sanitized string to
ctxFields under the "url" key; update the code around the "url" append (in
InfoEchof) to use the sanitized variable instead of ctx.Request().URL.

---

Nitpick comments:
In `@pkg/errors/error.go`:
- Around line 17-25: AbortWithError currently writes the JSON response directly
via ctx.JSON and therefore bypasses Echo's centralized error handler; change it
to construct and return an *echo.HTTPError (e.g. return echo.NewHTTPError(code,
&Error{Status: http.StatusText(code), Code: code, Message: err.Error(), Details:
details})) instead of calling ctx.JSON so the global e.HTTPErrorHandler can
handle logging and response serialization; update any callers to simply return
the error from AbortWithError without writing to the context.

In `@pkg/verification/captcha/captcha.go`:
- Around line 18-20: The Assessor interface and its CompleteAssessment method
currently use echo.Context; change the signature to use standard context.Context
instead (i.e., CompleteAssessment(ctx context.Context, cfg
configuration.RegistrationServiceConfig, token string) (*recaptchapb.Assessment,
error)) and update all implementations in pkg/verification/captcha (the methods
that implement Assessor, referenced around the other occurrences you saw) to
accept context.Context; then convert echo.Context to context.Context at the
HTTP/transport boundary by passing ctx.Request().Context() from handlers so the
lower-level captcha package stays framework-agnostic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 4172280a-b27f-42d1-bd09-64fab6312e90

📥 Commits

Reviewing files that changed from the base of the PR and between 1f9903a and 984c66c.

📒 Files selected for processing (47)
  • pkg/application/service/services.go
  • pkg/assets/assets.go
  • pkg/context/keys.go
  • pkg/controller/analytics.go
  • pkg/controller/analytics_test.go
  • pkg/controller/authconfig.go
  • pkg/controller/authconfig_test.go
  • pkg/controller/health_check.go
  • pkg/controller/health_check_test.go
  • pkg/controller/namespaces.go
  • pkg/controller/namespaces_test.go
  • pkg/controller/signup.go
  • pkg/controller/signup_test.go
  • pkg/controller/uiconfig.go
  • pkg/controller/uiconfig_test.go
  • pkg/controller/usernames.go
  • pkg/controller/usernames_test.go
  • pkg/errors/error.go
  • pkg/errors/error_test.go
  • pkg/log/log.go
  • pkg/log/log_test.go
  • pkg/middleware/jwt_middleware.go
  • pkg/middleware/promhttp_middleware.go
  • pkg/namespaces/namespaces_manager.go
  • pkg/namespaces/namespaces_manager_test.go
  • pkg/proxy/handlers/spacelister.go
  • pkg/proxy/handlers/spacelister_get_test.go
  • pkg/proxy/handlers/spacelister_list_test.go
  • pkg/proxy/proxy_test.go
  • pkg/server/metrics_server.go
  • pkg/server/routes.go
  • pkg/server/routes_test.go
  • pkg/server/server.go
  • pkg/server/server_test.go
  • pkg/signup/service/signup_service.go
  • pkg/signup/service/signup_service_test.go
  • pkg/signup/signup.go
  • pkg/signup/socialevent.go
  • pkg/signup/socialevent_test.go
  • pkg/verification/captcha/captcha.go
  • pkg/verification/sender/amazon_sns_sender.go
  • pkg/verification/sender/sender.go
  • pkg/verification/sender/twilio_sender.go
  • pkg/verification/sender/twilio_sender_test.go
  • pkg/verification/service/verification_service.go
  • pkg/verification/service/verification_service_test.go
  • test/fake/proxy.go
✅ Files skipped from review due to trivial changes (1)
  • pkg/proxy/handlers/spacelister_get_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: GolangCI Lint
  • GitHub Check: test
  • GitHub Check: Build & push operator bundles & dashboard image for e2e tests
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • pkg/errors/error_test.go
  • pkg/errors/error.go
  • pkg/namespaces/namespaces_manager.go
  • pkg/signup/signup.go
  • pkg/controller/authconfig.go
  • pkg/controller/namespaces.go
  • pkg/middleware/promhttp_middleware.go
  • pkg/controller/analytics.go
  • pkg/controller/usernames.go
  • pkg/verification/sender/sender.go
  • pkg/verification/sender/twilio_sender.go
  • pkg/application/service/services.go
  • pkg/controller/namespaces_test.go
  • pkg/verification/sender/amazon_sns_sender.go
  • pkg/controller/uiconfig_test.go
  • pkg/context/keys.go
  • pkg/verification/service/verification_service.go
  • pkg/assets/assets.go
  • pkg/server/routes.go
  • pkg/server/server_test.go
  • pkg/controller/uiconfig.go
  • test/fake/proxy.go
  • pkg/namespaces/namespaces_manager_test.go
  • pkg/verification/sender/twilio_sender_test.go
  • pkg/server/metrics_server.go
  • pkg/verification/captcha/captcha.go
  • pkg/middleware/jwt_middleware.go
  • pkg/controller/analytics_test.go
  • pkg/controller/health_check_test.go
  • pkg/server/routes_test.go
  • pkg/signup/socialevent_test.go
  • pkg/controller/authconfig_test.go
  • pkg/log/log.go
  • pkg/controller/usernames_test.go
  • pkg/log/log_test.go
  • pkg/verification/service/verification_service_test.go
  • pkg/controller/health_check.go
  • pkg/proxy/proxy_test.go
  • pkg/controller/signup.go
  • pkg/signup/service/signup_service_test.go
  • pkg/proxy/handlers/spacelister_list_test.go
  • pkg/proxy/handlers/spacelister.go
  • pkg/controller/signup_test.go
  • pkg/server/server.go
  • pkg/signup/socialevent.go
  • pkg/signup/service/signup_service.go
🪛 GitHub Check: SonarCloud Code Analysis
pkg/controller/signup_test.go

[warning] 567-567: This function has 8 parameters, which is greater than the 7 authorized.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ34TFGGAacx7-Vpg6Q0&open=AZ34TFGGAacx7-Vpg6Q0&pullRequest=593

pkg/signup/service/signup_service.go

[failure] 322-322: Refactor this method to reduce its Cognitive Complexity from 33 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ34TFMcAacx7-Vpg6Q1&open=AZ34TFMcAacx7-Vpg6Q1&pullRequest=593

🔇 Additional comments (23)
pkg/controller/uiconfig.go (2)

25-28: Good constructor addition for controller consistency.

NewUIConfig() keeps initialization explicit and matches the controller wiring pattern used in routes.


31-38: Echo handler migration is implemented correctly.

Using func(ctx echo.Context) error and return ctx.JSON(...) is the right contract for Echo handlers and preserves proper error propagation.

pkg/controller/uiconfig_test.go (2)

49-52: Test invocation update is correct for Echo handlers.

Creating echo.Context and asserting require.NoError on GetHandler matches the new controller contract and makes failures explicit.


91-94: Second test migration is consistent and correct.

This mirrors the Echo-based handler call pattern and preserves robust error checking.

pkg/server/metrics_server.go (1)

19-44: LGTM — migration is correct.

Key points verified:

  • *echo.Echo satisfies http.Handler via ServeHTTP, so assigning Handler: router directly (line 32) is valid and replaces the old router.Handler() call correctly.
  • echo.WrapHandler is the right adapter for bridging promhttp's http.Handler into Echo's handler chain.
  • HideBanner / HidePort suppress Echo's default startup noise, appropriate for a production metrics server.
  • Both callers (metrics_server_test.go and promhttp_middleware_test.go) handle the new (*http.Server, *echo.Echo) return type correctly.
pkg/signup/socialevent_test.go (1)

24-27: LGTM — Echo context setup is correct.

Creating the Echo context once with a real httptest.NewRequest ensures ctx.Request().Context() returns a valid context.Background()-backed context. Sharing ctx across subtests is safe since none of them mutate the Echo context state.

pkg/signup/socialevent.go (1)

32-32: No issue: log.Infof in pkg/log accepts echo.Context, supporting the migration from Gin to Echo.

pkg/middleware/promhttp_middleware.go (1)

7-7: 🏗️ Heavy lift

The review comment's premise about the PR objective is inverted.

The PR's stated goal is to "remove the dependency with Gin and just keep Echo." The file pkg/middleware/promhttp_middleware.go correctly implements Echo middleware, which aligns with this objective. Gin has been completely removed from the codebase—no Gin imports remain. The code in this file is correct and consistent with the actual PR goal.

			> Likely an incorrect or invalid review comment.
pkg/controller/authconfig.go (1)

31-39: LGTM – clean Echo handler migration.

The handler correctly returns ctx.JSON(...) as the error value, following the Echo handler contract.

pkg/controller/authconfig_test.go (1)

44-57: LGTM – Echo test harness correctly wired.

The Contains assertion on Content-Type (Line 57) is the right adaptation since Echo appends the charset suffix.

pkg/verification/sender/sender.go (1)

11-13: LGTM – interface and all implementations consistently updated.

pkg/signup/signup.go (1)

75-100: LGTM – PollUpdateSignup correctly updated to echo.Context.

pkg/errors/error_test.go (1)

27-49: LGTM – Echo test harness correctly replaces Gin's CreateTestContext.

pkg/controller/analytics.go (1)

21-32: LGTM – both analytics handlers cleanly migrated.

pkg/assets/assets.go (1)

11-13: ⚡ Quick win

The error return from ServeEmbedContent() is already properly handled by callers. In routes.go (line 117-120), the error is checked with if err != nil and wrapped before returning. In routes_test.go, it's checked with require.NoError(t, err). No action needed.

			> Likely an incorrect or invalid review comment.
pkg/log/log_test.go (1)

27-44: LGTM — Echo context setup is correct throughout.

Each subtest correctly constructs echo.New().NewContext(req, rr) and the buf.Reset() pattern is maintained consistently (omitted only for the first subtest, which is correct since buf is freshly initialised).

pkg/controller/health_check.go (1)

52-58: LGTM — handler and interface correctly migrated to Echo.

pkg/controller/health_check_test.go (1)

219-225: LGTM — mock correctly implements the updated HealthChecker interface.

pkg/proxy/proxy_test.go (1)

518-518: LGTM — OverrideGetSignupFunc signature correctly updated to echo.Context.

Also applies to: 683-685

pkg/verification/service/verification_service_test.go (1)

43-46: LGTM — newEchoTestContext() is a clean, reusable helper that correctly replaces the removed gin.CreateTestContext calls.

pkg/context/keys.go (1)

7-15: LGTM — GetString is correctly nil-safe and handles missing/wrong-type values via the two-value type assertion.

pkg/namespaces/namespaces_manager_test.go (1)

100-113: LGTM — Echo context setup is correct; the single shared context is safe since no sub-test mutates it.

pkg/signup/service/signup_service.go (1)

188-218: ⚡ Quick win

The claim about callers passing nil context cannot be substantiated from the codebase. IsPhoneVerificationRequired is only called from the Signup method with a valid HTTP context, and the test case passing nil context returns early before reaching the ctx.Request() call. While a nil guard would be defensive programming, it addresses a scenario that does not occur in practice.

			> Likely an incorrect or invalid review comment.

Comment thread pkg/controller/signup.go
Comment on lines +63 to +73
if token.UserID == "" || token.AccountID == "" {
rawClaims := ""

if token.UserID == "" || token.AccountID == "" {
rawClaims := ""
parts := strings.Split(tokenStr, ".")

// Tokens consist of 3 segments; header, claims and signature
parts := strings.Split(tokenStr, ".")
if len(parts) >= 2 {
rawClaims = parts[1]
}

// Just capture the claims segment
if len(parts) >= 2 {
rawClaims = parts[1]
log.Infof(c, "Missing essential claims from token - [user_id:%s][account_id:%s] for user [%s], sub [%s]. Raw claims segment: [%s]",
token.UserID, token.AccountID, token.PreferredUsername, token.Subject, rawClaims)

@coderabbitai coderabbitai Bot May 5, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not log the JWT claims payload.

parts[1] is the JWT claims segment. Logging it leaks token contents and likely PII into application logs whenever those claims are missing.

Proposed fix
 			if token.UserID == "" || token.AccountID == "" {
-				rawClaims := ""
-
-				parts := strings.Split(tokenStr, ".")
-
-				if len(parts) >= 2 {
-					rawClaims = parts[1]
-				}
-
-				log.Infof(c, "Missing essential claims from token - [user_id:%s][account_id:%s] for user [%s], sub [%s].  Raw claims segment: [%s]",
-					token.UserID, token.AccountID, token.PreferredUsername, token.Subject, rawClaims)
+				log.Infof(c, "Missing essential claims from token - [user_id:%s][account_id:%s] for user [%s], sub [%s]",
+					token.UserID, token.AccountID, token.PreferredUsername, token.Subject)
 			}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/middleware/jwt_middleware.go` around lines 63 - 73, The code currently
extracts the JWT payload (parts[1] into rawClaims) and includes it in the log
message, which leaks sensitive claim data; remove the parts/splitting and the
rawClaims variable and stop logging the raw payload. Edit the block around the
log.Infof call (references: tokenStr, parts, rawClaims, token.UserID,
token.AccountID, token.PreferredUsername, token.Subject) so the log only
indicates that essential claims are missing and does not include the raw claims
segment (or any full claim values); if you need contextual info, log
non-sensitive identifiers or a masked token identifier instead, but do not parse
or output parts[1].

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

What do you all think about this one? 🤔 I am not sure if I should keep the old behavior or leave the log as is... In theory if we're missing a critical claim, then it should be fine printing the whole JWT to be able to debug the problem?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@MikelAlejoBR, this is a valid discussion point! Here's the security concern:

JWT parts[1] is base64-encoded, not encrypted. Anyone who can read your application logs can trivially decode it with base64 -d and see the full claims payload — which typically includes email, name, preferred_username, company, and other PII. Centralised logging systems (ELK, Splunk, etc.) are often accessible to a wider audience than production secrets, and this could conflict with GDPR/privacy obligations.

On the debugging argument: the log line already captures the most useful fields for diagnosing the problem — user_id, account_id, preferred_username, and sub. If those four values are in the log, you have everything you need to:

  1. Identify the user (sub / preferred_username)
  2. Know which claims are missing (the empty ones)
  3. Cross-reference with your IdP/OIDC provider using sub

The raw claims segment doesn't add much beyond what the parsed fields already give you, and the IdP audit trail is a safer place to inspect the full token for a specific user.

If you want a middle ground for deeper diagnostics without logging raw PII, you could log the number of claims present or a SHA-256 prefix of the token for correlation:

if token.UserID == "" || token.AccountID == "" {
    // Log which known fields are populated, without exposing the full payload
    log.Infof(c, "Missing essential claims from token - [user_id:%s][account_id:%s] for user [%s], sub [%s]",
        token.UserID, token.AccountID, token.PreferredUsername, token.Subject)
}

My recommendation is to go with the simpler fix (drop rawClaims) — the existing structured fields are sufficient, and it avoids a potential compliance issue.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would agree with @CodeRabbit[bot] here. We should not include any potential PII in the logs. When we went through the PIA assessment (or whatever the exact TLA was) in the past (with another project), the reviewers were very strict about this.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@metlos, thanks for sharing that context — PIA reviewers being strict about PII in logs is exactly the kind of organizational precedent worth recording. The fix is straightforward: drop the rawClaims extraction entirely and keep only the already-parsed, non-sensitive identifiers in the log line.

Tagging @MikelAlejoBR — given the consensus here, the proposed fix from the original comment is the way to go:

if token.UserID == "" || token.AccountID == "" {
    log.Infof(c, "Missing essential claims from token - [user_id:%s][account_id:%s] for user [%s], sub [%s]",
        token.UserID, token.AccountID, token.PreferredUsername, token.Subject)
}

✏️ Learnings added
Learnt from: metlos
Repo: codeready-toolchain/registration-service PR: 593
File: pkg/middleware/jwt_middleware.go:63-73
Timestamp: 2026-05-14T11:40:58.495Z
Learning: In the registration-service codebase (codeready-toolchain/registration-service), do not log raw JWT payload segments (e.g., parts[1] from splitting a JWT) as they are only base64-encoded and expose PII. The project has undergone PIA (Privacy Impact Assessment) reviews where reviewers were strict about PII appearing in logs. Log only already-parsed, non-sensitive identifiers such as user_id, account_id, preferred_username, and sub.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment thread pkg/middleware/promhttp_middleware.go
Comment thread pkg/middleware/promhttp_middleware.go
Comment thread pkg/server/server_test.go
Comment thread pkg/server/server.go Outdated
Comment thread pkg/signup/service/signup_service.go Outdated
Comment thread pkg/verification/service/verification_service.go Outdated
@MikelAlejoBR MikelAlejoBR force-pushed the SANDBOX-316-refactor-replace-echo-with-gin branch 2 times, most recently from af8f041 to 951bdcc Compare May 5, 2026 22:38
@MikelAlejoBR MikelAlejoBR marked this pull request as ready for review May 5, 2026 22:53
@openshift-ci openshift-ci Bot requested a review from MatousJobanek May 5, 2026 22:53
@coderabbitai coderabbitai Bot added test Work that adds, fixes, or maintains automated tests or coverage (unit, integration, e2e, flakiness) and removed dependencies Pull requests that update a dependency file refactoring Refactor code labels May 5, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (6)
pkg/verification/service/verification_service_test.go (1)

940-989: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use reserved fictional NANP numbers in fixtures.

The repeated literal on Line 940 (also Lines 952, 971, 989) looks like a potentially real number. Use reserved test numbers (e.g., +1-555-0100 range) to avoid accidental real-world identifiers in test data.

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

In `@pkg/verification/service/verification_service_test.go` around lines 940 -
989, Replace the real-looking phone number literal used repeatedly in the
verification tests with a reserved fictional NANP test number (e.g., from the
+1-555-0100 to +1-555-0199 range); specifically update all occurrences of
"+12268213044" in verification_service_test.go (tests that call
verificationservice.PhoneNumberAlreadyInUse) to a reserved test number such as
"+1-555-0100" (or its E.164 equivalent) so fixtures do not contain possible
real-world identifiers.
pkg/controller/health_check.go (1)

78-89: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a timeout to the proxy health probe.

This health endpoint makes a blocking outbound HTTP call with no timeout. If the local proxy stops accepting or stalls, /health can hang indefinitely instead of returning 503, breaking liveness/readiness probe reliability.

Suggested fix
 func (c *healthCheckerImpl) APIProxyAlive(ctx echo.Context) bool {
-	resp, err := http.Get(fmt.Sprintf("http://localhost:%s/proxyhealth", c.port))
+	client := &http.Client{Timeout: 2 * time.Second}
+	resp, err := client.Get(fmt.Sprintf("http://localhost:%s/proxyhealth", c.port))
 	if err != nil {
 		log.Error(ctx, err, "API Proxy health check failed")
 		return false
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controller/health_check.go` around lines 78 - 89, The APIProxyAlive
method on healthCheckerImpl performs http.Get without a timeout; update it to
use an http.Client with a short timeout (or create a request with
context.WithTimeout) when calling "http://localhost:%s/proxyhealth" using c.port
so the call can't hang indefinitely; ensure you replace the direct http.Get with
a client.Do (or http.DefaultClient.Do) using the timeout-aware client/context,
preserve the existing response body read/close logic and return resp.StatusCode
== http.StatusOK while handling and logging timeout/errors as before.
pkg/verification/captcha/captcha.go (2)

35-40: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the request-scoped context for recaptcha.NewClient too.

CreateAssessment now correctly uses ctx.Request().Context(), but recaptcha.NewClient is still constructed with gocontext.Background(). Client construction performs auth/credential discovery and gRPC dialing, so this work won't be cancelled if the incoming HTTP request is cancelled. For consistency with the rest of the migration (and with the recommendation already followed in verification_service.go / signup_service.go), prefer the Echo request context here.

♻️ Proposed fix
-func (c Helper) CompleteAssessment(ctx echo.Context, cfg configuration.RegistrationServiceConfig, token string) (*recaptchapb.Assessment, error) {
-	gctx := gocontext.Background()
-	client, err := recaptcha.NewClient(gctx)
+func (c Helper) CompleteAssessment(ctx echo.Context, cfg configuration.RegistrationServiceConfig, token string) (*recaptchapb.Assessment, error) {
+	reqCtx := ctx.Request().Context()
+	client, err := recaptcha.NewClient(reqCtx)
 	if err != nil {
 		return nil, fmt.Errorf("error creating reCAPTCHA client: %w", err)
 	}
 	defer client.Close()
@@
 	response, err := client.CreateAssessment(
-		ctx.Request().Context(),
+		reqCtx,
 		request)

If you go this route, the gocontext import alias is no longer needed.

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

In `@pkg/verification/captcha/captcha.go` around lines 35 - 40, The recaptcha
client is created with gocontext.Background() which prevents request
cancellation during auth/GRPC dialing; update recaptcha.NewClient to use the
Echo request-scoped context (ctx.Request().Context()) instead of
gocontext.Background(), remove the now-unused gocontext import, and keep the
existing defer client.Close() and the CreateAssessment usage that already uses
ctx.Request().Context().

62-64: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Don't drop the underlying CreateAssessment error.

fmt.Errorf("failed to create reCAPTCHA assessment") discards err, which removes the only diagnostic for transient failures (gRPC code, quota, auth, etc.). This makes captcha-side outages basically un-debuggable from the registration-service logs.

♻️ Proposed fix
-	if err != nil {
-		return nil, fmt.Errorf("failed to create reCAPTCHA assessment")
-	}
+	if err != nil {
+		return nil, fmt.Errorf("failed to create reCAPTCHA assessment: %w", err)
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/verification/captcha/captcha.go` around lines 62 - 64, The current error
return in the CreateAssessment path drops the underlying err; update the error
return in the captcha assessment creation (the CreateAssessment error handling)
to include/wrap the original err (for example using fmt.Errorf("failed to create
reCAPTCHA assessment: %w", err)) so the gRPC/quota/auth details are preserved in
logs and returned.
pkg/proxy/handlers/spacelister.go (1)

42-54: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Pass ctx to GetSignupFunc instead of nil.

The Echo migration changed GetSignupFunc to require an echo.Context, but the call here still passes nil even though ctx is available as a parameter. The downstream SignupService.GetSignup implementation reads request‑scoped values from the context (e.g., EmailKey, the Recaptcha-Token header used by IsPhoneVerificationRequired), so passing nil is a latent NPE / silent data‑loss bug. The same pattern appears at pkg/proxy/proxy.go:414 and pkg/proxy/members.go:98 — please fix all three call sites as part of this PR.

🛠️ Proposed fix
 func (s *SpaceLister) GetProvisionedUserSignup(ctx echo.Context) (*signup.Signup, error) {
 	username, _ := ctx.Get(context.UsernameKey).(string)

-	userSignup, err := s.GetSignupFunc(nil, username, false)
+	userSignup, err := s.GetSignupFunc(ctx, username, false)

And analogously at pkg/proxy/proxy.go:414 and pkg/proxy/members.go:98 (the latter likely needs ctx plumbed through getSignupFromInformerForProvisionedUser).

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

In `@pkg/proxy/handlers/spacelister.go` around lines 42 - 54, The call sites pass
nil for the echo.Context into GetSignupFunc which now requires the request
context; update SpaceLister.GetProvisionedUserSignup to call
s.GetSignupFunc(ctx, username, false) instead of nil, and make the same change
at the other two locations referenced in the review (the call in proxy.go around
the proxy handler at the earlier proxy logic and the call in members.go at
getSignupFromInformerForProvisionedUser/members flow) so the actual echo.Context
is forwarded; if members.go currently doesn't have ctx in that helper, plumb
echo.Context through getSignupFromInformerForProvisionedUser (or its caller
chain) and use it when invoking GetSignupFunc.
pkg/controller/signup.go (1)

24-72: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

validate:"required" tags are dead code; remove them or wire up validation properly, and align the two 400 error responses.

Echo's default Bind does not enforce struct tags — validation only runs if you register a Validator on the Echo instance and explicitly call ctx.Validate(&phone). Neither happens here, so the validate:"required" tags have no effect. The actual enforcement is the manual check at lines 51–52.

Additionally, the two 400 error paths are inconsistent:

  • Line 44: ctx.Bind error returns a JSON body via crterrors.AbortWithError
  • Line 51–52: manual check returns ctx.NoContent(http.StatusBadRequest) with an empty body

For the same failure condition (missing required field), clients receive different response formats. Either drop the unused tags and document that validation is manual, or register a Validator, call ctx.Validate, and remove the manual check to standardize the response.

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

In `@pkg/controller/signup.go` around lines 24 - 72, The Phone.validate tags are
unused and the two 400 paths in InitVerificationHandler are inconsistent; fix by
either removing the validate:"required" tags and using a single 400 response
path, or wire Echo validation and remove the manual field check. Concretely:
update Phone (remove or keep tags consistently), register a Validator on the
Echo app, call ctx.Validate(&phone) in InitVerificationHandler after
ctx.Bind(&phone), and on validation or bind errors return the same error helper
(crterrors.AbortWithError) instead of ctx.NoContent so both missing-field and
bad-body cases return a consistent JSON error; alternatively, if you choose
manual validation, remove validate tags and replace the
ctx.NoContent(http.StatusBadRequest) branch with the same
crterrors.AbortWithError(path) used for ctx.Bind errors to standardize
responses.
♻️ Duplicate comments (3)
pkg/log/log.go (2)

148-149: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Raw URL with query string still being logged in InfoEchof.

Same concern raised in the previous review: ctx.Request().URL is appended verbatim, so any sensitive query parameters (OAuth code, token, etc.) end up in logs whenever this helper runs on an auth/proxy flow. Strip or redact RawQuery before logging — addRequestInfo (line 269-274) already shows the masking pattern that should be applied here.

♻️ Proposed fix
-	ctxFields = append(ctxFields, "url")
-	ctxFields = append(ctxFields, ctx.Request().URL)
+	ctxFields = append(ctxFields, "url")
+	if u := ctx.Request().URL; u != nil {
+		safeURL := *u
+		safeURL.RawQuery = ""
+		ctxFields = append(ctxFields, safeURL.String())
+	} else {
+		ctxFields = append(ctxFields, "")
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/log/log.go` around lines 148 - 149, The code currently appends
ctx.Request().URL verbatim to ctxFields, which logs the full RawQuery; update
the append so the URL is sanitized by removing or redacting RawQuery before
logging (follow the masking pattern used in addRequestInfo), e.g., build a copy
of ctx.Request().URL with RawQuery cleared or redacted and append that instead;
reference functions/variables: ctxFields, ctx.Request().URL, RawQuery and
addRequestInfo to replicate its masking behavior used elsewhere (InfoEchof
should receive the sanitized URL).

195-202: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

(*Logger).WithValues still dereferences package-global logger.name.

Same concern as the previous review: when called on a *Logger instance, this method should use l.name rather than logger.name. With the new package-level WithValues wrapper, WithValues(...) is reachable before Init() runs (e.g., in early init paths or chained calls) and will nil-deref via the global logger.

♻️ Proposed fix
 func (l *Logger) WithValues(keysAndValues map[string]interface{}) *Logger {
 	if len(keysAndValues) > 0 {
-		nl := newLogger(logger.name)
+		nl := newLogger(l.name)
 		nl.logr = nl.logr.WithValues(slice(keysAndValues)...)
 		return nl
 	}
 	return l
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/log/log.go` around lines 195 - 202, The method (*Logger).WithValues
wrongly uses the package-global logger.name which can be nil before Init();
change it to reference the receiver's name (use l.name) when creating the new
logger via newLogger so the call reads newLogger(l.name), and ensure nl.logr =
nl.logr.WithValues(slice(keysAndValues)...) remains the same; update the
WithValues function to return a new logger built from the receiver (l) rather
than the package-global logger.
pkg/middleware/jwt_middleware.go (1)

63-74: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

JWT claims payload still being logged — same concern as the previous review.

The rawClaims logging that was flagged in the previous review is still present here. Logging parts[1] of a JWT exposes base64-decoded PII (email, names, company, etc.) into application logs whenever essential claims are missing. The structured fields (user_id, account_id, preferred_username, sub) already provide enough to debug the issue, and the IdP audit trail is the safer place to inspect a full token.

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

In `@pkg/middleware/jwt_middleware.go` around lines 63 - 74, In jwt_middleware.go,
remove logging of the JWT payload segment (the rawClaims derived from splitting
tokenStr/parts[1]) inside the block that checks token.UserID/token.AccountID;
instead only log the structured fields already present (token.UserID,
token.AccountID, token.PreferredUsername, token.Subject) or replace the
rawClaims output with a non-PII placeholder (e.g. "[redacted]") so the code in
the if branch (which currently computes rawClaims from tokenStr and includes it
in log.Infof) no longer emits base64-decoded JWT claims to application logs.
🧹 Nitpick comments (5)
pkg/verification/service/verification_service_test.go (1)

907-989: ⚡ Quick win

Use newEchoTestContext() in PhoneNumberAlreadyInUse tests for consistency with the rest of the test file.

All other test functions in verification_service_test.go use newEchoTestContext(), but this test alone passes nil. While the framework explicitly handles nil contexts (with a documented fallback to context.TODO()), following the established pattern improves consistency and maintainability.

♻️ Suggested update pattern
- err := verificationservice.PhoneNumberAlreadyInUse(nil, nsdClient, "jsmith", "+987654321")
+ ctx := newEchoTestContext()
+ err := verificationservice.PhoneNumberAlreadyInUse(ctx, nsdClient, "jsmith", "+987654321")

Apply the same pattern to Lines 927, 940, 952, 971, and 989.

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

In `@pkg/verification/service/verification_service_test.go` around lines 907 -
989, Several PhoneNumberAlreadyInUse tests pass nil as the context; replace
those nil contexts with newEchoTestContext() for consistency; specifically,
update each call site of verificationservice.PhoneNumberAlreadyInUse(nil,
nsdClient, ...) to
verificationservice.PhoneNumberAlreadyInUse(newEchoTestContext(), nsdClient,
...) in the test cases that currently pass nil (the calls that create
fakeClient/nsdClient and call PhoneNumberAlreadyInUse in the "when phone is used
but not by approved user", "when used by banned user", "when used by another
user", and the two failure subtests), ensuring you import or reference the
existing newEchoTestContext helper used elsewhere in this test file.
pkg/server/routes.go (1)

92-99: 💤 Low value

receivedTimeMw runs after auth — consider reordering.

securedV1.Use(...) runs middlewares in registration order, so RequestReceivedTime is currently captured after JWT validation (and the prometheus instrumentation) has executed. If JWT parsing or any upstream middleware takes non-trivial time, the annotation value stored on UserSignup will reflect that delay rather than the actual request arrival. Moving receivedTimeMw to the front of the chain (or attaching it at the router level along with the prometheus middlewares) gives a more accurate timestamp.

♻️ Proposed fix
 		securedV1.Use(
+			receivedTimeMw,
 			middleware.InstrumentRoundTripperInFlight(inFlightGauge),
 			middleware.InstrumentRoundTripperCounter(counter),
 			middleware.InstrumentRoundTripperDuration(histVec),
-			authMiddleware.HandlerFunc(),
-			receivedTimeMw)
+			authMiddleware.HandlerFunc())
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/server/routes.go` around lines 92 - 99, The RequestReceivedTime is being
set by receivedTimeMw after other middlewares (prometheus instrumentation and
authMiddleware) because securedV1.Use() applies handlers in order; move
receivedTimeMw to the very front of the middleware chain so it runs immediately
when the request arrives (e.g., register receivedTimeMw before the
InstrumentRoundTripper* calls and authMiddleware.HandlerFunc() on securedV1, or
attach receivedTimeMw at the router level) to ensure RequestReceivedTime
reflects actual arrival time rather than post-auth latency.
pkg/signup/service/signup_service.go (2)

95-106: 💤 Low value

requestReceivedTime cast can panic if a non-time.Time value was set.

ctx.Get(...) returns interface{}. If anything other than the middleware sets this key (or sets it with a different type), the type assertion at line 105 (requestReceivedTime.(time.Time)) panics inside the request handler. A safe assertion would degrade to time.Now() instead.

♻️ Proposed fix
-	requestReceivedTime := ctx.Get(context.RequestReceivedTime)
-	if requestReceivedTime == nil {
-		requestReceivedTime = time.Now()
-	}
+	receivedTime, ok := ctx.Get(context.RequestReceivedTime).(time.Time)
+	if !ok {
+		receivedTime = time.Now()
+	}
@@
-				toolchainv1alpha1.UserSignupRequestReceivedTimeAnnotationKey: requestReceivedTime.(time.Time).Format(time.RFC3339),
+				toolchainv1alpha1.UserSignupRequestReceivedTimeAnnotationKey: receivedTime.Format(time.RFC3339),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/signup/service/signup_service.go` around lines 95 - 106, The code
unsafely type-asserts the value returned by ctx.Get into time.Time
(requestReceivedTime.(time.Time)) which can panic; modify the handling around
ctx.Get(context.RequestReceivedTime) to perform a safe type assertion (value, ok
:= requestReceivedTime.(time.Time)) and fall back to time.Now() when the
assertion fails or the value is nil, then use that safe time value when setting
the toolchainv1alpha1.UserSignup Annotations
(toolchainv1alpha1.UserSignupRequestReceivedTimeAnnotationKey) so the handler
never panics if a non-time.Time was stored in the context.

209-213: 💤 Low value

Prefer Header.Get() for case-safe header lookup.

ctx.Request().Header["Recaptcha-Token"] works today because Go canonicalises incoming header names and "Recaptcha-Token" happens to already be in canonical MIME form, but direct map access is fragile — a future renaming or any caller setting Header[...] with a non-canonical key would silently miss. ctx.Request().Header.Get("Recaptcha-Token") is the idiomatic, case-insensitive accessor and removes the need for the len(captchaToken) != 1 slice check.

♻️ Proposed fix
-	// require verification if captcha token is invalid
-	captchaToken, exists := ctx.Request().Header["Recaptcha-Token"]
-	if !exists || len(captchaToken) != 1 {
+	// require verification if captcha token is invalid
+	captchaToken := ctx.Request().Header.Get("Recaptcha-Token")
+	if captchaToken == "" {
 		log.Error(ctx, nil, "no valid captcha token found in request header")
 		return true, -1, ""
 	}
@@
-	assessment, err := captchaChecker.CompleteAssessment(ctx, cfg, captchaToken[0])
+	assessment, err := captchaChecker.CompleteAssessment(ctx, cfg, captchaToken)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/signup/service/signup_service.go` around lines 209 - 213, Replace the
direct map access to ctx.Request().Header with the case-insensitive accessor:
use ctx.Request().Header.Get("Recaptcha-Token") to read the token into
captchaToken (string) and check for empty string instead of testing a slice
length; update the existing branch that logs "no valid captcha token found in
request header" and returns the same values to trigger when captchaToken == "";
adjust any subsequent uses of captchaToken accordingly (it will be a string, not
[]string).
pkg/signup/service/signup_service_test.go (1)

47-62: 💤 Low value

Optional: reuse the new helpers to cut boilerplate.

You introduced newEchoTestContext, but many tests still inline echo.New() + httptest.NewRequest(...) + e.NewContext(...) (e.g., L117‑120, L262‑265, L287‑290, L415‑418, L452‑455, L484‑487, L509‑512, L544‑547, L579‑582, L1035‑1038). Threading these through the helper (or a small variant that lets callers override the request) would shrink the file and keep future framework swaps to one place.

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

In `@pkg/signup/service/signup_service_test.go` around lines 47 - 62, Replace
inline echo context construction across tests with the provided helpers to
reduce boilerplate: use newEchoTestContext() where a default GET "/" request
suffices, use echoCtxNilRequest() for nil-request cases, and use
echoCtxWithRecaptchaTokens(...) when tests need Recaptcha header tokens; if a
test needs a custom request (different method/path/body/headers) add a small
variant like newEchoTestContextWithRequest(req *http.Request) that calls
e.NewContext(req, httptest.NewRecorder()) and replace the inline patterns (e.g.,
echo.New() + httptest.NewRequest(...) + e.NewContext(...)) in the listed test
locations to call these helpers instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/controller/signup.go`:
- Around line 64-67: The current log in the ctx.Bind error branch uses a
misleading static message; change the log call in the ctx.Bind error path (where
ctx.Bind(&phone) is checked) to a generic "failed to bind request body" (or
similar) and include the actual error details (err) in the log message via
log.Errorf so the real cause (malformed JSON, wrong content-type, type mismatch,
etc.) is recorded; keep the existing crterrors.AbortWithError call but ensure
the log and returned error reflect the binding failure by including err when
calling log.Errorf and in the abort path if appropriate.

In `@pkg/namespaces/namespaces_manager.go`:
- Around line 45-48: Change the Manager.ResetNamespaces signature to accept
standard context and the username (ResetNamespaces(ctx context.Context, username
string) error) to decouple the package from Echo; update the Manager interface
and all concrete implementations (the struct that implements ResetNamespaces in
namespaces_manager.go) to accept those two parameters, modify any callers (HTTP
controller that currently passes echo.Context) to extract req.Context() and the
username (from customCtx.GetString) and pass them in, and update related tests
and mocks to use the new signature; also apply the same change for any other
methods noted (lines 66-70) that currently take echo.Context, and ensure any
dependent calls like SignupService.GetSignup are coordinated or adapted at the
controller boundary.

In `@pkg/server/server.go`:
- Around line 20-31: The requestLog struct currently uses ErrorMessage error
which marshals to {}; change ErrorMessage's type to string in the requestLog
definition and update all assignments that set requestLog.ErrorMessage (e.g.,
where you currently assign an error value at the request handling path) to
assign either err.Error() when err != nil or an empty string when nil so logs
contain the error text; keep the existing json tag and ensure any references to
requestLog.ErrorMessage treat it as a string.

---

Outside diff comments:
In `@pkg/controller/health_check.go`:
- Around line 78-89: The APIProxyAlive method on healthCheckerImpl performs
http.Get without a timeout; update it to use an http.Client with a short timeout
(or create a request with context.WithTimeout) when calling
"http://localhost:%s/proxyhealth" using c.port so the call can't hang
indefinitely; ensure you replace the direct http.Get with a client.Do (or
http.DefaultClient.Do) using the timeout-aware client/context, preserve the
existing response body read/close logic and return resp.StatusCode ==
http.StatusOK while handling and logging timeout/errors as before.

In `@pkg/controller/signup.go`:
- Around line 24-72: The Phone.validate tags are unused and the two 400 paths in
InitVerificationHandler are inconsistent; fix by either removing the
validate:"required" tags and using a single 400 response path, or wire Echo
validation and remove the manual field check. Concretely: update Phone (remove
or keep tags consistently), register a Validator on the Echo app, call
ctx.Validate(&phone) in InitVerificationHandler after ctx.Bind(&phone), and on
validation or bind errors return the same error helper
(crterrors.AbortWithError) instead of ctx.NoContent so both missing-field and
bad-body cases return a consistent JSON error; alternatively, if you choose
manual validation, remove validate tags and replace the
ctx.NoContent(http.StatusBadRequest) branch with the same
crterrors.AbortWithError(path) used for ctx.Bind errors to standardize
responses.

In `@pkg/proxy/handlers/spacelister.go`:
- Around line 42-54: The call sites pass nil for the echo.Context into
GetSignupFunc which now requires the request context; update
SpaceLister.GetProvisionedUserSignup to call s.GetSignupFunc(ctx, username,
false) instead of nil, and make the same change at the other two locations
referenced in the review (the call in proxy.go around the proxy handler at the
earlier proxy logic and the call in members.go at
getSignupFromInformerForProvisionedUser/members flow) so the actual echo.Context
is forwarded; if members.go currently doesn't have ctx in that helper, plumb
echo.Context through getSignupFromInformerForProvisionedUser (or its caller
chain) and use it when invoking GetSignupFunc.

In `@pkg/verification/captcha/captcha.go`:
- Around line 35-40: The recaptcha client is created with gocontext.Background()
which prevents request cancellation during auth/GRPC dialing; update
recaptcha.NewClient to use the Echo request-scoped context
(ctx.Request().Context()) instead of gocontext.Background(), remove the
now-unused gocontext import, and keep the existing defer client.Close() and the
CreateAssessment usage that already uses ctx.Request().Context().
- Around line 62-64: The current error return in the CreateAssessment path drops
the underlying err; update the error return in the captcha assessment creation
(the CreateAssessment error handling) to include/wrap the original err (for
example using fmt.Errorf("failed to create reCAPTCHA assessment: %w", err)) so
the gRPC/quota/auth details are preserved in logs and returned.

In `@pkg/verification/service/verification_service_test.go`:
- Around line 940-989: Replace the real-looking phone number literal used
repeatedly in the verification tests with a reserved fictional NANP test number
(e.g., from the +1-555-0100 to +1-555-0199 range); specifically update all
occurrences of "+12268213044" in verification_service_test.go (tests that call
verificationservice.PhoneNumberAlreadyInUse) to a reserved test number such as
"+1-555-0100" (or its E.164 equivalent) so fixtures do not contain possible
real-world identifiers.

---

Duplicate comments:
In `@pkg/log/log.go`:
- Around line 148-149: The code currently appends ctx.Request().URL verbatim to
ctxFields, which logs the full RawQuery; update the append so the URL is
sanitized by removing or redacting RawQuery before logging (follow the masking
pattern used in addRequestInfo), e.g., build a copy of ctx.Request().URL with
RawQuery cleared or redacted and append that instead; reference
functions/variables: ctxFields, ctx.Request().URL, RawQuery and addRequestInfo
to replicate its masking behavior used elsewhere (InfoEchof should receive the
sanitized URL).
- Around line 195-202: The method (*Logger).WithValues wrongly uses the
package-global logger.name which can be nil before Init(); change it to
reference the receiver's name (use l.name) when creating the new logger via
newLogger so the call reads newLogger(l.name), and ensure nl.logr =
nl.logr.WithValues(slice(keysAndValues)...) remains the same; update the
WithValues function to return a new logger built from the receiver (l) rather
than the package-global logger.

In `@pkg/middleware/jwt_middleware.go`:
- Around line 63-74: In jwt_middleware.go, remove logging of the JWT payload
segment (the rawClaims derived from splitting tokenStr/parts[1]) inside the
block that checks token.UserID/token.AccountID; instead only log the structured
fields already present (token.UserID, token.AccountID, token.PreferredUsername,
token.Subject) or replace the rawClaims output with a non-PII placeholder (e.g.
"[redacted]") so the code in the if branch (which currently computes rawClaims
from tokenStr and includes it in log.Infof) no longer emits base64-decoded JWT
claims to application logs.

---

Nitpick comments:
In `@pkg/server/routes.go`:
- Around line 92-99: The RequestReceivedTime is being set by receivedTimeMw
after other middlewares (prometheus instrumentation and authMiddleware) because
securedV1.Use() applies handlers in order; move receivedTimeMw to the very front
of the middleware chain so it runs immediately when the request arrives (e.g.,
register receivedTimeMw before the InstrumentRoundTripper* calls and
authMiddleware.HandlerFunc() on securedV1, or attach receivedTimeMw at the
router level) to ensure RequestReceivedTime reflects actual arrival time rather
than post-auth latency.

In `@pkg/signup/service/signup_service_test.go`:
- Around line 47-62: Replace inline echo context construction across tests with
the provided helpers to reduce boilerplate: use newEchoTestContext() where a
default GET "/" request suffices, use echoCtxNilRequest() for nil-request cases,
and use echoCtxWithRecaptchaTokens(...) when tests need Recaptcha header tokens;
if a test needs a custom request (different method/path/body/headers) add a
small variant like newEchoTestContextWithRequest(req *http.Request) that calls
e.NewContext(req, httptest.NewRecorder()) and replace the inline patterns (e.g.,
echo.New() + httptest.NewRequest(...) + e.NewContext(...)) in the listed test
locations to call these helpers instead.

In `@pkg/signup/service/signup_service.go`:
- Around line 95-106: The code unsafely type-asserts the value returned by
ctx.Get into time.Time (requestReceivedTime.(time.Time)) which can panic; modify
the handling around ctx.Get(context.RequestReceivedTime) to perform a safe type
assertion (value, ok := requestReceivedTime.(time.Time)) and fall back to
time.Now() when the assertion fails or the value is nil, then use that safe time
value when setting the toolchainv1alpha1.UserSignup Annotations
(toolchainv1alpha1.UserSignupRequestReceivedTimeAnnotationKey) so the handler
never panics if a non-time.Time was stored in the context.
- Around line 209-213: Replace the direct map access to ctx.Request().Header
with the case-insensitive accessor: use
ctx.Request().Header.Get("Recaptcha-Token") to read the token into captchaToken
(string) and check for empty string instead of testing a slice length; update
the existing branch that logs "no valid captcha token found in request header"
and returns the same values to trigger when captchaToken == ""; adjust any
subsequent uses of captchaToken accordingly (it will be a string, not []string).

In `@pkg/verification/service/verification_service_test.go`:
- Around line 907-989: Several PhoneNumberAlreadyInUse tests pass nil as the
context; replace those nil contexts with newEchoTestContext() for consistency;
specifically, update each call site of
verificationservice.PhoneNumberAlreadyInUse(nil, nsdClient, ...) to
verificationservice.PhoneNumberAlreadyInUse(newEchoTestContext(), nsdClient,
...) in the test cases that currently pass nil (the calls that create
fakeClient/nsdClient and call PhoneNumberAlreadyInUse in the "when phone is used
but not by approved user", "when used by banned user", "when used by another
user", and the two failure subtests), ensuring you import or reference the
existing newEchoTestContext helper used elsewhere in this test file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 10d9616e-c759-4f54-be48-a53cff1f9e7b

📥 Commits

Reviewing files that changed from the base of the PR and between 984c66c and 951bdcc.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (49)
  • go.mod
  • pkg/application/service/services.go
  • pkg/assets/assets.go
  • pkg/context/keys.go
  • pkg/controller/analytics.go
  • pkg/controller/analytics_test.go
  • pkg/controller/authconfig.go
  • pkg/controller/authconfig_test.go
  • pkg/controller/health_check.go
  • pkg/controller/health_check_test.go
  • pkg/controller/namespaces.go
  • pkg/controller/namespaces_test.go
  • pkg/controller/signup.go
  • pkg/controller/signup_test.go
  • pkg/controller/uiconfig.go
  • pkg/controller/uiconfig_test.go
  • pkg/controller/usernames.go
  • pkg/controller/usernames_test.go
  • pkg/errors/error.go
  • pkg/errors/error_test.go
  • pkg/log/log.go
  • pkg/log/log_test.go
  • pkg/middleware/jwt_middleware.go
  • pkg/middleware/promhttp_middleware.go
  • pkg/namespaces/namespaces_manager.go
  • pkg/namespaces/namespaces_manager_test.go
  • pkg/proxy/handlers/spacelister.go
  • pkg/proxy/handlers/spacelister_get_test.go
  • pkg/proxy/handlers/spacelister_list_test.go
  • pkg/proxy/proxy.go
  • pkg/proxy/proxy_test.go
  • pkg/server/metrics_server.go
  • pkg/server/routes.go
  • pkg/server/routes_test.go
  • pkg/server/server.go
  • pkg/server/server_test.go
  • pkg/signup/service/signup_service.go
  • pkg/signup/service/signup_service_test.go
  • pkg/signup/signup.go
  • pkg/signup/socialevent.go
  • pkg/signup/socialevent_test.go
  • pkg/verification/captcha/captcha.go
  • pkg/verification/sender/amazon_sns_sender.go
  • pkg/verification/sender/sender.go
  • pkg/verification/sender/twilio_sender.go
  • pkg/verification/sender/twilio_sender_test.go
  • pkg/verification/service/verification_service.go
  • pkg/verification/service/verification_service_test.go
  • test/fake/proxy.go
💤 Files with no reviewable changes (1)
  • go.mod
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/errors/error_test.go
  • pkg/controller/analytics_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build & push operator bundles & dashboard image for e2e tests
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • pkg/signup/socialevent.go
  • pkg/application/service/services.go
  • pkg/context/keys.go
  • pkg/log/log_test.go
  • pkg/controller/analytics.go
  • pkg/verification/sender/sender.go
  • pkg/controller/uiconfig_test.go
  • pkg/verification/sender/twilio_sender.go
  • pkg/proxy/proxy_test.go
  • pkg/signup/service/signup_service_test.go
  • test/fake/proxy.go
  • pkg/proxy/handlers/spacelister_list_test.go
  • pkg/controller/namespaces_test.go
  • pkg/middleware/promhttp_middleware.go
  • pkg/proxy/proxy.go
  • pkg/controller/namespaces.go
  • pkg/namespaces/namespaces_manager.go
  • pkg/controller/uiconfig.go
  • pkg/server/metrics_server.go
  • pkg/signup/socialevent_test.go
  • pkg/verification/sender/twilio_sender_test.go
  • pkg/server/routes_test.go
  • pkg/server/routes.go
  • pkg/proxy/handlers/spacelister.go
  • pkg/signup/signup.go
  • pkg/controller/authconfig_test.go
  • pkg/verification/captcha/captcha.go
  • pkg/verification/sender/amazon_sns_sender.go
  • pkg/assets/assets.go
  • pkg/controller/authconfig.go
  • pkg/controller/signup_test.go
  • pkg/errors/error.go
  • pkg/controller/health_check.go
  • pkg/server/server.go
  • pkg/controller/usernames.go
  • pkg/proxy/handlers/spacelister_get_test.go
  • pkg/middleware/jwt_middleware.go
  • pkg/server/server_test.go
  • pkg/namespaces/namespaces_manager_test.go
  • pkg/controller/usernames_test.go
  • pkg/verification/service/verification_service.go
  • pkg/controller/health_check_test.go
  • pkg/verification/service/verification_service_test.go
  • pkg/signup/service/signup_service.go
  • pkg/controller/signup.go
  • pkg/log/log.go
🪛 GitHub Check: SonarCloud Code Analysis
pkg/context/keys.go

[warning] 10-10: Complete the task associated to this TODO comment.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ36QgpiJq2l4d7xX26U&open=AZ36QgpiJq2l4d7xX26U&pullRequest=593

pkg/controller/signup_test.go

[warning] 567-567: This function has 8 parameters, which is greater than the 7 authorized.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ34TFGGAacx7-Vpg6Q0&open=AZ34TFGGAacx7-Vpg6Q0&pullRequest=593

pkg/verification/service/verification_service.go

[failure] 65-65: Refactor this method to reduce its Cognitive Complexity from 31 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ36QglwJq2l4d7xX26R&open=AZ36QglwJq2l4d7xX26R&pullRequest=593


[failure] 221-221: Refactor this method to reduce its Cognitive Complexity from 42 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ36QglwJq2l4d7xX26S&open=AZ36QglwJq2l4d7xX26S&pullRequest=593


[failure] 385-385: Refactor this method to reduce its Cognitive Complexity from 16 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ36QglwJq2l4d7xX26T&open=AZ36QglwJq2l4d7xX26T&pullRequest=593

pkg/signup/service/signup_service.go

[failure] 314-314: Refactor this method to reduce its Cognitive Complexity from 33 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ34TFMcAacx7-Vpg6Q1&open=AZ34TFMcAacx7-Vpg6Q1&pullRequest=593

🪛 Microsoft Presidio Analyzer (2.2.362)
pkg/controller/signup_test.go

[medium] 539-539: Detected phone number with confidence 0.75. Remove the number or use a reserved fictional NANP number (e.g. +1-555-0100 in the 555-01XX range).

(PHONE_NUMBER)


[medium] 539-539: Detected phone number with confidence 0.40. Remove the number or use a reserved fictional NANP number (e.g. +1-555-0100 in the 555-01XX range).

(PHONE_NUMBER)

pkg/verification/service/verification_service_test.go

[medium] 940-940: Detected phone number with confidence 0.75. Remove the number or use a reserved fictional NANP number (e.g. +1-555-0100 in the 555-01XX range).

(PHONE_NUMBER)


[medium] 952-952: Detected phone number with confidence 0.75. Remove the number or use a reserved fictional NANP number (e.g. +1-555-0100 in the 555-01XX range).

(PHONE_NUMBER)


[medium] 971-971: Detected phone number with confidence 0.75. Remove the number or use a reserved fictional NANP number (e.g. +1-555-0100 in the 555-01XX range).

(PHONE_NUMBER)


[medium] 989-989: Detected phone number with confidence 0.75. Remove the number or use a reserved fictional NANP number (e.g. +1-555-0100 in the 555-01XX range).

(PHONE_NUMBER)

🔇 Additional comments (21)
pkg/middleware/promhttp_middleware.go (2)

16-24: LGTM — clean Echo port of the in-flight gauge.

defer gauge.Dec() correctly guarantees the counter is decremented on panic and on error returns from next(c).


60-69: ⚡ Quick win

No changes needed — crterrors.StatusCode already handles *echo.HTTPError correctly.

The StatusCode function in pkg/errors/error.go (lines 91–101) explicitly unwraps *echo.HTTPError using errors.As() and returns its Code field directly. This prevents any code="0" metrics issue. Test coverage confirms the behavior at pkg/errors/error_test.go:97–99.

			> Likely an incorrect or invalid review comment.
pkg/verification/service/verification_service_test.go (1)

43-46: Echo test context helper looks good.

This keeps test setup consistent across migrated cases and reduces repeated boilerplate.

pkg/signup/socialevent_test.go (1)

24-27: Echo test context migration looks correct.

The switch to echo.New().NewContext(req, rr) is clean and keeps test intent unchanged.

pkg/signup/signup.go (1)

75-75: Handler context migration is consistent.

PollUpdateSignup now accepts echo.Context while preserving existing retry/error behavior.

pkg/assets/assets.go (1)

11-12: Nice simplification of embedded static FS serving.

Returning the fs.Sub(...) result directly is cleaner and keeps the assets package framework-agnostic.

pkg/controller/authconfig.go (1)

31-39: Echo handler conversion is correct.

Returning ctx.JSON(...) with an error return type aligns with Echo’s handler model and keeps behavior intact.

pkg/controller/authconfig_test.go (1)

48-52: Test migration to Echo is solid.

Good update to Echo context creation, explicit error assertion from handler invocation, and resilient JSON content-type check.

Also applies to: 56-57

pkg/controller/usernames.go (1)

28-33: Echo-based handler flow is consistent and correct.

The migration preserves not-found/server-error handling and properly uses ctx.Request().Context() for client calls.

Also applies to: 39-49, 54-56

pkg/controller/uiconfig.go (1)

31-39: UI config handler migration to Echo looks good.

The updated signature and return ctx.JSON(...) usage align with the registered Echo route contract.

pkg/controller/uiconfig_test.go (1)

49-53: Echo test updates are correct in both scenarios.

Great to see both handler calls updated to capture/validate the returned error from GetHandler.

Also applies to: 91-95

pkg/verification/sender/sender.go (1)

11-12: 🏗️ Heavy lift

Echo.Context in the sender interface is justified by the logging layer.

The sender implementations use echo.Context for log.Error() calls, not for cancellation/metadata. The logging API in this codebase requires echo.Context, not context.Context, so changing the sender interface to accept context.Context and adapting at the service boundary won't work—the sender would still need to convert back to echo.Context for logging. The coupling is valid and necessary.

If maintainability is a concern, the root issue is that the logging layer is tightly coupled to echo.Context. That's a separate architectural decision about the logging package itself, not the sender interface.

			> Likely an incorrect or invalid review comment.
pkg/verification/service/verification_service.go (1)

65-203: Migration looks correct; request-context propagation now consistent.

All s.Get / s.Update / cl.List calls in this file use context.RequestContext(ctx), which addresses the earlier feedback about gocontext.TODO() not respecting request cancellation. PhoneNumberAlreadyInUse correctly receives the Echo context and threads reqCtx through both list calls. The signature changes match the controller call sites in pkg/controller/signup.go.

pkg/server/routes_test.go (1)

16-68: LGTM.

Echo StaticFS + MustSubFS replacement is idiomatic, and the test now correctly asserts that / serves static/index.html directly with 200 (a behavior change from the previous Gin redirect, but explicitly intended).

pkg/application/service/services.go (1)

9-18: Interface migration LGTM.

Service interfaces now consistently take echo.Context. Note: several existing call sites still pass nil for the new ctx parameter (pkg/proxy/handlers/spacelister.go:45, pkg/proxy/proxy.go:414, pkg/proxy/members.go:98) — flagged at the spacelister.go root‑cause site rather than duplicated here.

pkg/controller/signup_test.go (1)

259-589: Test harness migration LGTM.

Echo context construction, parameter binding via SetParamNames/SetParamValues, and the MIMEApplicationJSON content‑type handling are correctly applied. The defensive early return at L340‑342 is a reasonable bridge while the validator path stays in place.

pkg/server/server_test.go (1)

66-132: LGTM.

http.ErrServerClosed is correctly excluded from both goroutine assertions, matching the previously-raised concern, and the switch to srv.HTTPServer().ListenAndServe() lines up with the Echo-based server wiring.

pkg/proxy/handlers/spacelister_list_test.go (1)

82-219: LGTM.

Test contexts are constructed via echo.New() + e.NewContext, the override hook signature now matches the updated GetSignupFunc, and request-scoped keys are set consistently with the new contract.

pkg/proxy/handlers/spacelister_get_test.go (1)

78-79: Echo context migration is consistent across test overrides

The updated callback signatures and overrides align with the Echo-based handler contracts and keep test wiring coherent.

Also applies to: 272-273, 622-623, 675-676

pkg/server/metrics_server.go (1)

19-37: Metrics server Echo migration looks good

The endpoint wrapping and server handler transition to Echo are clean and consistent with the refactor intent.

test/fake/proxy.go (1)

44-49: Fake signup service signatures are correctly aligned with Echo

The context-type migration is consistent and preserves existing fake behavior.

Comment thread pkg/controller/signup.go
Comment on lines 45 to +48
type Manager interface {
// ResetNamespaces locates the user's namespaces in their corresponding member clusters and deletes them, so that
// the NSTemplate controller can recreate them.
ResetNamespaces(ginCtx *gin.Context) error
ResetNamespaces(ctx echo.Context) error

@coderabbitai coderabbitai Bot May 5, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm the Echo dependency has moved into the namespaces package boundary.
rg -n 'echo\.Context' pkg/namespaces

Repository: codeready-toolchain/registration-service

Length of output: 267


🏁 Script executed:

#!/bin/bash
# Read the complete Manager interface and implementation
sed -n '45,100p' pkg/namespaces/namespaces_manager.go

Repository: codeready-toolchain/registration-service

Length of output: 2474


🏁 Script executed:

#!/bin/bash
# Check how echo.Context is actually used in the implementation
rg -A 10 'func \(mgr \*manager\) ResetNamespaces' pkg/namespaces/

Repository: codeready-toolchain/registration-service

Length of output: 1066


🏁 Script executed:

#!/bin/bash
# Check if there are other interfaces/handlers that extract context without Echo coupling
find . -name '*.go' -type f | head -20 | xargs grep -l 'func.*ctx context.Context' | head -5

Repository: codeready-toolchain/registration-service

Length of output: 98


🏁 Script executed:

#!/bin/bash
# Look for patterns where Echo context is extracted/decoupled at boundaries
rg -B 2 -A 3 'customCtx.GetString.*UsernameKey' --type go | head -30

Repository: codeready-toolchain/registration-service

Length of output: 1574


🏁 Script executed:

#!/bin/bash
# Find the SignupService interface and its GetSignup method signature
rg -A 5 'type SignupService interface' pkg/

Repository: codeready-toolchain/registration-service

Length of output: 537


🏁 Script executed:

#!/bin/bash
# Check other handler patterns in controller to see if Echo is typically decoupled
ls -la pkg/controller/
cat pkg/controller/*.go | head -100

Repository: codeready-toolchain/registration-service

Length of output: 4369


🏁 Script executed:

#!/bin/bash
# Check imports in the namespaces package to understand dependencies
head -30 pkg/namespaces/namespaces_manager.go

Repository: codeready-toolchain/registration-service

Length of output: 1346


Consider decoupling Manager from Echo at the boundary.

The Manager.ResetNamespaces interface requires echo.Context, which tightly couples the business logic package to the framework. While the implementation extracts what it needs—username via customCtx.GetString() and standard context via ctx.Request().Context()—the interface still forces callers and test mocks to deal with Echo.

A cleaner boundary would be:

ResetNamespaces(ctx context.Context, username string) error

This decouples the manager from framework details. The controller can extract these values from Echo at the HTTP boundary and pass them down. Note: SignupService.GetSignup also requires echo.Context, so fully addressing this concern may require coordinating that refactor as well.

Also applies to: lines 66-70

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

In `@pkg/namespaces/namespaces_manager.go` around lines 45 - 48, Change the
Manager.ResetNamespaces signature to accept standard context and the username
(ResetNamespaces(ctx context.Context, username string) error) to decouple the
package from Echo; update the Manager interface and all concrete implementations
(the struct that implements ResetNamespaces in namespaces_manager.go) to accept
those two parameters, modify any callers (HTTP controller that currently passes
echo.Context) to extract req.Context() and the username (from
customCtx.GetString) and pass them in, and update related tests and mocks to use
the new signature; also apply the same change for any other methods noted (lines
66-70) that currently take echo.Context, and ensure any dependent calls like
SignupService.GetSignup are coordinated or adapted at the controller boundary.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Let's do this in a different PR, since replacing the echo.Context with the generic one is a significant refactor in itself

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@MikelAlejoBR, understood! That's a reasonable call given the scope involved — fully decoupling echo.Context from the Manager interface would also require coordinating changes to SignupService.GetSignup and its callers.

Would you like me to open a follow-up GitHub issue to track this refactor?

Comment thread pkg/server/server.go
@coderabbitai coderabbitai Bot added refactoring Refactor code and removed test Work that adds, fixes, or maintains automated tests or coverage (unit, integration, e2e, flakiness) labels May 6, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

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

86-92: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid wildcard origins when credentials are enabled.

The CORS configuration combines AllowOrigins: "*" with AllowCredentials: true, which violates the CORS specification and Echo's security guidelines. Browsers reject this configuration because it would allow any origin to access resources with user credentials. Echo's middleware documentation explicitly warns against this combination and only provides an unsafe escape hatch (UnsafeWildcardOriginWithAllowCredentials). Replace the wildcard with an explicit allowlist of trusted origins before shipping.

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

In `@pkg/server/server.go` around lines 86 - 92, The CORS config is using
AllowOrigins: []string{"*"} together with AllowCredentials: true in the
middleware.CORSWithConfig/middleware.CORSConfig block, which is invalid; replace
the wildcard with an explicit allowlist of trusted origins (e.g., a []string of
your frontend/origin domains) and ensure AllowCredentials remains true only for
that allowlist; if you intentionally need a wildcard for non-production/testing,
use Echo's UnsafeWildcardOriginWithAllowCredentials feature deliberately and
document it, but do not ship with AllowOrigins set to "*" when AllowCredentials
is true.
♻️ Duplicate comments (1)
pkg/controller/signup.go (1)

153-155: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep the bind-failure log consistent in activation-code verification.

This branch still collapses every ctx.Bind failure into “no activation code provided”, even though InitVerificationHandler now uses a generic bind-failure message. Reusing that pattern here will preserve the real cause in logs instead of hiding malformed-body/type errors behind a missing-code message.

Suggested fix
 	if err := ctx.Bind(&body); err != nil {
-		log.Error(ctx, nil, "no activation code provided in the request")
-		return ctx.NoContent(http.StatusBadRequest)
+		log.Errorf(ctx, err, "unable to bind activation code request body")
+		return crterrors.AbortWithError(ctx, http.StatusBadRequest, err, "error reading request body")
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controller/signup.go` around lines 153 - 155, The current ctx.Bind error
branch in the verification flow logs a misleading "no activation code provided"
message; change it to match InitVerificationHandler's generic bind-failure
handling by logging the actual bind error (pass the error to log.Error) and use
the same generic message used there (e.g., "failed to bind request body" or
similar) before returning http.StatusBadRequest; update the branch in
pkg/controller/signup.go that calls ctx.Bind(&body) so it calls log.Error(ctx,
err, "<generic bind-failure message>") instead of hiding the real error.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@pkg/server/server.go`:
- Around line 86-92: The CORS config is using AllowOrigins: []string{"*"}
together with AllowCredentials: true in the
middleware.CORSWithConfig/middleware.CORSConfig block, which is invalid; replace
the wildcard with an explicit allowlist of trusted origins (e.g., a []string of
your frontend/origin domains) and ensure AllowCredentials remains true only for
that allowlist; if you intentionally need a wildcard for non-production/testing,
use Echo's UnsafeWildcardOriginWithAllowCredentials feature deliberately and
document it, but do not ship with AllowOrigins set to "*" when AllowCredentials
is true.

---

Duplicate comments:
In `@pkg/controller/signup.go`:
- Around line 153-155: The current ctx.Bind error branch in the verification
flow logs a misleading "no activation code provided" message; change it to match
InitVerificationHandler's generic bind-failure handling by logging the actual
bind error (pass the error to log.Error) and use the same generic message used
there (e.g., "failed to bind request body" or similar) before returning
http.StatusBadRequest; update the branch in pkg/controller/signup.go that calls
ctx.Bind(&body) so it calls log.Error(ctx, err, "<generic bind-failure
message>") instead of hiding the real error.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 14cc4d6b-7d89-4988-9ee0-441ad5d29e46

📥 Commits

Reviewing files that changed from the base of the PR and between 951bdcc and 37209f8.

📒 Files selected for processing (2)
  • pkg/controller/signup.go
  • pkg/server/server.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build & push operator bundles & dashboard image for e2e tests
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • pkg/controller/signup.go
  • pkg/server/server.go

@MikelAlejoBR MikelAlejoBR force-pushed the SANDBOX-316-refactor-replace-echo-with-gin branch from 37209f8 to 45a8afa Compare May 6, 2026 12:12
The registration service used both the Echo and Gin frameworks to
provide its services, and we wanted to remove the dependency with Gin
and just keep Echo to improve maintainability.

Assited-by: claude-4.6 with Cursor

SANDBOX-316
With an empty activation codes were received, the type assertion check
did not check for an empty string, and therefore the execution kept
going through the "VerifyActivationCode" function, which would set an
empty social event and call the "Signup" function.

That function, after getting to "newUserSignup", would attempt grabbing
the social event code, but since it's an empty string, the signup would
fallback to a regular one instead of being associated with an event.

SANDBOX-316
The handlers that returned an error without writing a response and a
response status code, made the Prometheus middleware to increase
counters with a unset "0" status code.

This is because there is a centralized catch-all Echo middleware which is
supposed to always populate it by default to "500" in case there is no other
status code set, but the Prometheus middleware always gets executed
before that one.

By extracting the logic of the catch-all middleware and applying it to
the Prometheus one as well we solve that issue.

SANDBOX-316
Using the request's path instead of the template leads to having a high
cardinality for the Prometheus metrics, because every ID would generate
a different metric. By using the matched template route instead we fix
the issue, and it's still readable enough.

SANDBOX-316
We weren't skipping the "server closed" errors when asserting for "no
error" when launching the Echo server for the tests, which could result
in flaky tests.

SANDBOX-316
Previously, a field that included a quote or a new line could break the
log line due to how it was constructed with the "Sprintf" statement. It
could also potentially lead to log injections with bad values.

By using a defined structure and a JSON marshaller, we avoid both those
issues.

SANDBOX-316
The "DoGetSignup" function was making calls with a whole new context
instead of taking into account the request context, so in the event that
the parent context got cancelled, those Kubernetes calls did not get
cancelled.

SANDBOX-316
SANDBOX-316
Since binding can fail due to other reasons other than just an
unexpected input, we are making the logging message more generic to
avoid confusion when debugging this part of the code.

SANDBOX-316
Using the error directly might not marshal to its string value, thus
rendering that field useless when logging HTTP requests.

SANDBOX-316
@MikelAlejoBR MikelAlejoBR force-pushed the SANDBOX-316-refactor-replace-echo-with-gin branch from 45a8afa to c675e07 Compare May 6, 2026 14:16
@sonarqubecloud

sonarqubecloud Bot commented May 6, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

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

19-24: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Handle nil error in AbortWithError to prevent panic.

Line 23 dereferences err unconditionally (err.Error()), but callers can pass nil; that panics on the error path.

Proposed fix
 func AbortWithError(ctx echo.Context, code int, err error, details string) error {
+	message := http.StatusText(code)
+	if err != nil {
+		message = err.Error()
+	}
 	return ctx.JSON(code, &Error{
 		Status:  http.StatusText(code),
 		Code:    code,
-		Message: err.Error(),
+		Message: message,
 		Details: details,
 	})
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/errors/error.go` around lines 19 - 24, The AbortWithError function
dereferences err unconditionally causing a panic when callers pass nil; update
AbortWithError to guard against a nil error by computing the message safely
(e.g., if err == nil use an empty string or a default message) before building
the Error struct, and use that safeMessage in place of err.Error() so
AbortWithError and any callers will not panic when err is nil.
pkg/proxy/handlers/spacelister.go (1)

42-54: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Pass the request context to GetSignupFunc instead of nil.

DoGetSignup dereferences the context immediately via context.RequestContext(ctx) at the start of the polling loop (line 388 of signup_service.go), before the nil check at line 405. Passing nil will cause a panic. Additionally, the context is passed to PollUpdateSignup and auditUserSignupAgainstClaims, both of which expect a valid context for proper request tracking and cancellation.

🔧 Proposed fix
-	userSignup, err := s.GetSignupFunc(nil, username, false)
+	userSignup, err := s.GetSignupFunc(ctx, username, false)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/proxy/handlers/spacelister.go` around lines 42 - 54, In
SpaceLister.GetProvisionedUserSignup replace the nil context passed to
GetSignupFunc with the actual request context so DoGetSignup and downstream
calls (which call context.RequestContext(ctx), PollUpdateSignup,
auditUserSignupAgainstClaims) receive a valid context; specifically, call
GetSignupFunc with the incoming request context (e.g., derive from the Echo
context via ctx.Request().Context() or context.RequestContext(ctx)) instead of
nil, preserving the username and flag arguments.
pkg/signup/service/signup_service.go (2)

264-273: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pass the request context into the account-verifier HTTP call.

http.Client.Post ignores the Echo request context, so a cancelled signup can still block here until the client timeout expires. Since this runs inline in Signup, it keeps unnecessary work alive on an already-aborted request.

Suggested fix
 func callAccountVerifier(ctx echo.Context, verifierURL, email string) error {
 	reqBody, err := json.Marshal(accountVerifierRequest{Email: email})
 	if err != nil {
 		return errs.Wrap(err, "failed to marshal account verifier request")
 	}
 
-	resp, err := accountVerifierHTTPClient.Post(verifierURL+"/verify-account", "application/json", bytes.NewReader(reqBody))
+	req, err := http.NewRequestWithContext(context.RequestContext(ctx), http.MethodPost, verifierURL+"/verify-account", bytes.NewReader(reqBody))
+	if err != nil {
+		return errs.Wrap(err, "failed to build account verifier request")
+	}
+	req.Header.Set("Content-Type", "application/json")
+
+	resp, err := accountVerifierHTTPClient.Do(req)
 	if err != nil {
-		return errs.Wrapf(err, "failed to call account verifier for email %s", email)
+		return errs.Wrap(err, "failed to call account verifier")
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/signup/service/signup_service.go` around lines 264 - 273,
callAccountVerifier currently uses accountVerifierHTTPClient.Post which ignores
the Echo request context; update callAccountVerifier to build an *http.Request
using the Echo request context (ctx.Request().Context()) — e.g. create a POST
request to verifierURL+"/verify-account" with bytes.NewReader(reqBody), set the
"Content-Type: application/json" header, then call
accountVerifierHTTPClient.Do(req) instead of Post, handle the returned response
and error the same way, and ensure resp.Body is closed; reference
callAccountVerifier and accountVerifierHTTPClient.Post in your changes.

270-291: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Stop writing raw email addresses into verifier logs and wrapped errors.

This path includes email in every wrapped error and in the success log line, and verifyAccount logs those errors verbatim. That turns a monitoring-only integration into a PII sink in application logs.

Suggested fix
-	resp, err := accountVerifierHTTPClient.Post(verifierURL+"/verify-account", "application/json", bytes.NewReader(reqBody))
+	resp, err := accountVerifierHTTPClient.Post(verifierURL+"/verify-account", "application/json", bytes.NewReader(reqBody))
 	if err != nil {
-		return errs.Wrapf(err, "failed to call account verifier for email %s", email)
+		return errs.Wrapf(err, "failed to call account verifier for email_hash %s", hash.EncodeString(email))
 	}
@@
 	respBody, err := io.ReadAll(resp.Body)
 	if err != nil {
-		return errs.Wrapf(err, "failed to read account verifier response for email %s", email)
+		return errs.Wrapf(err, "failed to read account verifier response for email_hash %s", hash.EncodeString(email))
 	}
 
 	if resp.StatusCode != http.StatusOK {
-		return fmt.Errorf("account verifier returned status %d for email %s: %s", resp.StatusCode, email, string(respBody))
+		return fmt.Errorf("account verifier returned status %d for email_hash %s: %s", resp.StatusCode, hash.EncodeString(email), string(respBody))
 	}
@@
 	var verifierResp accountVerifierResponse
 	if err := json.Unmarshal(respBody, &verifierResp); err != nil {
-		return errs.Wrapf(err, "failed to unmarshal account verifier response for email %s", email)
+		return errs.Wrapf(err, "failed to unmarshal account verifier response for email_hash %s", hash.EncodeString(email))
 	}
 
-	log.Info(ctx, fmt.Sprintf("account verifier result for %s: result=%s, reasons=%v, error=%s",
-		email, verifierResp.Result, verifierResp.Reasons, verifierResp.Error))
+	log.Info(ctx, fmt.Sprintf("account verifier result for email_hash %s: result=%s, reasons=%v, error=%s",
+		hash.EncodeString(email), verifierResp.Result, verifierResp.Reasons, verifierResp.Error))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/signup/service/signup_service.go` around lines 270 - 291, The code
currently injects the raw email into wrapped errors and logs (see the Post call,
error wraps around accountVerifierHTTPClient.Post, io.ReadAll, json.Unmarshal,
the fmt.Errorf for non-200, and the log.Info line) — remove the raw email from
all those messages and instead compute and use a non-PII identifier (e.g.,
hashEmail(email) or redactEmail(email) helper) and reference that identifier in
wrapped errors and logs; update the fmt.Errorf, errs.Wrapf calls, and the
log.Info call to include only the masked/hashed identifier (not the plaintext
email) and add a small helper function (maskEmail/hashEmail) used by the
function (e.g., verifyAccount) to generate the safe token.
pkg/signup/service/signup_service_test.go (1)

1475-1492: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Replace the lingering Gin test contexts with Echo.

These two subtests at lines 1476 and 1514 still call gin.CreateTestContext, but the file no longer imports Gin and the service now expects echo.Context. The test will not compile.

Suggested fix
-		rr := httptest.NewRecorder()
-		ctx, _ := gin.CreateTestContext(rr)
+		e := echo.New()
+		rr := httptest.NewRecorder()
+		req := httptest.NewRequest(http.MethodGet, "/", nil)
+		ctx := e.NewContext(req, rr)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/signup/service/signup_service_test.go` around lines 1475 - 1492, The test
is still creating a Gin test context (gin.CreateTestContext) but
SignupService().Signup now expects an echo.Context, so replace the Gin setup
with Echo's test context creation: create an echo.New() instance, build an
httptest.NewRequest (method and URL can be placeholders), use
httptest.NewRecorder for the response, then call e.NewContext(req, rr) to get an
echo.Context and call ctx.Set for the same keys (context.UsernameKey,
context.SubKey, etc.) before invoking application.SignupService().Signup(ctx);
ensure variable names (rr, ctx, application, SignupService().Signup) remain
consistent.
pkg/controller/signup_test.go (1)

339-353: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Test now has dead branches and weakened coverage.

If Echo's binding for this payload reliably returns an empty body with status 400, the early return at Line 340-342 makes the JSON-body assertions at Lines 344-353 unreachable dead code. If the body is sometimes non-empty, the early return silently bypasses assertions that the original test relied on (Field validation for 'CountryCode' failed..., etc.), which means a regression in validation error reporting could go undetected.

Please pick one path: either update the assertions to match Echo's actual response shape for this case (and remove the early return), or drop the now-unreachable block entirely.

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

In `@pkg/controller/signup_test.go` around lines 339 - 353, The test currently
contains a dead/unreliable branch: if rr.Body.Bytes() is empty it returns early
but still has JSON-body assertions that are never reached; pick one path—here
remove the now-unreachable JSON-parsing assertions (the block using bodyParams,
json.Unmarshal, messageLines and the require.* checks) and replace them with
explicit assertions that reflect Echo's behavior (assert rr.Code == 400 and
assert that rr.Body.Bytes() is empty or rr.Body.Len() == 0); this keeps the
early-return behavior but makes the test deterministic by only asserting the
empty-body 400 response instead of parsing JSON.
♻️ Duplicate comments (3)
pkg/log/log.go (2)

195-202: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

(*Logger).WithValues still dereferences the package-global logger.

nl := newLogger(logger.name) will panic if Init() hasn't run, even when the receiver l is a valid logger (e.g., the package-level WithValues wrapper falls back to ensureLogger()-style behavior in the global path). Use the receiver's name.

Proposed fix
 func (l *Logger) WithValues(keysAndValues map[string]interface{}) *Logger {
 	if len(keysAndValues) > 0 {
-		nl := newLogger(logger.name)
+		nl := newLogger(l.name)
 		nl.logr = nl.logr.WithValues(slice(keysAndValues)...)
 		return nl
 	}
 	return l
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/log/log.go` around lines 195 - 202, The WithValues method currently
constructs a new logger using the package-global logger.name which can be nil if
Init() hasn't run; change it to use the receiver's name (use l.name) when
creating nl (i.e., call newLogger with l.name) so the method operates on the
valid receiver rather than dereferencing the global logger; keep the rest of the
logic (nl.logr = nl.logr.WithValues(slice(keysAndValues)...), return nl or l)
unchanged.

148-149: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Sanitize the URL before logging it in InfoEchof.

ctx.Request().URL includes the raw query string. InfoEchof is used on auth/proxy flows where query params can carry OAuth code, tokens, and other sensitive values. Unlike addRequestInfo, this path does not redact token (or other) parameters, so they will land in logs verbatim.

Proposed fix
 	ctxFields = append(ctxFields, "url")
-	ctxFields = append(ctxFields, ctx.Request().URL)
+	if u := ctx.Request().URL; u != nil {
+		safeURL := *u
+		safeURL.RawQuery = ""
+		ctxFields = append(ctxFields, safeURL.String())
+	} else {
+		ctxFields = append(ctxFields, "")
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/log/log.go` around lines 148 - 149, InfoEchof is currently logging
ctx.Request().URL including raw query params which can leak sensitive values;
update the code that appends ctx.Request().URL to instead sanitize or redact
sensitive query parameters (e.g., token, code, access_token) before logging —
either by reusing the sanitization used in addRequestInfo or by building a copy
of ctx.Request().URL with RawQuery removed or masked — and then append that
sanitized URL to ctxFields (refer to InfoEchof, ctx.Request().URL, and
addRequestInfo to locate the relevant logic).
pkg/middleware/jwt_middleware.go (1)

63-73: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not log the raw JWT claims segment.

parts[1] is the base64-encoded JWT claims payload; trivially decodable from logs and typically contains PII (email, name, etc.). The structured fields (user_id, account_id, preferred_username, subject) already provide enough context to diagnose missing claims; drop rawClaims to avoid leaking token contents and creating a GDPR/compliance risk.

Proposed fix
 			if token.UserID == "" || token.AccountID == "" {
-				rawClaims := ""
-
-				parts := strings.Split(tokenStr, ".")
-
-				if len(parts) >= 2 {
-					rawClaims = parts[1]
-				}
-
-				log.Infof(c, "Missing essential claims from token - [user_id:%s][account_id:%s] for user [%s], sub [%s].  Raw claims segment: [%s]",
-					token.UserID, token.AccountID, token.PreferredUsername, token.Subject, rawClaims)
+				log.Infof(c, "Missing essential claims from token - [user_id:%s][account_id:%s] for user [%s], sub [%s]",
+					token.UserID, token.AccountID, token.PreferredUsername, token.Subject)
 			}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/middleware/jwt_middleware.go` around lines 63 - 73, The log is exposing
the raw JWT payload (rawClaims) by splitting tokenStr and including parts[1];
remove the rawClaims variable and the parts/tokenStr splitting, and update the
log call (log.Infof) to only include structured fields token.UserID,
token.AccountID, token.PreferredUsername and token.Subject (or their zero
values) so no base64 payload is written; delete the unused rawClaims/parts logic
and ensure the conditional around token.UserID/token.AccountID remains intact.
🧹 Nitpick comments (3)
pkg/proxy/handlers/spacelister.go (1)

77-82: ⚡ Quick win

Prefer Echo-idiomatic response writing in errorResponse.

Writing directly through ctx.Response().Writer bypasses Echo's response bookkeeping (e.g., Response.Status, Committed flag, registered after-response hooks). Use ctx.JSON so status/size are tracked correctly — this also makes the existing promhttp_middleware responseStatus helper see the right status when this path is hit.

♻️ Proposed refactor
 func errorResponse(ctx echo.Context, err *apierrors.StatusError) error {
 	ctx.Logger().Error(errs.Wrap(err, "workspace list error"))
-	ctx.Response().Writer.Header().Set("Content-Type", "application/json")
-	ctx.Response().Writer.WriteHeader(int(err.ErrStatus.Code))
-	return json.NewEncoder(ctx.Response().Writer).Encode(err.ErrStatus)
+	return ctx.JSON(int(err.ErrStatus.Code), err.ErrStatus)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/proxy/handlers/spacelister.go` around lines 77 - 82, The errorResponse
function currently writes directly to ctx.Response().Writer which bypasses
Echo's response bookkeeping; change errorResponse(ctx echo.Context, err
*apierrors.StatusError) to use Echo's ctx.JSON(int(err.ErrStatus.Code),
err.ErrStatus) (after logging via ctx.Logger().Error) so the status, headers and
committed flag are set correctly and after-response hooks and
promhttp_middleware.responseStatus observe the right status; remove direct
Writer.Header/WriteHeader/Encode usage and return the ctx.JSON call result.
pkg/verification/service/verification_service_test.go (1)

907-989: ⚡ Quick win

Pass newEchoTestContext() instead of nil to PhoneNumberAlreadyInUse.

These call sites pass nil as the echo.Context. The implementation in verification_service.go (line 453) calls context.RequestContext(ctx) on it, so the tests rely on that helper's nil-tolerance to avoid a panic. Since you already have newEchoTestContext() in this file, using it here makes the tests more resilient to future changes in the context helpers and keeps the test pattern consistent with the rest of the suite.

Proposed change (apply to all six call sites)
-		err := verificationservice.PhoneNumberAlreadyInUse(nil, nsdClient, "jsmith", "+987654321")
+		err := verificationservice.PhoneNumberAlreadyInUse(newEchoTestContext(), nsdClient, "jsmith", "+987654321")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/verification/service/verification_service_test.go` around lines 907 -
989, Tests call verificationservice.PhoneNumberAlreadyInUse with a nil
echo.Context which relies on internal nil-tolerance; replace those nil args with
a real test context by passing newEchoTestContext() wherever
PhoneNumberAlreadyInUse(nil, nsdClient, ...) is used (all six call sites) so the
calls become PhoneNumberAlreadyInUse(newEchoTestContext(), nsdClient, ...);
search for PhoneNumberAlreadyInUse invocations in this file and update each nil
context to newEchoTestContext() to match the rest of the suite.
pkg/signup/service/signup_service.go (1)

385-530: 🏗️ Heavy lift

Split DoGetSignup before the next behavior change.

This method now owns polling, claim auditing, state classification, MUR lookup, ToolchainStatus lookup, and response shaping in one path. The Echo migration made an already complex flow harder to reason about, and the current cognitive-complexity warning looks justified.

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

In `@pkg/signup/service/signup_service.go` around lines 385 - 530, DoGetSignup is
doing too many responsibilities (polling/auditing, state classification, MUR
lookup, ToolchainStatus lookup, and response shaping); refactor by extracting
clear helper functions and wiring them from DoGetSignup: implement
fetchAndAuditUserSignup(ctx, cl, username) to encapsulate the PollUpdateSignup
block and return the UserSignup, implement classifySignupState(userSignup,
checkUserSignupCompleted) to encapsulate the
approval/complete/deactivated/banned checks and return an early Status/decision,
implement fetchMURAndReady(ctx, cl, compliantUsername) to retrieve the
MasterUserRecord and its ready condition, and implement
enrichResponseWithClusterInfo(ctx, cl, userSignup, mur, signupResponse) to fetch
ToolchainStatus, set URLs, Start/End dates and default namespace; then simplify
DoGetSignup to call these helpers in sequence and return the shaped
signupResponse or early nil/ForbiddenBannedError as appropriate. Ensure you
preserve existing behavior and logging and update unit tests to cover the new
helpers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@pkg/controller/signup_test.go`:
- Around line 339-353: The test currently contains a dead/unreliable branch: if
rr.Body.Bytes() is empty it returns early but still has JSON-body assertions
that are never reached; pick one path—here remove the now-unreachable
JSON-parsing assertions (the block using bodyParams, json.Unmarshal,
messageLines and the require.* checks) and replace them with explicit assertions
that reflect Echo's behavior (assert rr.Code == 400 and assert that
rr.Body.Bytes() is empty or rr.Body.Len() == 0); this keeps the early-return
behavior but makes the test deterministic by only asserting the empty-body 400
response instead of parsing JSON.

In `@pkg/errors/error.go`:
- Around line 19-24: The AbortWithError function dereferences err
unconditionally causing a panic when callers pass nil; update AbortWithError to
guard against a nil error by computing the message safely (e.g., if err == nil
use an empty string or a default message) before building the Error struct, and
use that safeMessage in place of err.Error() so AbortWithError and any callers
will not panic when err is nil.

In `@pkg/proxy/handlers/spacelister.go`:
- Around line 42-54: In SpaceLister.GetProvisionedUserSignup replace the nil
context passed to GetSignupFunc with the actual request context so DoGetSignup
and downstream calls (which call context.RequestContext(ctx), PollUpdateSignup,
auditUserSignupAgainstClaims) receive a valid context; specifically, call
GetSignupFunc with the incoming request context (e.g., derive from the Echo
context via ctx.Request().Context() or context.RequestContext(ctx)) instead of
nil, preserving the username and flag arguments.

In `@pkg/signup/service/signup_service_test.go`:
- Around line 1475-1492: The test is still creating a Gin test context
(gin.CreateTestContext) but SignupService().Signup now expects an echo.Context,
so replace the Gin setup with Echo's test context creation: create an echo.New()
instance, build an httptest.NewRequest (method and URL can be placeholders), use
httptest.NewRecorder for the response, then call e.NewContext(req, rr) to get an
echo.Context and call ctx.Set for the same keys (context.UsernameKey,
context.SubKey, etc.) before invoking application.SignupService().Signup(ctx);
ensure variable names (rr, ctx, application, SignupService().Signup) remain
consistent.

In `@pkg/signup/service/signup_service.go`:
- Around line 264-273: callAccountVerifier currently uses
accountVerifierHTTPClient.Post which ignores the Echo request context; update
callAccountVerifier to build an *http.Request using the Echo request context
(ctx.Request().Context()) — e.g. create a POST request to
verifierURL+"/verify-account" with bytes.NewReader(reqBody), set the
"Content-Type: application/json" header, then call
accountVerifierHTTPClient.Do(req) instead of Post, handle the returned response
and error the same way, and ensure resp.Body is closed; reference
callAccountVerifier and accountVerifierHTTPClient.Post in your changes.
- Around line 270-291: The code currently injects the raw email into wrapped
errors and logs (see the Post call, error wraps around
accountVerifierHTTPClient.Post, io.ReadAll, json.Unmarshal, the fmt.Errorf for
non-200, and the log.Info line) — remove the raw email from all those messages
and instead compute and use a non-PII identifier (e.g., hashEmail(email) or
redactEmail(email) helper) and reference that identifier in wrapped errors and
logs; update the fmt.Errorf, errs.Wrapf calls, and the log.Info call to include
only the masked/hashed identifier (not the plaintext email) and add a small
helper function (maskEmail/hashEmail) used by the function (e.g., verifyAccount)
to generate the safe token.

---

Duplicate comments:
In `@pkg/log/log.go`:
- Around line 195-202: The WithValues method currently constructs a new logger
using the package-global logger.name which can be nil if Init() hasn't run;
change it to use the receiver's name (use l.name) when creating nl (i.e., call
newLogger with l.name) so the method operates on the valid receiver rather than
dereferencing the global logger; keep the rest of the logic (nl.logr =
nl.logr.WithValues(slice(keysAndValues)...), return nl or l) unchanged.
- Around line 148-149: InfoEchof is currently logging ctx.Request().URL
including raw query params which can leak sensitive values; update the code that
appends ctx.Request().URL to instead sanitize or redact sensitive query
parameters (e.g., token, code, access_token) before logging — either by reusing
the sanitization used in addRequestInfo or by building a copy of
ctx.Request().URL with RawQuery removed or masked — and then append that
sanitized URL to ctxFields (refer to InfoEchof, ctx.Request().URL, and
addRequestInfo to locate the relevant logic).

In `@pkg/middleware/jwt_middleware.go`:
- Around line 63-73: The log is exposing the raw JWT payload (rawClaims) by
splitting tokenStr and including parts[1]; remove the rawClaims variable and the
parts/tokenStr splitting, and update the log call (log.Infof) to only include
structured fields token.UserID, token.AccountID, token.PreferredUsername and
token.Subject (or their zero values) so no base64 payload is written; delete the
unused rawClaims/parts logic and ensure the conditional around
token.UserID/token.AccountID remains intact.

---

Nitpick comments:
In `@pkg/proxy/handlers/spacelister.go`:
- Around line 77-82: The errorResponse function currently writes directly to
ctx.Response().Writer which bypasses Echo's response bookkeeping; change
errorResponse(ctx echo.Context, err *apierrors.StatusError) to use Echo's
ctx.JSON(int(err.ErrStatus.Code), err.ErrStatus) (after logging via
ctx.Logger().Error) so the status, headers and committed flag are set correctly
and after-response hooks and promhttp_middleware.responseStatus observe the
right status; remove direct Writer.Header/WriteHeader/Encode usage and return
the ctx.JSON call result.

In `@pkg/signup/service/signup_service.go`:
- Around line 385-530: DoGetSignup is doing too many responsibilities
(polling/auditing, state classification, MUR lookup, ToolchainStatus lookup, and
response shaping); refactor by extracting clear helper functions and wiring them
from DoGetSignup: implement fetchAndAuditUserSignup(ctx, cl, username) to
encapsulate the PollUpdateSignup block and return the UserSignup, implement
classifySignupState(userSignup, checkUserSignupCompleted) to encapsulate the
approval/complete/deactivated/banned checks and return an early Status/decision,
implement fetchMURAndReady(ctx, cl, compliantUsername) to retrieve the
MasterUserRecord and its ready condition, and implement
enrichResponseWithClusterInfo(ctx, cl, userSignup, mur, signupResponse) to fetch
ToolchainStatus, set URLs, Start/End dates and default namespace; then simplify
DoGetSignup to call these helpers in sequence and return the shaped
signupResponse or early nil/ForbiddenBannedError as appropriate. Ensure you
preserve existing behavior and logging and update unit tests to cover the new
helpers.

In `@pkg/verification/service/verification_service_test.go`:
- Around line 907-989: Tests call verificationservice.PhoneNumberAlreadyInUse
with a nil echo.Context which relies on internal nil-tolerance; replace those
nil args with a real test context by passing newEchoTestContext() wherever
PhoneNumberAlreadyInUse(nil, nsdClient, ...) is used (all six call sites) so the
calls become PhoneNumberAlreadyInUse(newEchoTestContext(), nsdClient, ...);
search for PhoneNumberAlreadyInUse invocations in this file and update each nil
context to newEchoTestContext() to match the rest of the suite.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 92ed7629-ed06-4136-990b-b641a717799b

📥 Commits

Reviewing files that changed from the base of the PR and between 37209f8 and c675e07.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (49)
  • go.mod
  • pkg/application/service/services.go
  • pkg/assets/assets.go
  • pkg/context/keys.go
  • pkg/controller/analytics.go
  • pkg/controller/analytics_test.go
  • pkg/controller/authconfig.go
  • pkg/controller/authconfig_test.go
  • pkg/controller/health_check.go
  • pkg/controller/health_check_test.go
  • pkg/controller/namespaces.go
  • pkg/controller/namespaces_test.go
  • pkg/controller/signup.go
  • pkg/controller/signup_test.go
  • pkg/controller/uiconfig.go
  • pkg/controller/uiconfig_test.go
  • pkg/controller/usernames.go
  • pkg/controller/usernames_test.go
  • pkg/errors/error.go
  • pkg/errors/error_test.go
  • pkg/log/log.go
  • pkg/log/log_test.go
  • pkg/middleware/jwt_middleware.go
  • pkg/middleware/promhttp_middleware.go
  • pkg/namespaces/namespaces_manager.go
  • pkg/namespaces/namespaces_manager_test.go
  • pkg/proxy/handlers/spacelister.go
  • pkg/proxy/handlers/spacelister_get_test.go
  • pkg/proxy/handlers/spacelister_list_test.go
  • pkg/proxy/proxy.go
  • pkg/proxy/proxy_test.go
  • pkg/server/metrics_server.go
  • pkg/server/routes.go
  • pkg/server/routes_test.go
  • pkg/server/server.go
  • pkg/server/server_test.go
  • pkg/signup/service/signup_service.go
  • pkg/signup/service/signup_service_test.go
  • pkg/signup/signup.go
  • pkg/signup/socialevent.go
  • pkg/signup/socialevent_test.go
  • pkg/verification/captcha/captcha.go
  • pkg/verification/sender/amazon_sns_sender.go
  • pkg/verification/sender/sender.go
  • pkg/verification/sender/twilio_sender.go
  • pkg/verification/sender/twilio_sender_test.go
  • pkg/verification/service/verification_service.go
  • pkg/verification/service/verification_service_test.go
  • test/fake/proxy.go
💤 Files with no reviewable changes (1)
  • go.mod
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test
  • GitHub Check: GolangCI Lint
  • GitHub Check: Build & push operator bundles & dashboard image for e2e tests
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • pkg/context/keys.go
  • pkg/application/service/services.go
  • pkg/proxy/handlers/spacelister_list_test.go
  • pkg/proxy/handlers/spacelister_get_test.go
  • pkg/errors/error_test.go
  • pkg/log/log_test.go
  • pkg/server/routes.go
  • pkg/signup/socialevent_test.go
  • pkg/middleware/jwt_middleware.go
  • pkg/server/server_test.go
  • pkg/verification/sender/amazon_sns_sender.go
  • pkg/signup/signup.go
  • pkg/controller/usernames_test.go
  • pkg/controller/authconfig_test.go
  • pkg/verification/sender/sender.go
  • pkg/server/routes_test.go
  • pkg/verification/sender/twilio_sender.go
  • pkg/controller/namespaces_test.go
  • test/fake/proxy.go
  • pkg/namespaces/namespaces_manager.go
  • pkg/signup/service/signup_service_test.go
  • pkg/controller/health_check_test.go
  • pkg/controller/namespaces.go
  • pkg/controller/analytics_test.go
  • pkg/proxy/proxy_test.go
  • pkg/middleware/promhttp_middleware.go
  • pkg/proxy/handlers/spacelister.go
  • pkg/verification/captcha/captcha.go
  • pkg/verification/sender/twilio_sender_test.go
  • pkg/controller/analytics.go
  • pkg/assets/assets.go
  • pkg/controller/uiconfig_test.go
  • pkg/server/server.go
  • pkg/server/metrics_server.go
  • pkg/controller/uiconfig.go
  • pkg/controller/authconfig.go
  • pkg/verification/service/verification_service_test.go
  • pkg/controller/usernames.go
  • pkg/namespaces/namespaces_manager_test.go
  • pkg/errors/error.go
  • pkg/controller/signup.go
  • pkg/controller/signup_test.go
  • pkg/signup/service/signup_service.go
  • pkg/proxy/proxy.go
  • pkg/controller/health_check.go
  • pkg/signup/socialevent.go
  • pkg/verification/service/verification_service.go
  • pkg/log/log.go
🪛 GitHub Check: SonarCloud Code Analysis
pkg/context/keys.go

[warning] 10-10: Complete the task associated to this TODO comment.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ36QgpiJq2l4d7xX26U&open=AZ36QgpiJq2l4d7xX26U&pullRequest=593

pkg/controller/signup_test.go

[warning] 567-567: This function has 8 parameters, which is greater than the 7 authorized.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ34TFGGAacx7-Vpg6Q0&open=AZ34TFGGAacx7-Vpg6Q0&pullRequest=593

pkg/signup/service/signup_service.go

[failure] 385-385: Refactor this method to reduce its Cognitive Complexity from 33 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ34TFMcAacx7-Vpg6Q1&open=AZ34TFMcAacx7-Vpg6Q1&pullRequest=593

pkg/verification/service/verification_service.go

[failure] 65-65: Refactor this method to reduce its Cognitive Complexity from 31 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ36QglwJq2l4d7xX26R&open=AZ36QglwJq2l4d7xX26R&pullRequest=593


[failure] 221-221: Refactor this method to reduce its Cognitive Complexity from 42 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ36QglwJq2l4d7xX26S&open=AZ36QglwJq2l4d7xX26S&pullRequest=593


[failure] 385-385: Refactor this method to reduce its Cognitive Complexity from 16 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=codeready-toolchain_registration-service&issues=AZ36QglwJq2l4d7xX26T&open=AZ36QglwJq2l4d7xX26T&pullRequest=593

🔇 Additional comments (24)
pkg/signup/socialevent.go (1)

20-23: Echo context migration in social event lookup is consistent and correct.

The updated signature and request-context usage preserve behavior while aligning with the new framework direction.

pkg/signup/socialevent_test.go (1)

24-27: Test context setup is correctly migrated to Echo.

The new context creation path is compatible with GetAndValidateSocialEvent(ctx echo.Context, ...) and keeps the test intent unchanged.

pkg/verification/captcha/captcha.go (1)

9-60: LGTM — clean Echo migration.

The four changed lines are a correct mechanical substitution:

  • The echo.Context import and updated Assessor interface/Helper signature are consistent with the rest of the codebase migration and the test mock (context snippet 2).
  • Passing ctx.Request().Context() to client.CreateAssessment (line 60) is actually an improvement over the previous behaviour — it propagates request cancellation/deadline to the gRPC call.
  • The caller in signup_service.go (context snippet 1, line 208) already guards ctx.Request() == nil before invoking CompleteAssessment, so no nil-deref risk is introduced at line 60.
pkg/proxy/proxy_test.go (1)

29-29: LGTM — clean Echo signature update for the test scaffolding.

The OverrideGetSignupFunc callback type and override implementation are consistently migrated to echo.Context, matching handlers.SpaceLister.GetSignupFunc and the rest of the migration.

Also applies to: 518-518, 683-683

pkg/assets/assets.go (1)

11-13: LGTM — replacing gin-contrib/static with fs.Sub is a sound simplification.

Returning a plain fs.FS rooted at static/ is exactly what Echo's StaticFS/MustSubFS consumes, and dropping the Gin-specific wrapper removes a dependency without behavior change.

pkg/controller/authconfig.go (1)

31-39: LGTM — idiomatic Echo handler.

Returning ctx.JSON(...) and propagating its error matches Echo conventions; payload construction is unchanged.

pkg/controller/authconfig_test.go (1)

48-57: LGTM — Echo-based test wiring is correct.

Using echo.New().NewContext(req, rr) and require.Contains on the Content-Type accommodates Echo's application/json; charset=UTF-8 while still validating the media type.

pkg/controller/analytics.go (1)

21-32: LGTM — straightforward Echo migration for both write-key endpoints.

Behavior and status codes are preserved; ctx.String is the right choice for the plain-text payload.

pkg/controller/analytics_test.go (1)

44-54: LGTM — tests correctly assert the new error-returning Echo handlers.

require.NoError(err) before status/body assertions matches the updated controller signatures and prevents masking handler failures.

Also applies to: 77-87

pkg/controller/health_check.go (1)

37-63: LGTM — interface and implementations are migrated consistently.

HealthChecker.Alive / APIProxyAlive now take echo.Context, and getHealthInfo / GetHandler propagate it correctly. Status mapping (200 vs 503) and the proxy probe logic are preserved.

Also applies to: 73-90

pkg/context/keys.go (1)

12-29: LGTM — nil-safe Echo context helpers.

RequestContext correctly guards against a nil Echo context and a nil underlying http.Request (useful in tests), and GetString returns "" on missing/non-string values via a single type-asserted ctx.Get. Good fit as the canonical accessors for the rest of the Echo migration.

pkg/proxy/handlers/spacelister_list_test.go (1)

124-124: LGTM — signatures consistently aligned with the Echo-based GetSignupFunc.

Also applies to: 183-183

pkg/proxy/handlers/spacelister_get_test.go (1)

78-78: LGTM — Echo context setup and updated overrideSignupFunc signatures look consistent.

Also applies to: 272-272, 622-622, 675-675

pkg/verification/sender/sender.go (1)

8-13: LGTM — interface migration to echo.Context matches both Twilio and SNS implementations.

pkg/verification/sender/twilio_sender_test.go (1)

88-91: LGTM — Echo context construction is correct for both subtests.

Also applies to: 105-108

pkg/verification/sender/amazon_sns_sender.go (1)

9-9: LGTM — signature migration is clean; using _ for the unused context is appropriate.

Also applies to: 30-30

pkg/verification/sender/twilio_sender.go (1)

10-10: LGTM — Echo context is correctly threaded through to log.Error.

Also applies to: 47-47

pkg/middleware/promhttp_middleware.go (1)

16-69: LGTM — Echo migration with responseStatus helper and c.Path() cleanly addresses prior cardinality and error-status concerns.

The centralized responseStatus keeps both counter and histogram middlewares consistent, and falling back through crterrors.StatusCode(err) correctly handles the case where Echo's error handler hasn't yet committed the response.

pkg/server/metrics_server.go (1)

19-45: LGTM!

The migration to Echo is correctly implemented: *echo.Echo satisfies http.Handler via ServeHTTP, HideBanner/HidePort are appropriate for an embedded metrics server, and echo.WrapHandler is the idiomatic way to bridge promhttp.InstrumentMetricHandler into Echo's routing.

pkg/controller/health_check_test.go (1)

47-225: LGTM!

Test migration is straightforward: echo.New().NewContext(req, rr) correctly wires the recorder, the handler now returns an error checked via require.NoError, and the mock health checker accepts echo.Context consistently with the updated HealthChecker interface.

pkg/controller/usernames_test.go (1)

51-120: LGTM!

Echo path parameters via SetParamNames/SetParamValues and direct GetHandler(ctx) invocation match the new controller signature. The error subtest (lines 119–123) correctly relies on test.AssertError inspecting the response recorder, since the handler writes the error response into rr and returns nil.

pkg/verification/service/verification_service.go (1)

65-481: LGTM!

The Echo migration consistently propagates the request-scoped context via context.RequestContext(ctx) into all Get/Update/List calls, including inside the doUpdate retry closures. The new PhoneNumberAlreadyInUse(ctx echo.Context, ...) signature derives reqCtx once and reuses it for both List calls, which is clean.

Note: SonarCloud's cognitive-complexity flags on InitVerification and VerifyPhoneCode are pre-existing and unrelated to this refactor; addressing them is out of scope for this PR.

pkg/application/service/services.go (1)

6-18: LGTM!

Interface signatures cleanly migrated to echo.Context; no behavioral changes here.

pkg/controller/namespaces.go (1)

35-51: ⚡ Quick win

crterrors.AbortWithError correctly writes the response and returns nil, preventing any conflict with Echo's error handler.

The implementation uses ctx.JSON(code, ...) which writes the JSON response with the specified status code and implicitly returns nil. This means the response body is written before control returns to the Echo framework, and no error is propagated to Echo's error handler—the pattern is sound.

@openshift-ci

openshift-ci Bot commented May 20, 2026

Copy link
Copy Markdown

PR needs rebase.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants