feat(version): answer the build commit and time
Build, Test & Push Auth Service / quality-check (push) Successful in 31s
Build, Test & Push Auth Service / docker (push) Successful in 1m21s

GET /api/version is public. CI passes GIT_SHA and BUILD_TIME as Docker build args; a local build answers dev.
This commit is contained in:
lobo committed 2026-09-27 10:27:01 +02:00
1 parent 4ec47f1b2c
commit a1763addce
9 files changed
+76

No files matched your search

@@ -44,6 +44,7 @@ public class SecurityConfig {
"/api/steam-link/callback", // Steam's redirect back; bound to the browser by a cookie, see SteamLinkService
"/actuator/health", // Docker health check; details are off
"/.well-known/jwks.json", // Public verify keys for Core
"/api/version", // Build of the running image, shown in the settings
"/error" // Default Spring Boot error page routing
};
@@ -0,0 +1,22 @@
package auth_service.modules.version.api;
import auth_service.modules.version.api.dto.VersionDto;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class VersionController {
private final VersionDto version;
public VersionController(@Value("${app.build.commit}") String commit, @Value("${app.build.time}") String builtAt) {
this.version = new VersionDto(commit.isBlank() ? "dev" : commit, builtAt.isBlank() ? null : builtAt);
}
@GetMapping("/api/version")
public ResponseEntity<VersionDto> getVersion() {
return ResponseEntity.ok(version);
}
}
@@ -0,0 +1,7 @@
package auth_service.modules.version.api.dto;
/**
* @param commit full git hash the image was built from, "dev" outside the CI build
* @param builtAt ISO-8601 UTC build time, null outside the CI build
*/
public record VersionDto(String commit, String builtAt) {}
+4
View File
@@ -45,6 +45,10 @@ security:
# Custom properties for CORS
app:
build:
# Filled from the CI run by the Dockerfile.
commit: ${APP_BUILD_COMMIT:dev}
time: ${APP_BUILD_TIME:}
cors:
# Production default: strictly allow only the frontend domain
allowed-origins: "https://tbp.andreas-dahm.eu"
@@ -42,4 +42,11 @@ class PublicEndpointsTest extends AbstractIntegrationTest {
int status = mockMvc.perform(get("/actuator/prometheus")).andReturn().getResponse().getStatus();
assertTrue(Set.of(401, 403).contains(status), "/actuator/prometheus answered " + status);
}
@Test
void versionIsPublic() throws Exception {
mockMvc.perform(get("/api/version"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.commit").isString());
}
}
@@ -0,0 +1,24 @@
package auth_service.modules.version.api;
import auth_service.modules.version.api.dto.VersionDto;
import auth_service.shared.test.AbstractUnitTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class VersionControllerTest extends AbstractUnitTest {
@Test
void answersTheBuildOfTheImage() {
VersionDto version = new VersionController("4ec47f1aa0b1", "2026-09-27T08:05:00Z").getVersion().getBody();
assertEquals(new VersionDto("4ec47f1aa0b1", "2026-09-27T08:05:00Z"), version);
}
@Test
void emptyBuildArgsCountAsLocalBuild() {
VersionDto version = new VersionController("", "").getVersion().getBody();
assertEquals(new VersionDto("dev", null), version);
}
}