Public Access
feat(version): answer the build commit and time
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:
1 parent
4ec47f1b2c
commit
a1763addce
9 files changed
+76
No files matched your search
@@ -52,6 +52,7 @@ jobs:
|
||||
BRANCH="$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]')"
|
||||
echo "branch=$BRANCH" >> "$GITHUB_OUTPUT"
|
||||
echo "sha=${GITHUB_SHA::12}" >> "$GITHUB_OUTPUT"
|
||||
echo "build_time=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
@@ -69,6 +70,9 @@ jobs:
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
build-args: |
|
||||
GIT_SHA=${{ github.sha }}
|
||||
BUILD_TIME=${{ steps.prep.outputs.build_time }}
|
||||
tags: |
|
||||
git.andreas-dahm.eu/lobo_corp/tbp-auth-service:${{ steps.prep.outputs.branch }}
|
||||
git.andreas-dahm.eu/lobo_corp/tbp-auth-service:${{ steps.prep.outputs.branch }}-${{ steps.prep.outputs.sha }}
|
||||
|
||||
@@ -25,6 +25,11 @@ FROM eclipse-temurin:25-jre-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Passed by the CI workflow; shown by GET /api/version
|
||||
ARG GIT_SHA=dev
|
||||
ARG BUILD_TIME=
|
||||
ENV APP_BUILD_COMMIT=$GIT_SHA APP_BUILD_TIME=$BUILD_TIME
|
||||
|
||||
# Expose the port your Spring Boot app runs on
|
||||
EXPOSE 8080
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ To Be Played is split into three repositories:
|
||||
| `PUT` | `/api/users/settings/profile-stats` (`{groups}`: `PILE`, `TOP_GAMES`, `TASTE`, `HABITS`, `FINISHED`, `TREND`; `204`) | access token |
|
||||
| `GET` | `/api/public/profiles/{displayName}` | public |
|
||||
| `GET` | `/api/stats/public` | public |
|
||||
| `GET` | `/api/version` (`{commit, builtAt}` of the running image, from the CI build; `dev` locally) | public |
|
||||
|
||||
Endpoints use Spring's API versioning with a query parameter: `?version=1.0` (default `1.0`).
|
||||
|
||||
@@ -80,6 +81,7 @@ layers:
|
||||
| Persistence | `persistence` | JPA entities, Spring Data repositories, `EntityMapper`. Entities never reach the API layer. |
|
||||
|
||||
`profile` and `stats` only read data. They have no entities and use `JdbcTemplate` queries in a `repo` package.
|
||||
`version` has only an `api` package: `GET /api/version` answers the commit and build time of the running image.
|
||||
|
||||
ArchUnit enforces these rules in `src/test/java/auth_service/architecture/ArchitectureTest.java`, so a layer
|
||||
violation fails the build. It also keeps the modules independent of each other and free of cycles. Test base
|
||||
|
||||
@@ -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) {}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user