feat(setup): show running build version in the Setup tab bar
CI already computes <branch>-<short-sha> for image tags but never surfaced it anywhere reachable from the app, so there was no way to tell what's actually deployed on a booth without cross-referencing komodo/resources.toml's TAG by hand. Thread it through: CI passes BUILD_VERSION as a Docker build-arg, the Dockerfile captures it as a runtime env var, GET /api/version (gated by the existing site:read permission) exposes it, and the Setup page's tab bar shows it right-aligned, muted, absent entirely on a local/dev build with no CI-supplied value. Claude-Session: https://claude.ai/code/session_01FWncR69HgGPuei1dLrW3cU
This commit is contained in:
@@ -56,6 +56,37 @@ describe("auth guard — no token", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("GET /api/version", () => {
|
||||
it("without a session is 401", async () => {
|
||||
const res = await app.inject({ method: "GET", url: "/api/version" });
|
||||
expect(res.statusCode).toBe(401);
|
||||
});
|
||||
|
||||
it("a site:read user gets the BUILD_VERSION env var, null when unset", async () => {
|
||||
const { username, password } = await seedUser(db, {
|
||||
username: "viewer2", roleId: "viewer2", permissions: ["site:read"],
|
||||
});
|
||||
const { cookie } = await login(app, username, password);
|
||||
const res = await app.inject({ method: "GET", url: "/api/version", headers: { cookie } });
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.json()).toEqual({ buildVersion: null }); // no BUILD_VERSION set in the test env
|
||||
});
|
||||
|
||||
it("reflects a real BUILD_VERSION when the env var is set", async () => {
|
||||
process.env.BUILD_VERSION = "stage-abc1234";
|
||||
try {
|
||||
const { username, password } = await seedUser(db, {
|
||||
username: "viewer3", roleId: "viewer3", permissions: ["site:read"],
|
||||
});
|
||||
const { cookie } = await login(app, username, password);
|
||||
const res = await app.inject({ method: "GET", url: "/api/version", headers: { cookie } });
|
||||
expect(res.json()).toEqual({ buildVersion: "stage-abc1234" });
|
||||
} finally {
|
||||
delete process.env.BUILD_VERSION;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("RBAC permission gate", () => {
|
||||
it("a site:read-only user can GET occupancy but is 403 on PUT site-config", async () => {
|
||||
const { username, password } = await seedUser(db, {
|
||||
|
||||
@@ -78,6 +78,15 @@ export async function siteRoutes(app: FastifyInstance, db: Db, eventLog?: EventL
|
||||
// Live occupancy: cars inside, capacity, free, full. Any signed-in role.
|
||||
app.get("/api/occupancy", { preHandler: readGuard }, async () => getOccupancy(db));
|
||||
|
||||
// Running build version ("<branch>-<short-sha>", matching the Komodo Stack's TAG in
|
||||
// komodo/resources.toml) — baked in at image build time (apps/server/Dockerfile
|
||||
// BUILD_VERSION ARG), read here from the running process env. null on a local/dev
|
||||
// build with no CI-supplied value. Purely informational (Setup nav display); not
|
||||
// site config, so it isn't stored in site_config.
|
||||
app.get("/api/version", { preHandler: readGuard }, async () => ({
|
||||
buildVersion: process.env.BUILD_VERSION?.trim() || null,
|
||||
}));
|
||||
|
||||
// Read site config (capacity + park metadata).
|
||||
app.get("/api/site-config", { preHandler: readGuard }, async () => {
|
||||
const row = db.select().from(siteConfig).where(eq(siteConfig.id, 1)).get();
|
||||
|
||||
Reference in New Issue
Block a user