From 3eab81fdea8f8a4d2e4a5c4301a9d76a59a13587 Mon Sep 17 00:00:00 2001
From: Ada <ada@gnous.eu>
Date: Fri, 5 Apr 2024 18:20:04 +0200
Subject: [PATCH 1/4] Fix #3030 add Cache-Control header for health-check

(cherry picked from commit b210a3ebd59ffd59a82bbddcf9b9cee3fee43598)
---
 routers/web/healthcheck/check.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/routers/web/healthcheck/check.go b/routers/web/healthcheck/check.go
index d278ee1709..6be3be86d8 100644
--- a/routers/web/healthcheck/check.go
+++ b/routers/web/healthcheck/check.go
@@ -85,6 +85,7 @@ func Check(w http.ResponseWriter, r *http.Request) {
 
 	data, _ := json.MarshalIndent(rsp, "", "  ")
 	w.Header().Set("Content-Type", "application/json")
+	w.Header().Set("Cache-Control", "no-store, no-cache, max-age=0, must-revalidate, proxy-revalidate")
 	w.WriteHeader(rsp.Status.ToHTTPStatus())
 	_, _ = w.Write(data)
 }

From 12c28641abec976167c111d1cd3700c325dbb93a Mon Sep 17 00:00:00 2001
From: Ada <ada@gnous.eu>
Date: Fri, 5 Apr 2024 22:08:22 +0200
Subject: [PATCH 2/4] Remove old proxy backwards compatibility

(cherry picked from commit d2ff8f8720a5d3cc65b8d94c1458a8b4c569bb4c)
---
 routers/web/healthcheck/check.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/routers/web/healthcheck/check.go b/routers/web/healthcheck/check.go
index 6be3be86d8..b21971c9e2 100644
--- a/routers/web/healthcheck/check.go
+++ b/routers/web/healthcheck/check.go
@@ -85,7 +85,7 @@ func Check(w http.ResponseWriter, r *http.Request) {
 
 	data, _ := json.MarshalIndent(rsp, "", "  ")
 	w.Header().Set("Content-Type", "application/json")
-	w.Header().Set("Cache-Control", "no-store, no-cache, max-age=0, must-revalidate, proxy-revalidate")
+	w.Header().Set("Cache-Control", "no-store")
 	w.WriteHeader(rsp.Status.ToHTTPStatus())
 	_, _ = w.Write(data)
 }

From 8ddfd26d97058bcf9431ca93047d297d87e3fd25 Mon Sep 17 00:00:00 2001
From: Ada <ada@gnous.eu>
Date: Sat, 6 Apr 2024 00:25:30 +0200
Subject: [PATCH 3/4] Add health-check test

(cherry picked from commit 84f5115bd1b8ed32b0160bf53acb47bbe54b75f0)
---
 routers/web/healthcheck/check.go     | 42 ++++++++++++++--------------
 tests/integration/api_health_test.go | 28 +++++++++++++++++++
 2 files changed, 49 insertions(+), 21 deletions(-)
 create mode 100644 tests/integration/api_health_test.go

