Skip to content

Commit 24bf739

Browse files
committed
feat(health): expose running app version metadata
1 parent e532e0a commit 24bf739

9 files changed

Lines changed: 109 additions & 6 deletions

File tree

.github/workflows/ci.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ jobs:
102102
platforms: linux/amd64
103103
push: true
104104
tags: ${{ steps.login-ecr.outputs.registry }}/${{ steps.ecr-repo.outputs.name }}:dev
105+
build-args: |
106+
APP_VERSION=dev
107+
GIT_SHA=${{ github.sha }}
105108
provenance: false
106109
sbom: false
107110

@@ -206,6 +209,9 @@ jobs:
206209
platforms: linux/amd64
207210
push: true
208211
tags: ${{ steps.meta.outputs.tags }}
212+
build-args: |
213+
APP_VERSION=${{ needs.detect-version.outputs.version || github.ref_name }}
214+
GIT_SHA=${{ github.sha }}
209215
provenance: false
210216
sbom: false
211217

@@ -266,6 +272,9 @@ jobs:
266272
platforms: linux/arm64
267273
push: true
268274
tags: ${{ steps.meta.outputs.tags }}
275+
build-args: |
276+
APP_VERSION=${{ needs.detect-version.outputs.version || github.ref_name }}
277+
GIT_SHA=${{ github.sha }}
269278
provenance: false
270279
sbom: false
271280

.github/workflows/images.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ jobs:
9797
platforms: linux/amd64
9898
push: true
9999
tags: ${{ steps.meta.outputs.tags }}
100+
build-args: |
101+
APP_VERSION=${{ github.ref_name }}
102+
GIT_SHA=${{ github.sha }}
100103
provenance: false
101104
sbom: false
102105

@@ -143,6 +146,9 @@ jobs:
143146
platforms: linux/arm64
144147
push: true
145148
tags: ${{ steps.meta.outputs.tags }}
149+
build-args: |
150+
APP_VERSION=${{ github.ref_name }}
151+
GIT_SHA=${{ github.sha }}
146152
provenance: false
147153
sbom: false
148154

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ docker compose -f docker-compose.prod.yml up -d
7474

