Skip to content

Conversation

@gocanto
Copy link
Collaborator

@gocanto gocanto commented Sep 10, 2025

Summary

  • rename ping handler to keep-alive
  • add handler that pings database connection
  • cover keep-alive handlers with tests

Testing

  • go test ./handler -run KeepAliveDB -count=1 -v
  • go test ./metal/kernel -run Ping -count=1 -v

https://chatgpt.com/codex/tasks/task_e_68c0d3ec39ac83338f20efabf010fdc9

Summary by CodeRabbit

  • New Features

    • Added a database health-check endpoint GET /ping-db protected by Basic Auth. Returns a “pong” message with a timestamp when the database is reachable.
  • Improvements

    • Keep-alive responses now include no-cache headers to prevent stale clients.
    • Startup now logs database ping failures.
    • Existing GET /ping keep-alive endpoint remains available.
  • Tests

    • Added tests for the /ping-db route (valid/invalid credentials, DB failure), keep-alive handler, and no-cache response behavior.

@coderabbitai
Copy link

coderabbitai bot commented Sep 10, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Renames Ping to KeepAlive across handlers, payloads, tests, and routing. Adds a BasicAuth-protected /ping-db route that pings the database. Introduces a no-cache HTTP response helper. Changes database Connection.Ping to return error and updates call sites. Adjusts app boot and router wiring accordingly.

Changes

Cohort / File(s) Summary
Keep-Alive handler rename
handler/keep_alive.go, handler/keep_alive_test.go, handler/payload/keep_alive.go
Renamed PingHandler→KeepAliveHandler and PingResponse→KeepAliveResponse; swapped MakeResponseFrom→MakeNoCacheResponse; updated tests accordingly.
New DB keep-alive handler + tests
handler/keep_alive_db.go, handler/keep_alive_db_test.go, metal/kernel/router_keep_alive_db_test.go
Added KeepAliveDBHandler with BasicAuth and DB ping; constructor provided; tests cover valid/invalid auth and DB failure; router route test added.
Router and app wiring
metal/kernel/router.go, metal/kernel/app.go, metal/kernel/router_keep_alive_test.go
Replaced Router.Ping with Router.KeepAlive; added Router.KeepAliveDB for GET /ping-db; updated boot sequence and route tests.
DB connection ping updates
database/connection.go, main.go
Connection.Ping now returns error; implementation calls driver.DB().Ping and returns wrapped errors; main logs ping failure on startup.
HTTP response helper
pkg/http/response.go, pkg/http/response_test.go
Added MakeNoCacheResponse setting no-store and standard headers; HasCache short-circuits on empty ETag; test validates no-cache behavior.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant Router
  participant KeepAliveHandler as KeepAliveHandler
  participant HTTP as http.Response

  Client->>Router: GET /ping
  Router->>KeepAliveHandler: Handle(w, r)
  KeepAliveHandler->>HTTP: MakeNoCacheResponse(w, r)
  KeepAliveHandler-->>Client: 200 OK {message:"pong", dateTime:"..."}

  %% Note: No auth, no DB
  note over KeepAliveHandler: Constructs payload.KeepAliveResponse
Loading
sequenceDiagram
  autonumber
  actor Client
  participant Router
  participant KeepAliveDB as KeepAliveDBHandler
  participant Env as env.Ping
  participant DB as database.Connection
  participant HTTP as http.Response

  Client->>Router: GET /ping-db (BasicAuth)
  Router->>KeepAliveDB: Handle(w, r)
  KeepAliveDB->>Env: Validate creds
  alt Invalid or missing creds
    KeepAliveDB-->>Client: 401 Unauthorized
  else Valid creds
    KeepAliveDB->>DB: Ping()
    alt DB ping error
      KeepAliveDB-->>Client: 500 Internal Server Error
    else OK
      KeepAliveDB->>HTTP: MakeNoCacheResponse(w, r)
      KeepAliveDB-->>Client: 200 OK {message:"pong", dateTime:"..."}
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