diff --git a/routers/web/healthcheck/check.go b/routers/web/healthcheck/check.go
index b21971c9e2..83dfe62537 100644
--- a/routers/web/healthcheck/check.go
+++ b/routers/web/healthcheck/check.go
@@ -19,7 +19,7 @@ import (
 type status string
 
 const (
-	// pass healthy (acceptable aliases: "ok" to support Node's Terminus and "up" for Java's SpringBoot)
+	// Pass healthy (acceptable aliases: "ok" to support Node's Terminus and "up" for Java's SpringBoot)
 	// fail unhealthy (acceptable aliases: "error" to support Node's Terminus and "down" for Java's SpringBoot), and
 	// warn healthy, with some concerns.
 	//
@@ -27,19 +27,19 @@ const (
 	// status: (required) indicates whether the service status is acceptable
 	// or not.  API publishers SHOULD use following values for the field:
 	// The value of the status field is case-insensitive and is tightly
-	// related with the HTTP response code returned by the health endpoint.
-	// For "pass" status, HTTP response code in the 2xx-3xx range MUST be
-	// used.  For "fail" status, HTTP response code in the 4xx-5xx range
+	// related with the HTTP Response code returned by the health endpoint.
+	// For "pass" status, HTTP Response code in the 2xx-3xx range MUST be
+	// used.  For "fail" status, HTTP Response code in the 4xx-5xx range
 	// MUST be used.  In case of the "warn" status, endpoints MUST return
 	// HTTP status in the 2xx-3xx range, and additional information SHOULD
-	// be provided, utilizing optional fields of the response.
-	pass status = "pass"
-	fail status = "fail"
+	// be provided, utilizing optional fields of the Response.
+	Pass status = "pass"
+	Fail status = "fail"
 	warn status = "warn"
 )
 
 func (s status) ToHTTPStatus() int {
-	if s == pass || s == warn {
+	if s == Pass || s == warn {
 		return http.StatusOK
 	}
 	return http.StatusFailedDependency
@@ -47,8 +47,8 @@ func (s status) ToHTTPStatus() int {
 
 type checks map[string][]componentStatus
 
-// response is the data returned by the health endpoint, which will be marshaled to JSON format
-type response struct {
+// Response is the data returned by the health endpoint, which will be marshaled to JSON format
+type Response struct {
 	Status      status `json:"status"`
 	Description string `json:"description"`      // a human-friendly description of the service
 	Checks      checks `json:"checks,omitempty"` // The Checks Object, should be omitted on installation route
@@ -65,8 +65,8 @@ type componentStatus struct {
 
 // Check is the health check API handler
 func Check(w http.ResponseWriter, r *http.Request) {
-	rsp := response{
-		Status:      pass,
+	rsp := Response{
+		Status:      Pass,
 		Description: setting.AppName,
 		Checks:      make(checks),
 	}
@@ -77,8 +77,8 @@ func Check(w http.ResponseWriter, r *http.Request) {
 		statuses = append(statuses, checkCache(rsp.Checks))
 	}
 	for _, s := range statuses {
-		if s != pass {
-			rsp.Status = fail
+		if s != Pass {
+			rsp.Status = Fail
 			break
 		}
 	}
@@ -94,22 +94,22 @@ func Check(w http.ResponseWriter, r *http.Request) {
 func checkDatabase(ctx context.Context, checks checks) status {
 	st := componentStatus{}
 	if err := db.GetEngine(ctx).Ping(); err != nil {
-		st.Status = fail
+		st.Status = Fail
 		st.Time = getCheckTime()
 		log.Error("database ping failed with error: %v", err)
 	} else {
-		st.Status = pass
+		st.Status = Pass
 		st.Time = getCheckTime()
 	}
 
-	if setting.Database.Type.IsSQLite3() && st.Status == pass {
+	if setting.Database.Type.IsSQLite3() && st.Status == Pass {
 		if !setting.EnableSQLite3 {
-			st.Status = fail
+			st.Status = Fail
 			st.Time = getCheckTime()
 			log.Error("SQLite3 health check failed with error: %v", "this Forgejo binary is built without SQLite3 enabled")
 		} else {
 			if _, err := os.Stat(setting.Database.Path); err != nil {
-				st.Status = fail
+				st.Status = Fail
 				st.Time = getCheckTime()
 				log.Error("SQLite3 file exists check failed with error: %v", err)
 			}
@@ -124,11 +124,11 @@ func checkDatabase(ctx context.Context, checks checks) status {
 func checkCache(checks checks) status {
 	st := componentStatus{}
 	if err := cache.GetCache().Ping(); err != nil {
-		st.Status = fail
+		st.Status = Fail
 		st.Time = getCheckTime()
 		log.Error("cache ping failed with error: %v", err)
 	} else {
-		st.Status = pass
+		st.Status = Pass
 		st.Time = getCheckTime()
 	}
 	checks["cache:ping"] = []componentStatus{st}
diff --git a/tests/integration/api_health_test.go b/tests/integration/api_health_test.go
new file mode 100644
index 0000000000..d351fcd26c
--- /dev/null
+++ b/tests/integration/api_health_test.go
@@ -0,0 +1,28 @@
+package integration
+
+import (
+	"net/http"
+	"testing"
+
+	"code.gitea.io/gitea/modules/setting"
+	"code.gitea.io/gitea/routers/web/healthcheck"
+	"code.gitea.io/gitea/tests"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestApiHeatlhCheck(t *testing.T) {
+	defer tests.PrepareTestEnv(t)()
+	t.Run("Test health-check pass", func(t *testing.T) {
+		defer tests.PrintCurrentTest(t)()
+
+		req := NewRequest(t, "GET", "/api/healthz")
+		resp := MakeRequest(t, req, http.StatusOK)
+		assert.Contains(t, resp.Header().Values("Cache-Control"), "no-store")
+
+		var status healthcheck.Response
+		DecodeJSON(t, resp, &status)
+		assert.Equal(t, healthcheck.Pass, status.Status)
+		assert.Equal(t, setting.AppName, status.Description)
+	})
+}

From 7aa0999c9fe8ba31ab90c0903308a53e02cb35a9 Mon Sep 17 00:00:00 2001
From: Ada <ada@gnous.eu>
Date: Sat, 6 Apr 2024 00:43:22 +0200
Subject: [PATCH 4/4] Remove useless t.run

(cherry picked from commit 323d7ad50719e69b5969d059415ba027075232c9)
---
 tests/integration/api_health_test.go | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/tests/integration/api_health_test.go b/tests/integration/api_health_test.go
index d351fcd26c..5657f4fd06 100644
--- a/tests/integration/api_health_test.go
+++ b/tests/integration/api_health_test.go
@@ -13,16 +13,13 @@ import (
 
 func TestApiHeatlhCheck(t *testing.T) {
 	defer tests.PrepareTestEnv(t)()
-	t.Run("Test health-check pass", func(t *testing.T) {
-		defer tests.PrintCurrentTest(t)()
 
-		req := NewRequest(t, "GET", "/api/healthz")
-		resp := MakeRequest(t, req, http.StatusOK)
-		assert.Contains(t, resp.Header().Values("Cache-Control"), "no-store")
+	req := NewRequest(t, "GET", "/api/healthz")
+	resp := MakeRequest(t, req, http.StatusOK)
+	assert.Contains(t, resp.Header().Values("Cache-Control"), "no-store")
 
-		var status healthcheck.Response
-		DecodeJSON(t, resp, &status)
-		assert.Equal(t, healthcheck.Pass, status.Status)
-		assert.Equal(t, setting.AppName, status.Description)
-	})
+	var status healthcheck.Response
+	DecodeJSON(t, resp, &status)
+	assert.Equal(t, healthcheck.Pass, status.Status)
+	assert.Equal(t, setting.AppName, status.Description)
 }