mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 13:22:14 +00:00
chore(release): v1.4.15
Bumps version to 1.4.15 and adds the corresponding CHANGELOG entry covering backup completeness, achievements UI, onboarding tour, doctor-report v2, auto-deploy on GHCR push, empty-states sweep, notification + integration status UI, AI hallucination guardrails, mobile UX fixes, and the BD-Zielbereich percentage fix. Includes the formatting drift left over by the v1.4.15 development phases (Prettier sweep on touched files) and a typecheck fix in `dashboard-layout.test.ts` so `pnpm typecheck`, `pnpm lint`, `pnpm format:check`, `pnpm test`, and `pnpm test:integration` all pass green on the release tag. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1b1214bcb3
commit
4dcaa08b42
32 files changed
+639
-295
No files matched your search
@@ -252,10 +252,7 @@ describe("POST /api/internal/deploy-webhook", () => {
|
||||
|
||||
it("tolerates malformed (non-string) status fields by treating them as unknown", async () => {
|
||||
const res = await POST(
|
||||
jsonRequest(
|
||||
{ status: 42 },
|
||||
{ "x-deploy-webhook-secret": "test-secret" },
|
||||
),
|
||||
jsonRequest({ status: 42 }, { "x-deploy-webhook-secret": "test-secret" }),
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
const body = (await res.json()) as { outcome: string };
|
||||
@@ -291,18 +288,24 @@ describe("POST /api/internal/deploy-webhook", () => {
|
||||
|
||||
describe("GET /api/internal/deploy-webhook (reachability check)", () => {
|
||||
it("returns 200 with valid secret header", async () => {
|
||||
const req = new NextRequest("http://localhost/api/internal/deploy-webhook", {
|
||||
method: "GET",
|
||||
headers: { "x-deploy-webhook-secret": "test-secret" },
|
||||
});
|
||||
const req = new NextRequest(
|
||||
"http://localhost/api/internal/deploy-webhook",
|
||||
{
|
||||
method: "GET",
|
||||
headers: { "x-deploy-webhook-secret": "test-secret" },
|
||||
},
|
||||
);
|
||||
const res = await GET(req);
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
|
||||
it("returns 401 without a secret", async () => {
|
||||
const req = new NextRequest("http://localhost/api/internal/deploy-webhook", {
|
||||
method: "GET",
|
||||
});
|
||||
const req = new NextRequest(
|
||||
"http://localhost/api/internal/deploy-webhook",
|
||||
{
|
||||
method: "GET",
|
||||
},
|
||||
);
|
||||
const res = await GET(req);
|
||||
expect(res.status).toBe(401);
|
||||
});
|
||||
|
||||
@@ -52,7 +52,10 @@ interface NormalizedEvent {
|
||||
raw: CoolifyDeployPayload;
|
||||
}
|
||||
|
||||
function asStringOr<T extends string | null>(value: unknown, fallback: T): string | T {
|
||||
function asStringOr<T extends string | null>(
|
||||
value: unknown,
|
||||
fallback: T,
|
||||
): string | T {
|
||||
return typeof value === "string" && value.length > 0 ? value : fallback;
|
||||
}
|
||||
|
||||
@@ -63,7 +66,8 @@ function classifyOutcome(status: unknown): NormalizedEvent["outcome"] {
|
||||
// "failed" / "error" / "stopped" for unhappy. Anything else is
|
||||
// logged but doesn't trigger a Telegram page (avoids alert fatigue
|
||||
// on intermediate states like "queued" or "in_progress").
|
||||
if (s === "success" || s === "finished" || s === "succeeded") return "success";
|
||||
if (s === "success" || s === "finished" || s === "succeeded")
|
||||
return "success";
|
||||
if (s === "failed" || s === "error" || s === "stopped" || s === "failure") {
|
||||
return "failure";
|
||||
}
|
||||
@@ -148,7 +152,11 @@ export const POST = apiHandler(async (request: NextRequest) => {
|
||||
// Coolify's per-event burst (typically 1-2 per deploy) but well below
|
||||
// a hostile actor flooding to fish for a working secret.
|
||||
const ip = getClientIp(request);
|
||||
const rl = await checkRateLimit(`deploy-webhook:${ip ?? "unknown"}`, 60, 60_000);
|
||||
const rl = await checkRateLimit(
|
||||
`deploy-webhook:${ip ?? "unknown"}`,
|
||||
60,
|
||||
60_000,
|
||||
);
|
||||
if (!rl.allowed) {
|
||||
return NextResponse.json(
|
||||
{ status: "rate_limited" },
|
||||
@@ -204,7 +212,10 @@ export const POST = apiHandler(async (request: NextRequest) => {
|
||||
await notifyAdminsOfFailure(event);
|
||||
}
|
||||
|
||||
return NextResponse.json({ status: "ok", outcome: event.outcome }, { status: 200 });
|
||||
return NextResponse.json(
|
||||
{ status: "ok", outcome: event.outcome },
|
||||
{ status: 200 },
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user