codex

Pre-merge checks (2 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly captures the core changes by highlighting both the introduction of keep-alive handlers and the accompanying database ping test, which aligns directly with the PR’s objectives of renaming the existing ping handler, adding a DB health-check handler, and implementing tests.

Poem

A tap on the wire—ping, ping—alive!
I twitch my ears: two routes now thrive.
One nibbles bytes, no-cache delight,
One checks the burrow’s DB might.
Credentials snug, the status strong—
“pong,” I chirp, and bounce along. 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/rename-ping.go-to-keep_alive.go-and-add-keep_alive_db.go

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@gocanto gocanto marked this pull request as draft September 10, 2025 01:39
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @gocanto, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refactors the existing health check endpoint by renaming it to keep-alive for clearer semantics and introduces a dedicated health check endpoint for the database connection. These changes improve the application's ability to monitor its operational status and dependencies.

Highlights

  • Handler Renaming: The existing generic "ping" handler and its associated files have been renamed to "keep-alive" to better reflect its purpose as a general health check.
  • Database Keep-Alive Handler: A new handler, KeepAliveDBHandler, has been introduced to specifically perform a ping test against the database connection, enhancing the application's health monitoring capabilities.
  • New Test Coverage: Comprehensive unit tests have been added for the newly introduced KeepAliveDBHandler to ensure its correct functionality and robustness.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the ping handler to keep-alive, adds a new keep-alive handler to check database connectivity, and includes corresponding tests. The changes are generally good, but there are a few important issues. The new database keep-alive handler doesn't correctly handle database ping failures, which is a critical flaw. There's also some code duplication between the two keep-alive handlers that could be refactored. Finally, the tests for the new database handler are missing a case for when the database connection fails. My review includes suggestions to address these points.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (2)
metal/kernel/router.go (1)

83-91: Register or remove DB keep-alive handler
MakeKeepAliveDBHandler is never wired in metal/kernel/router.go (no GET /ping/db). Either expose it in Router.Ping or remove the unused handler.

handler/keep_alive.go (1)

22-45: Avoid caching authenticated keep-alive responses.

http.MakeResponseFrom sets Cache-Control: public, max-age=3600. With BasicAuth, public enables shared caches to store responses (RFC 7234). For an auth-gated health endpoint, prefer no-store.

Two approaches:

  • Add a no-cache variant in pkg/http and use it here:
// pkg/http: add a constructor that sets Cache-Control: no-store
func MakeNoCacheResponse(writer baseHttp.ResponseWriter, request *baseHttp.Request) *Response { ... }

Then:

- resp := http.MakeResponseFrom("0.0.1", w, r)
+ resp := http.MakeNoCacheResponse(w, r)
  • Or extend MakeResponseFrom with options to override cache headers for auth endpoints.
🧹 Nitpick comments (7)
handler/payload/keep_alive.go (1)

3-7: Consider clarifying time semantics.

If this is always UTC, add it to the doc comment to avoid client ambiguity.

metal/kernel/router.go (2)

83-91: Use the existing public pipeline helper for consistency.

You can simplify and ensure common public middleware by using PublicPipelineFor.

 func (r *Router) Ping() {
-	abstract := handler.MakeKeepAliveHandler(&r.Env.Ping)
-
-	apiHandler := http.MakeApiHandler(
-		r.Pipeline.Chain(abstract.Handle),
-	)
-
-	r.Mux.HandleFunc("GET /ping", apiHandler)
+	abstract := handler.MakeKeepAliveHandler(&r.Env.Ping)
+	apiHandler := r.PublicPipelineFor(abstract.Handle)
+	r.Mux.HandleFunc("GET /ping", apiHandler)
 }

83-91: Endpoint name vs. function name.

Method remains Ping() though the handler is “keep-alive.” Optional rename to KeepAlive() for clarity.

handler/keep_alive_test.go (2)

15-18: Credential length may conflict with future validation.

env.Ping has min=16 tags. Tests use short creds; if validation is later enforced, tests will break. Safer to use 16+ chars.

- e := env.Ping{Username: "user", Password: "pass"}
+ e := env.Ping{Username: "0123456789abcdef", Password: "fedcba9876543210"}

And update SetBasicAuth below accordingly.


15-49: Optional: mark as parallel.

This unit test doesn’t use shared resources; t.Parallel() can speed up the suite.

handler/keep_alive_db_test.go (1)

16-20: Use long credentials to align with struct tags.

Future validation could enforce min=16.

- e := env.Ping{Username: "user", Password: "pass"}
+ e := env.Ping{Username: "0123456789abcdef", Password: "fedcba9876543210"}

And update the SetBasicAuth calls below.

handler/keep_alive.go (1)

32-38: Version salt should come from a single source.

Hardcoding "0.0.1" risks drift. Consider a build-time var or shared const.

- resp := http.MakeResponseFrom("0.0.1", w, r)
+ resp := http.MakeResponseFrom(portal.Version, w, r) // or env/build var
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between efe6e0e and e7ea24d.

📒 Files selected for processing (7)
  • handler/keep_alive.go (2 hunks)
  • handler/keep_alive_db.go (1 hunks)
  • handler/keep_alive_db_test.go (1 hunks)
  • handler/keep_alive_test.go (2 hunks)
  • handler/payload/keep_alive.go (1 hunks)
  • handler/payload/ping.go (0 hunks)
  • metal/kernel/router.go (1 hunks)
💤 Files with no reviewable changes (1)
  • handler/payload/ping.go
🧰 Additional context used
🧬 Code graph analysis (6)
handler/keep_alive_db_test.go (4)
handler/tests/db.go (1)
  • MakeTestDB (18-88)
metal/env/ping.go (1)
  • Ping (5-8)
handler/payload/keep_alive.go (1)
  • KeepAliveResponse (4-7)
pkg/portal/consts.go (1)
  • DatesLayout (3-3)
handler/payload/keep_alive.go (1)
pkg/http/schema.go (1)
  • Message (11-15)
handler/keep_alive_db.go (6)
metal/env/ping.go (1)
  • Ping (5-8)
database/connection.go (1)
  • Connection (13-18)
pkg/http/schema.go (1)
  • ApiError (11-15)
pkg/http/response.go (3)
  • LogUnauthorisedError (101-108)
  • MakeResponseFrom (19-39)
  • LogInternalError (76-83)
handler/payload/keep_alive.go (1)
  • KeepAliveResponse (4-7)
pkg/portal/consts.go (1)
  • DatesLayout (3-3)
handler/keep_alive_test.go (3)
metal/env/ping.go (1)
  • Ping (5-8)
handler/keep_alive.go (1)
  • MakeKeepAliveHandler (18-20)
handler/payload/keep_alive.go (1)
  • KeepAliveResponse (4-7)
metal/kernel/router.go (2)
handler/keep_alive.go (1)
  • MakeKeepAliveHandler (18-20)
metal/env/ping.go (1)
  • Ping (5-8)
handler/keep_alive.go (5)
metal/env/ping.go (1)
  • Ping (5-8)
pkg/http/schema.go (1)
  • ApiError (11-15)
handler/payload/keep_alive.go (1)
  • KeepAliveResponse (4-7)
pkg/portal/consts.go (1)
  • DatesLayout (3-3)
pkg/http/response.go (1)
  • LogInternalError (76-83)
🔇 Additional comments (5)
handler/payload/keep_alive.go (1)

3-7: LGTM: Simple, clear DTO.

Structure and tags look good.

handler/keep_alive_test.go (1)

19-39: Test asserts are solid.

Covers status, payload, and datetime format. Nice.

handler/keep_alive_db_test.go (1)

43-51: Auth negative-path assertion is correct.

Unauthorized flow is properly validated.

handler/keep_alive.go (1)

22-45: Core flow looks good.

Auth check, UTC timestamp, and payload encoding are straightforward and correct.

handler/keep_alive_db.go (1)

20-22: Value vs. pointer receiver is fine here.

Small struct; returning by value is okay.

@gocanto gocanto added testing and removed codex labels Sep 10, 2025
@gocanto gocanto marked this pull request as ready for review September 10, 2025 03:20
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
handler/keep_alive.go (1)

22-30: Use constant-time comparison in HasInvalidCreds
In metal/env/ping.go, HasInvalidCreds currently does

return username != strings.TrimSpace(p.Username) ||
       password != strings.TrimSpace(p.Password)

Replace these plain != checks with crypto/subtle.ConstantTimeCompare on the trimmed stored values versus the provided inputs to eliminate timing side-channels (and add import "crypto/subtle").

♻️ Duplicate comments (1)
handler/keep_alive_db_test.go (1)

52-61: Failure-path test added — previous feedback addressed.

The 500-on-ping-failure path is now covered. Thanks for closing the gap.

🧹 Nitpick comments (12)
pkg/http/response_test.go (1)

34-59: Solid no-cache coverage; consider asserting more headers.

Looks good. For completeness, also assert Content-Type and X-Content-Type-Options set by MakeNoCacheResponse.

- if rec.Code != http.StatusOK {
+ if rec.Code != http.StatusOK {
   t.Fatalf("status %d", rec.Code)
 }
 
 if rec.Header().Get("Cache-Control") != "no-store" {
   t.Fatalf("unexpected cache-control: %s", rec.Header().Get("Cache-Control"))
 }
 
 if rec.Header().Get("ETag") != "" {
   t.Fatalf("etag should be empty")
 }
 
+if rec.Header().Get("Content-Type") != "application/json" {
+  t.Fatalf("content-type mismatch: %s", rec.Header().Get("Content-Type"))
+}
+if rec.Header().Get("X-Content-Type-Options") != "nosniff" {
+  t.Fatalf("x-content-type-options mismatch: %s", rec.Header().Get("X-Content-Type-Options"))
+}
main.go (1)

38-40: DB ping on startup: OK to log-only?

Confirm that continuing startup on ping failure is intended. If not, fail fast or expose a health endpoint for liveness/readiness.

Also, drop the “Testing” comment to avoid confusion in prod logs.

-  // --- Testing
   if err := app.GetDB().Ping(); err != nil {
     slog.Error("database ping failed", "error", err)
   }

Optionally, add a timeout in Connection.Ping() (see suggestion in database/connection.go).

metal/kernel/router_keep_alive_test.go (1)

12-39: Test credentials below validation min lengths; use longer strings to prevent future breakage.

env.Ping enforces min=16; if validation is later applied here, this could fail. Also consider asserting no-cache headers on responses.

- r := Router{
-   Env:      &env.Environment{Ping: env.Ping{Username: "user", Password: "pass"}},
+ r := Router{
+   Env:      &env.Environment{Ping: env.Ping{Username: "user-cred-should-be-16", Password: "pass-cred-should-be-16"}},

Optional header assertions:

 rec := httptest.NewRecorder()
 r.Mux.ServeHTTP(rec, req)
 if rec.Code != http.StatusOK {
   t.Fatalf("expected status %d, got %d", http.StatusOK, rec.Code)
 }
+if h := rec.Header().Get("Cache-Control"); h != "no-store" {
+  t.Fatalf("cache-control: %s", h)
+}
+if ct := rec.Header().Get("Content-Type"); ct != "application/json" {
+  t.Fatalf("content-type: %s", ct)
+}
pkg/http/response.go (1)

41-54: MakeNoCacheResponse: add legacy no-cache headers for intermediaries.

Add Pragma and Expires for broader proxy behavior; harmless alongside no-store.

 func MakeNoCacheResponse(writer baseHttp.ResponseWriter, request *baseHttp.Request) *Response {
   cacheControl := "no-store"

   return &Response{
     writer:       writer,
     request:      request,
     cacheControl: cacheControl,
     headers: func(w baseHttp.ResponseWriter) {
       w.Header().Set("Content-Type", "application/json")
       w.Header().Set("X-Content-Type-Options", "nosniff")
       w.Header().Set("Cache-Control", cacheControl)
+      w.Header().Set("Pragma", "no-cache")
+      w.Header().Set("Expires", "0")
     },
   }
 }
database/connection.go (1)

49-60: Use PingContext with timeout to avoid startup hangs.

A stuck DNS/TCP can hang Ping() indefinitely. Add a short timeout.

 func (c *Connection) Ping() error {
   conn, err := c.driver.DB()
   if err != nil {
     return fmt.Errorf("error retrieving the db driver: %w", err)
   }

-  if err := conn.Ping(); err != nil {
+  ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
+  defer cancel()
+  if err := conn.PingContext(ctx); err != nil {
     return fmt.Errorf("error pinging the db driver: %w", err)
   }

   return nil
 }

Add imports:

// at top of file
import (
  "context"
  "time"
)
metal/kernel/router_keep_alive_db_test.go (1)

13-42: Good route coverage; add a ping-failure case and align creds with validation constraints.

  • Use 16+ char creds per env.Ping tags.
  • Add subtest that closes DB before request to assert 500.
- r := Router{
-   Env:      &env.Environment{Ping: env.Ping{Username: "user", Password: "pass"}},
+ r := Router{
+   Env:      &env.Environment{Ping: env.Ping{Username: "user-cred-should-be-16", Password: "pass-cred-should-be-16"}},
    Db:       db,
    Mux:      http.NewServeMux(),
    Pipeline: middleware.Pipeline{PublicMiddleware: middleware.MakePublicMiddleware("", false)},
 }
 r.KeepAliveDB()
@@
   })
 
+ t.Run("db ping failure", func(t *testing.T) {
+   // Force failure by closing the DB before the request.
+   if ok := db.Close(); !ok {
+     t.Fatalf("failed to close db for test")
+   }
+   req := httptest.NewRequest("GET", "/ping-db", nil)
+   req.SetBasicAuth("user-cred-should-be-16", "pass-cred-should-be-16")
+   rec := httptest.NewRecorder()
+   r.Mux.ServeHTTP(rec, req)
+   if rec.Code != http.StatusInternalServerError {
+     t.Fatalf("expected status %d, got %d", http.StatusInternalServerError, rec.Code)
+   }
+ })
metal/kernel/router.go (1)

83-101: Route wiring: prefer PublicPipelineFor for consistency and middleware coverage.

Other public routes use PublicMiddleware (rate-limit, TTL, IP rules). KeepAlive endpoints should likely do the same.

 func (r *Router) KeepAlive() {
-  abstract := handler.MakeKeepAliveHandler(&r.Env.Ping)
-
-  apiHandler := http.MakeApiHandler(
-    r.Pipeline.Chain(abstract.Handle),
-  )
-
-  r.Mux.HandleFunc("GET /ping", apiHandler)
+  abstract := handler.MakeKeepAliveHandler(&r.Env.Ping)
+  r.Mux.HandleFunc("GET /ping", r.PublicPipelineFor(abstract.Handle))
 }
 
 func (r *Router) KeepAliveDB() {
-  abstract := handler.MakeKeepAliveDBHandler(&r.Env.Ping, r.Db)
-
-  apiHandler := http.MakeApiHandler(
-    r.Pipeline.Chain(abstract.Handle),
-  )
-
-  r.Mux.HandleFunc("GET /ping-db", apiHandler)
+  abstract := handler.MakeKeepAliveDBHandler(&r.Env.Ping, r.Db)
+  r.Mux.HandleFunc("GET /ping-db", r.PublicPipelineFor(abstract.Handle))
 }
handler/keep_alive_db_test.go (3)

16-20: Use 16+ char credentials to match env.Ping validation and future-proof the tests.

env.Ping enforces min=16 via tags; aligning tests reduces churn if validation is applied in construction paths.

-	e := env.Ping{Username: "user", Password: "pass"}
+	e := env.Ping{Username: "0123456789abcdef", Password: "fedcba9876543210"}

And update BasicAuth calls:

-		req.SetBasicAuth("user", "pass")
+		req.SetBasicAuth("0123456789abcdef", "fedcba9876543210")
-		req.SetBasicAuth("user", "pass")
+		req.SetBasicAuth("0123456789abcdef", "fedcba9876543210")

21-41: Assert no-cache and content-type headers on success.

KeepAlive uses MakeNoCacheResponse; validating headers catches regressions.

 		if rec.Code != http.StatusOK {
 			t.Fatalf("status %d", rec.Code)
 		}
+		if got := rec.Header().Get("Cache-Control"); got != "no-store" {
+			t.Fatalf("unexpected Cache-Control: %q", got)
+		}
+		if ct := rec.Header().Get("Content-Type"); ct != "application/json" {
+			t.Fatalf("unexpected Content-Type: %q", ct)
+		}

52-61: Isolate the failure-path by not mutating the shared DB used by other subtests.

Use a fresh connection for the failure case to avoid side effects.

-	t.Run("db ping failure", func(t *testing.T) {
-		db.Close()
-		req := httptest.NewRequest("GET", "/ping-db", nil)
-		req.SetBasicAuth("user", "pass")
-		rec := httptest.NewRecorder()
-		if err := h.Handle(rec, req); err == nil || err.Status != http.StatusInternalServerError {
-			t.Fatalf("expected internal error, got %#v", err)
-		}
-	})
+	t.Run("db ping failure", func(t *testing.T) {
+		db2, _ := handlertests.MakeTestDB(t)
+		h2 := MakeKeepAliveDBHandler(&e, db2)
+		_ = db2.Close() // simulate DB down, keep other subtests unaffected
+		req := httptest.NewRequest("GET", "/ping-db", nil)
+		req.SetBasicAuth("0123456789abcdef", "fedcba9876543210")
+		rec := httptest.NewRecorder()
+		if err := h2.Handle(rec, req); err == nil || err.Status != http.StatusInternalServerError {
+			t.Fatalf("expected internal error, got %#v", err)
+		}
+	})
handler/keep_alive.go (2)

22-30: Minor cleanup: prefer errors.New over fmt.Errorf with a constant string.

-import (
-	"fmt"
+import (
+	"errors"
 	baseHttp "net/http"
 	"time"
 )
@@
-			fmt.Errorf("invalid credentials"),
+			errors.New("invalid credentials"),

22-30: Set WWW-Authenticate header on 401 for BasicAuth clients.

Browsers and other HTTP clients require this header to trigger a credentials prompt. Add immediately before returning the unauthorized error:

 func (h KeepAliveHandler) Handle(w baseHttp.ResponseWriter, r *baseHttp.Request) *http.ApiError {
     user, pass, ok := r.BasicAuth()

     if !ok || h.env.HasInvalidCreds(user, pass) {
+        w.Header().Set("WWW-Authenticate", `Basic realm="keep-alive", charset="UTF-8"`)
         return http.LogUnauthorisedError(
             "invalid credentials",
             fmt.Errorf("invalid credentials"),
         )
     }
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e7ea24d and 56b1ecc.

📒 Files selected for processing (12)
  • database/connection.go (1 hunks)
  • handler/keep_alive.go (2 hunks)
  • handler/keep_alive_db.go (1 hunks)
  • handler/keep_alive_db_test.go (1 hunks)
  • handler/payload/keep_alive.go (1 hunks)
  • main.go (1 hunks)
  • metal/kernel/app.go (1 hunks)
  • metal/kernel/router.go (2 hunks)
  • metal/kernel/router_keep_alive_db_test.go (1 hunks)
  • metal/kernel/router_keep_alive_test.go (1 hunks)
  • pkg/http/response.go (2 hunks)
  • pkg/http/response_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • handler/payload/keep_alive.go
  • handler/keep_alive_db.go
🧰 Additional context used
🧬 Code graph analysis (9)
main.go (1)
metal/kernel/helpers.go (1)
  • a (22-28)
metal/kernel/router_keep_alive_test.go (5)
metal/kernel/router.go (1)
  • Router (25-31)
metal/env/ping.go (1)
  • Ping (5-8)
pkg/middleware/pipeline.go (1)
  • Pipeline (10-15)
pkg/middleware/public_middleware.go (2)
  • PublicMiddleware (20-29)
  • MakePublicMiddleware (31-42)
metal/kernel/router_signature_test.go (1)
  • TestSignatureRoute_PublicMiddleware (15-65)
metal/kernel/router_keep_alive_db_test.go (5)
handler/tests/db.go (1)
  • MakeTestDB (18-88)
metal/kernel/router.go (1)
  • Router (25-31)
metal/env/env.go (1)
  • Environment (9-16)
metal/env/ping.go (1)
  • Ping (5-8)
pkg/middleware/public_middleware.go (2)
  • PublicMiddleware (20-29)
  • MakePublicMiddleware (31-42)
pkg/http/response_test.go (1)
pkg/http/response.go (1)
  • MakeNoCacheResponse (41-54)
metal/kernel/router.go (5)
handler/keep_alive.go (1)
  • MakeKeepAliveHandler (18-20)
metal/env/ping.go (1)
  • Ping (5-8)
handler/keep_alive_db.go (1)
  • MakeKeepAliveDBHandler (20-22)
pkg/http/handler.go (1)
  • MakeApiHandler (9-28)
pkg/middleware/pipeline.go (1)
  • Pipeline (10-15)
handler/keep_alive_db_test.go (5)
handler/tests/db.go (1)
  • MakeTestDB (18-88)
metal/env/ping.go (1)
  • Ping (5-8)
handler/keep_alive_db.go (1)
  • MakeKeepAliveDBHandler (20-22)
handler/payload/keep_alive.go (1)
  • KeepAliveResponse (3-6)
pkg/portal/consts.go (1)
  • DatesLayout (3-3)
metal/kernel/app.go (1)
metal/kernel/kernel_test.go (1)
  • TestAppBootRoutes (138-197)
database/connection.go (2)
database/seeder/seeds/seeder_test.go (1)
  • testConnection (16-88)
database/connection_testhelpers.go (1)
  • NewConnectionFromGorm (6-8)
handler/keep_alive.go (5)
metal/env/ping.go (1)
  • Ping (5-8)
pkg/http/schema.go (1)
  • ApiError (11-15)
pkg/http/response.go (2)
  • MakeNoCacheResponse (41-54)
  • LogInternalError (95-102)
handler/payload/keep_alive.go (1)
  • KeepAliveResponse (3-6)
pkg/portal/consts.go (1)
  • DatesLayout (3-3)
🔇 Additional comments (5)
metal/kernel/app.go (1)

72-74: Boot now wires KeepAlive and KeepAliveDB—LGTM.

Matches PR intent; routes are initialized early in boot.

pkg/http/response.go (1)

71-74: HasCache short-circuit on empty ETag—LGTM.

Prevents false positives for no-cache responses.

handler/keep_alive.go (3)

14-20: Rename and constructor look good.

Type and factory rename are consistent with the PR’s intent.


32-38: LGTM: no-cache response and payload formatting.

Using MakeNoCacheResponse and portal.DatesLayout is consistent with the new policy.


40-41: LGTM: internal error message clarifies the failure point.

@gocanto gocanto merged commit 036b5d8 into main Sep 10, 2025
6 checks passed
@gocanto gocanto deleted the codex/rename-ping.go-to-keep_alive.go-and-add-keep_alive_db.go branch September 10, 2025 03:32
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.

2 participants