mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 06:06:10 +00:00
The compose file runs Postgres 18. An install from v1.45 or earlier keeps its Postgres 16 data in `pgdata`, which 18 cannot open, so a one-shot `db-upgrade` service moves it on the first start: it starts Postgres 16 on the old volume inside its own container, streams a dump into 18 in one transaction, compares every table's row count, gathers planner statistics and marks the old volume as moved. The app waits for it to succeed. The old volume is never changed apart from the marker, so the way back is the previous image and volume lines. A move cut short leaves a "moving" marker and runs again from scratch; an emptied new volume after a finished move is refused rather than refilled with the old state. scripts/compose-db-upgrade-check.sh plays all of it against real containers from the v1.45.0 compose file, and runs in CI on every change to the compose file. Pull requests run the integration suite and e2e on Postgres 18; the nightly integration run keeps 16 covered for installs that bring their own database.
174 lines
5.7 KiB
YAML
174 lines
5.7 KiB
YAML
name: Post-publish verify
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
image_ref:
|
|
description: Exact registry repository to verify
|
|
required: true
|
|
type: string
|
|
image_tag:
|
|
description: Exact published release tag
|
|
required: true
|
|
type: string
|
|
image_digest:
|
|
description: Exact published multi-arch manifest digest
|
|
required: true
|
|
type: string
|
|
build_sha:
|
|
description: Expected short source commit SHA
|
|
required: true
|
|
type: string
|
|
workflow_dispatch:
|
|
inputs:
|
|
image_ref:
|
|
description: Exact registry repository to verify
|
|
required: true
|
|
type: string
|
|
image_tag:
|
|
description: Exact published release tag
|
|
required: true
|
|
type: string
|
|
image_digest:
|
|
description: Exact published multi-arch manifest digest
|
|
required: true
|
|
type: string
|
|
build_sha:
|
|
description: Expected short source commit SHA
|
|
required: true
|
|
type: string
|
|
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
|
|
jobs:
|
|
verify:
|
|
name: Pull and smoke-test exact published image
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 10
|
|
env:
|
|
IMAGE_REF: ${{ inputs.image_ref }}
|
|
IMAGE_TAG: ${{ inputs.image_tag }}
|
|
IMAGE_DIGEST: ${{ inputs.image_digest }}
|
|
BUILD_SHA: ${{ inputs.build_sha }}
|
|
DATABASE_URL: postgresql://healthlog:healthlog@localhost:5432/healthlog?schema=public
|
|
|
|
services:
|
|
postgres:
|
|
image: postgres:18-alpine
|
|
env:
|
|
POSTGRES_USER: healthlog
|
|
POSTGRES_PASSWORD: healthlog
|
|
POSTGRES_DB: healthlog
|
|
ports:
|
|
- 5432:5432
|
|
options: >-
|
|
--health-cmd "pg_isready -U healthlog"
|
|
--health-interval 5s
|
|
--health-timeout 5s
|
|
--health-retries 10
|
|
|
|
steps:
|
|
- name: Log in to GHCR
|
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Pull exact image
|
|
run: |
|
|
TAG_REF="${IMAGE_REF}:${IMAGE_TAG}"
|
|
DIGEST_REF="${IMAGE_REF}@${IMAGE_DIGEST}"
|
|
|
|
echo "Pulling published tag $TAG_REF"
|
|
docker pull "$TAG_REF"
|
|
resolved_digest="$(docker buildx imagetools inspect "$TAG_REF" --format '{{json .Manifest.Digest}}' | tr -d '"')"
|
|
if [ "$resolved_digest" != "$IMAGE_DIGEST" ]; then
|
|
echo "::error::Published tag digest mismatch: $TAG_REF resolved to '$resolved_digest', expected '$IMAGE_DIGEST'." >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "Pulling immutable image $DIGEST_REF"
|
|
docker pull "$DIGEST_REF"
|
|
|
|
- name: Run migrations
|
|
run: |
|
|
DIGEST_REF="${IMAGE_REF}@${IMAGE_DIGEST}"
|
|
docker run --rm \
|
|
--network host \
|
|
--entrypoint node \
|
|
-e DATABASE_URL="$DATABASE_URL" \
|
|
"$DIGEST_REF" \
|
|
/opt/prisma-cli/node_modules/prisma/build/index.js migrate deploy
|
|
|
|
- name: Start exact image
|
|
run: |
|
|
DIGEST_REF="${IMAGE_REF}@${IMAGE_DIGEST}"
|
|
docker run -d --name healthlog-verify \
|
|
--network host \
|
|
-e DATABASE_URL="$DATABASE_URL" \
|
|
-e ENCRYPTION_KEYS='{"v1":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}' \
|
|
-e ENCRYPTION_ACTIVE_KEY_ID=v1 \
|
|
-e API_TOKEN_HMAC_KEY=cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc \
|
|
-e AUTH_RP_NAME=HealthLog \
|
|
-e AUTH_RP_ID=localhost \
|
|
-e AUTH_RP_ORIGIN=http://localhost:3000 \
|
|
-e NODE_ENV=production \
|
|
-e PORT=3000 \
|
|
"$DIGEST_REF"
|
|
|
|
- name: Verify exact version
|
|
run: |
|
|
body=""
|
|
for i in $(seq 1 30); do
|
|
if body="$(curl -sf http://localhost:3000/api/version)"; then
|
|
echo "Version endpoint ready after $((i * 2))s"
|
|
break
|
|
fi
|
|
sleep 2
|
|
done
|
|
if [ -z "$body" ]; then
|
|
echo "::error::Exact image did not expose /api/version within 60 seconds." >&2
|
|
docker logs healthlog-verify || true
|
|
exit 1
|
|
fi
|
|
|
|
EXPECTED_VERSION="${IMAGE_TAG#v}"
|
|
echo "$body" | jq .
|
|
if ! jq -e --arg expected "$EXPECTED_VERSION" '.data.version == $expected' <<< "$body" >/dev/null; then
|
|
actual="$(jq -r '.data.version // "<missing>"' <<< "$body")"
|
|
echo "::error::Version mismatch: exact image reports '$actual', expected '$EXPECTED_VERSION' (release tag '$IMAGE_TAG')." >&2
|
|
exit 1
|
|
fi
|
|
if ! jq -e --arg expected "$BUILD_SHA" '.data.buildSha == $expected' <<< "$body" >/dev/null; then
|
|
actual="$(jq -r '.data.buildSha // "<missing>"' <<< "$body")"
|
|
echo "::error::Build SHA mismatch: exact image reports '$actual', expected '$BUILD_SHA'." >&2
|
|
exit 1
|
|
fi
|
|
|
|
- name: Verify health
|
|
run: |
|
|
for i in $(seq 1 30); do
|
|
if body="$(curl -sf http://localhost:3000/api/health)" && jq -e '.status == "ok"' <<< "$body" >/dev/null; then
|
|
echo "$body" | jq .
|
|
echo "Health endpoint ready after $((i * 2))s"
|
|
exit 0
|
|
fi
|
|
sleep 2
|
|
done
|
|
echo "::error::Exact image did not report healthy within 60 seconds." >&2
|
|
docker logs healthlog-verify || true
|
|
exit 1
|
|
|
|
- name: Container logs
|
|
if: always()
|
|
continue-on-error: true
|
|
run: docker logs healthlog-verify
|
|
|
|
- name: Tear down
|
|
if: always()
|
|
continue-on-error: true
|
|
run: docker rm -f healthlog-verify
|