7575
Open [http://localhost:3000](http://localhost:3000)
7676

77+
Check the running app version and build metadata:
78+
79+
```bash
80+
curl http://localhost:3000/api/health
81+
```
82+
7783
Sim also supports local models via [Ollama](https://ollama.ai) and [vLLM](https://docs.vllm.ai/) — see the [Docker self-hosting docs](https://docs.sim.ai/self-hosting/docker) for setup details.
7884

7985
### Self-hosted: Manual Setup

apps/sim/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ BETTER_AUTH_URL=http://localhost:3000
1212
NEXT_PUBLIC_APP_URL=http://localhost:3000
1313
# INTERNAL_API_BASE_URL=http://sim-app.default.svc.cluster.local:3000 # Optional: internal URL for server-side /api self-calls; defaults to NEXT_PUBLIC_APP_URL
1414
# TRUSTED_ORIGINS=https://www.example.com,https://app.example.com # Optional: comma-separated additional public origins to trust for auth (apex+www, alias domains). Merged into Better Auth trustedOrigins.
15+
# APP_VERSION=v0.6.91 # Optional: shown by /api/health for self-hosted version checks
16+
# GIT_SHA= # Optional: commit/build SHA shown by /api/health
1517

1618
# Security (Required)
1719
ENCRYPTION_KEY=your_encryption_key # Use `openssl rand -hex 32` to generate, used to encrypt environment variables
Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,49 @@
11
/**
22
* @vitest-environment node
33
*/
4-
import { describe, expect, it } from 'vitest'
4+
import { NextRequest } from 'next/server'
5+
import { afterEach, describe, expect, it } from 'vitest'
56
import { GET } from '@/app/api/health/route'
67

8+
afterEach(() => {
9+
process.env.APP_VERSION = ''
10+
process.env.NEXT_PUBLIC_APP_VERSION = ''
11+
process.env.GIT_SHA = ''
12+
process.env.VERCEL_GIT_COMMIT_SHA = ''
13+
process.env.COMMIT_SHA = ''
14+
})
15+
716
describe('GET /api/health', () => {
8-
it('returns an ok status payload', async () => {
9-
const response = await GET()
17+
it('returns status with runtime version metadata', async () => {
18+
process.env.APP_VERSION = 'v1.2.3'
19+
process.env.GIT_SHA = 'abc123'
20+
21+
const response = await GET(new NextRequest('http://localhost/api/health'))
22+
23+
expect(response.status).toBe(200)
24+
await expect(response.json()).resolves.toEqual({
25+
status: 'ok',
26+
timestamp: expect.any(String),
27+
version: 'v1.2.3',
28+
commit: 'abc123',
29+
})
30+
})
31+
32+
it('falls back to the package version when runtime metadata is not provided', async () => {
33+
process.env.APP_VERSION = ''
34+
process.env.NEXT_PUBLIC_APP_VERSION = ''
35+
process.env.GIT_SHA = ''
36+
process.env.VERCEL_GIT_COMMIT_SHA = ''
37+
process.env.COMMIT_SHA = ''
38+
39+
const response = await GET(new NextRequest('http://localhost/api/health'))
1040

1141
expect(response.status).toBe(200)
1242
await expect(response.json()).resolves.toEqual({
1343
status: 'ok',
1444
timestamp: expect.any(String),
45+
version: '0.1.0',
46+
commit: null,
1547
})
1648
})
1749
})

apps/sim/app/api/health/route.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,32 @@
1+
import type { NextRequest } from 'next/server'
2+
import { NextResponse } from 'next/server'
3+
import { healthContract } from '@/lib/api/contracts/health'
4+
import { parseRequest } from '@/lib/api/server'
5+
import appPackage from '@/package.json'
6+
7+
const DEFAULT_VERSION = appPackage.version
8+
9+
function getAppVersion(): string {
10+
return process.env.APP_VERSION || process.env.NEXT_PUBLIC_APP_VERSION || DEFAULT_VERSION
11+
}
12+
13+
function getAppCommit(): string | null {
14+
return process.env.GIT_SHA || process.env.VERCEL_GIT_COMMIT_SHA || process.env.COMMIT_SHA || null
15+
}
16+
117
/**
218
* Health check endpoint for deployment platforms and container probes.
319
*/
4-
export async function GET(): Promise<Response> {
5-
return Response.json(
20+
export async function GET(request: NextRequest): Promise<Response> {
21+
const parsed = await parseRequest(healthContract, request, {})
22+
if (!parsed.success) return parsed.response
23+
24+
return NextResponse.json(
625
{
726
status: 'ok',
827
timestamp: new Date().toISOString(),
28+
version: getAppVersion(),
29+
commit: getAppCommit(),
930
},
1031
{ status: 200 }
1132
)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { z } from 'zod'
2+
import { noInputSchema } from '@/lib/api/contracts/primitives'
3+
import { defineRouteContract } from '@/lib/api/contracts/types'
4+
5+
export const healthResponseSchema = z.object({
6+
status: z.literal('ok'),
7+
timestamp: z.string(),
8+
version: z.string(),
9+
commit: z.string().nullable(),
10+
})
11+
12+
export type HealthResponse = z.output<typeof healthResponseSchema>
13+
14+
export const healthContract = defineRouteContract({
15+
method: 'GET',
16+
path: '/api/health',
17+
query: noInputSchema,
18+
response: {
19+
mode: 'json',
20+
schema: healthResponseSchema,
21+
},
22+
})

apps/sim/lib/api/contracts/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export * from './environment'
1414
export * from './execution-payloads'
1515
export * from './file-uploads'
1616
export * from './folders'
17+
export * from './health'
1718
export * from './hotspots'
1819
export * from './inbox'
1920
export * from './media'

docker/app.Dockerfile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ RUN --mount=type=cache,id=next-cache-${TARGETPLATFORM},target=/app/apps/sim/.nex
8888
FROM base AS runner
8989
WORKDIR /app
9090

91+
ARG APP_VERSION="0.1.0"
92+
ARG GIT_SHA=""
9193
# Node.js 22, Python, ffmpeg, etc. are already installed in base stage
9294
ENV NODE_ENV=production
9395

@@ -134,6 +136,8 @@ USER nextjs
134136

135137
EXPOSE 3000
136138
ENV PORT=3000 \
137-
HOSTNAME="0.0.0.0"
139+
HOSTNAME="0.0.0.0" \
140+
APP_VERSION=${APP_VERSION} \
141+
GIT_SHA=${GIT_SHA}
138142

139143
CMD ["bun", "apps/sim/server.js"]

0 commit comments

Comments
 (0)