Fix production health build identification
CI / verify (push) Has been cancelled
CI / publish (push) Has been cancelled

Mount the versioned health route instead of the legacy shadowing handler so deployments can verify the exact running image.
This commit is contained in:
Rocky
2026-08-21 23:15:59 +08:00
parent 0d236f57fb
commit f8fa93dc48
2 changed files with 22 additions and 23 deletions
@@ -108,6 +108,7 @@ import com.osglab.account.features.gateway.services.GatewayBearerIdentity
import com.osglab.account.features.gateway.services.GatewayGrantService
import com.osglab.account.features.gateway.services.GatewayReconciliationService
import com.osglab.account.features.gateway.services.GatewayService
import com.osglab.account.features.health.healthRoutes
import com.osglab.account.features.integrity.AppAttestCrypto
import com.osglab.account.features.integrity.AppAttestRepository
import com.osglab.account.features.integrity.AppAttestService
@@ -152,8 +153,6 @@ import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation as ClientContentNegotiation
import io.ktor.client.plugins.HttpTimeout
import io.ktor.client.plugins.websocket.WebSockets as ClientWebSockets
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.Application
import io.ktor.server.application.ApplicationStopped
@@ -169,9 +168,6 @@ import io.ktor.server.plugins.ratelimit.RateLimitName
import io.ktor.server.plugins.ratelimit.rateLimit
import io.ktor.server.request.httpMethod
import io.ktor.server.response.respond
import io.ktor.server.response.respondText
import io.ktor.server.routing.get
import io.ktor.server.routing.Route
import io.ktor.server.routing.routing
import io.ktor.server.websocket.WebSockets
import kotlinx.serialization.json.Json
@@ -379,22 +375,6 @@ fun Application.module() {
}
}
fun Route.healthRoutes(databaseFactory: DatabaseFactory? = null) {
get("/health") { call.respondText("""{"status":"UP"}""", ContentType.Application.Json) }
get("/health/live") { call.respondText("""{"status":"UP"}""", ContentType.Application.Json) }
get("/health/ready") {
if (databaseFactory?.isReady() == true) {
call.respondText("""{"status":"UP"}""", ContentType.Application.Json)
} else {
call.respondText(
"""{"status":"DOWN"}""",
ContentType.Application.Json,
HttpStatusCode.ServiceUnavailable,
)
}
}
}
fun accountServerModule(config: AppConfig): Module = module {
single { config }
single { DatabaseFactory(config.database) }
@@ -1,16 +1,23 @@
package com.osglab.account
import com.osglab.account.config.AppConfig
import com.osglab.account.config.DatabaseFactory
import com.osglab.account.features.credits.repositories.BillingTransactionRunner
import com.osglab.account.features.credits.repositories.BillingUnitOfWork
import com.osglab.account.features.credits.services.CreditOperations
import com.osglab.account.features.credits.services.CreditService
import com.osglab.account.features.health.healthRoutes
import com.osglab.account.features.referrals.services.ReferralOperations
import com.osglab.account.features.referrals.services.ReferralService
import io.mockk.mockk
import io.kotest.matchers.shouldBe
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpStatusCode
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.install
import io.ktor.server.config.MapApplicationConfig
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.routing.routing
import io.ktor.server.testing.testApplication
import org.koin.dsl.koinApplication
@@ -21,11 +28,23 @@ import kotlin.test.Test
class ApplicationTest {
@Test
fun `liveness endpoint remains independent of external services`() = testApplication {
val buildSha = "a".repeat(40)
application {
routing { healthRoutes() }
install(ContentNegotiation) {
json()
}
routing {
healthRoutes(
databaseFactory = mockk<DatabaseFactory>(relaxed = true),
buildSha = buildSha,
)
}
}
client.get("/health/live").status shouldBe HttpStatusCode.OK
client.get("/health/live").apply {
status shouldBe HttpStatusCode.OK
bodyAsText() shouldBe """{"status":"UP","buildSha":"$buildSha"}"""
}
}
@Test