Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 37 additions & 36 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,52 +117,53 @@ jobs:
set -euo pipefail

base_url=$(node -e 'const u = new URL(process.env.WEBHOOK_URL); console.log(`${u.protocol}//${u.host}`)')
auth_health_url="${base_url}/api/health/auth-config"
generic_health_url="${base_url}/api/health"
health_url="$auth_health_url"
health_url="${base_url}/api/health/auth-config"

echo "==> Running deploy smoke check: $health_url"

for attempt in $(seq 1 18); do
echo "Attempt ${attempt}/18..."
response=$(curl -sS --max-time 20 -w "\n%{http_code}" "$health_url" || true)
http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | sed '$d')

if [ "$http_code" = "404" ] && [ "$health_url" = "$auth_health_url" ]; then
echo "Auth-config health endpoint not available. Falling back to generic health check."
health_url="$generic_health_url"
continue
fi

if [ "$http_code" = "200" ]; then
if [ "$health_url" = "$generic_health_url" ]; then
echo "==> Generic health check passed"
exit 0
fi
echo "Attempt ${attempt}/18..."
response=$(curl -sS --max-time 20 -w "\n%{http_code}" "$health_url" || true)
http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | sed '$d')

HEALTH_BODY="$body" node -e '
const body = process.env.HEALTH_BODY ?? "";
let parsed;
try {
parsed = JSON.parse(body);
if [ "$http_code" = "200" ]; then
HEALTH_BODY="$body" node -e '
const body = process.env.HEALTH_BODY ?? "";
let parsed;
try {
parsed = JSON.parse(body);
} catch {
console.error("::error::auth-config returned invalid JSON");
process.exit(1);
}

const status = parsed?.status ?? "unknown";
const hasLegacyDomain = Boolean(parsed?.auth?.hasLegacyDomain);
const warnings = Array.isArray(parsed?.warnings) ? parsed.warnings : [];

if (status !== "ok" || hasLegacyDomain || warnings.length > 0) {
console.error(
`::error::OAuth auth-config smoke check failed (status=${status}, hasLegacyDomain=${hasLegacyDomain}, warnings=${warnings.length})`,
);
if (warnings.length > 0) {
console.error(`::error::Warnings: ${warnings.join(" | ")}`);
}
process.exit(1);
const status = parsed?.status ?? "unknown";
const auth = parsed?.auth ?? {};
const hasLegacyDomain = Boolean(parsed?.auth?.hasLegacyDomain);
const warnings = Array.isArray(parsed?.warnings) ? parsed.warnings : [];
const clientIdConfigured = auth?.clientIdConfigured === true;
const sessionSecretConfigured = auth?.sessionSecretConfigured === true;
const redisHealthy = auth?.redisHealthy === true;
const redirectUri = typeof auth?.redirectUri === "string" ? auth.redirectUri : "";
const callbackPathOk = redirectUri.includes("/api/auth/callback");

if (
status !== "ok" ||
hasLegacyDomain ||
warnings.length > 0 ||
!clientIdConfigured ||
!sessionSecretConfigured ||
!redisHealthy ||
!callbackPathOk
) {
console.error(
`::error::OAuth auth-config smoke check failed (status=${status}, hasLegacyDomain=${hasLegacyDomain}, warnings=${warnings.length}, clientIdConfigured=${clientIdConfigured}, sessionSecretConfigured=${sessionSecretConfigured}, redisHealthy=${redisHealthy}, callbackPathOk=${callbackPathOk})`,
);
if (warnings.length > 0) {
console.error(`::error::Warnings: ${warnings.join(" | ")}`);
}
process.exit(1);
}

console.log("==> OAuth auth-config smoke check passed");
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
(PID-aware) after interrupted deploys instead of blocking all future runs
- Backend startup now attempts to connect the shared Redis client before serving
requests, while continuing with fallback behavior if Redis is unavailable
- Deploy workflow auth smoke gate now strictly requires
`/api/health/auth-config` with `status=ok`, no warnings, and healthy
auth-session/Redis flags (no fallback to generic health endpoint)

### Added

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ compose working directory, so runs from `/repo` target the existing homelab stac
The webhook container now executes deploy commands from
`/home/luk-server/Lucky` to match the live compose stack metadata.
Interrupted deploys now auto-recover stale lock directories on the next run.
Deploy workflow smoke checks now require `GET /api/health/auth-config` to return
`status=ok` with no warnings (including healthy Redis/auth-session flags).

Vercel note: `vercel.json` runs `npm run db:generate` before `build:shared` and `build:frontend` to ensure Prisma generated client files are present during cloud builds.
For hosted frontend deployments, set `VITE_API_BASE_URL` to your backend API origin
Expand Down