Merge branch 'fix/v1437-r2-jobs' into release/v1.43.7

This commit is contained in:
Marc-André Bombeck committed 2026-10-20 10:17:01 +02:00
commit e5b7eebe64
62 files changed
+1745 -774

No files matched your search

@@ -14,6 +14,10 @@ vi.mock("@/lib/auth/audit", () => ({
auditLog: vi.fn().mockResolvedValue(undefined),
}));
vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() }));
vi.mock("@/lib/logging/signal", async (importOriginal) => ({
...(await importOriginal<typeof import("@/lib/logging/signal")>()),
emitSignal: vi.fn(),
}));
vi.mock("@/lib/db-compat", () => ({
ensureDbCompatibility: vi.fn().mockResolvedValue(undefined),
}));
@@ -78,6 +82,8 @@ vi.mock("@/lib/db", () => ({
import { POST } from "../route";
import { getSession } from "@/lib/auth/session";
import { auditLog } from "@/lib/auth/audit";
import { emitSignal } from "@/lib/logging/signal";
const SESSION_OK = {
session: { id: "sess-1", expiresAt: new Date(Date.now() + 3_600_000) },
@@ -144,6 +150,18 @@ describe("POST /api/import/apple-health-export", () => {
);
const res = await POST(req);
expect(res.status).toBe(413);
// A refused upload is an operational outcome, not an account action: a
// signal, never an audit row.
expect(auditLog).not.toHaveBeenCalledWith(
"import.apple-health.kickoff.denied",
expect.anything(),
);
expect(emitSignal).toHaveBeenCalledWith(
expect.objectContaining({
action: "import.apple-health.kickoff.denied",
meta: expect.objectContaining({ reason: "content_length_exceeded" }),
}),
);
});
it("returns 429 when the rate-limit window is exhausted", async () => {
+14 -13
View File
@@ -26,6 +26,7 @@ import { apiHandler, requireAuth, HttpError } from "@/lib/api-handler";
import { apiError, apiSuccess, getClientIp } from "@/lib/api-response";
import { annotate } from "@/lib/logging/context";
import { auditLog } from "@/lib/auth/audit";
import { emitSignal } from "@/lib/logging/signal";
import { checkRateLimit } from "@/lib/rate-limit";
import { getGlobalBoss } from "@/lib/jobs/boss-instance";
import {
@@ -77,12 +78,12 @@ export const POST = apiHandler(async (request: NextRequest) => {
// content-length cannot bypass it.
const declaredBytes = Number(request.headers.get("content-length") ?? 0);
if (declaredBytes > MAX_UPLOAD_BYTES) {
await auditLog("import.apple-health.kickoff.denied", {
userId: user.id,
ipAddress: getClientIp(request),
details: {
emitSignal({
action: "import.apple-health.kickoff.denied",
level: "warn",
meta: {
reason: "content_length_exceeded",
contentLength: declaredBytes,
content_length: declaredBytes,
},
});
return apiError("Upload exceeds 1.5 GB limit", 413);
@@ -107,10 +108,10 @@ export const POST = apiHandler(async (request: NextRequest) => {
);
} catch (err) {
const message = err instanceof Error ? err.message : "upload_failed";
await auditLog("import.apple-health.kickoff.denied", {
userId: user.id,
ipAddress: getClientIp(request),
details: { reason: "stream_to_disk_failed", message },
emitSignal({
action: "import.apple-health.kickoff.denied",
level: "warn",
meta: { reason: "stream_to_disk_failed", message },
});
return apiError(`Multipart upload failed: ${message}`, 422);
}
@@ -150,10 +151,10 @@ export const POST = apiHandler(async (request: NextRequest) => {
const boss = getGlobalBoss();
if (!boss) {
await auditLog("import.apple-health.kickoff.denied", {
userId: user.id,
ipAddress: getClientIp(request),
details: { reason: "worker_not_running" },
emitSignal({
action: "import.apple-health.kickoff.denied",
level: "warn",
meta: { reason: "worker_not_running" },
});
// Nothing will ever read the staged export; it must not stay in /tmp.
await discardStagedUpload(uploaded.filePath);
@@ -22,6 +22,7 @@ import { apiHandler, requireAuth, HttpError } from "@/lib/api-handler";
import { apiError, apiSuccess, getClientIp } from "@/lib/api-response";
import { annotate } from "@/lib/logging/context";
import { auditLog } from "@/lib/auth/audit";
import { emitSignal } from "@/lib/logging/signal";
import { checkRateLimit } from "@/lib/rate-limit";
import { getGlobalBoss } from "@/lib/jobs/boss-instance";
import {
@@ -67,12 +68,12 @@ export const POST = apiHandler(async (request: NextRequest) => {
const declaredBytes = Number(request.headers.get("content-length") ?? 0);
if (declaredBytes > HEALTH_CONNECT_MAX_UPLOAD_BYTES) {
await auditLog("import.health-connect.kickoff.denied", {
userId: user.id,
ipAddress: getClientIp(request),
details: {
emitSignal({
action: "import.health-connect.kickoff.denied",
level: "warn",
meta: {
reason: "content_length_exceeded",
contentLength: declaredBytes,
content_length: declaredBytes,
},
});
return apiError("Upload exceeds the 1 GB limit", 413);
@@ -94,10 +95,10 @@ export const POST = apiHandler(async (request: NextRequest) => {
);
} catch (err) {
const message = err instanceof Error ? err.message : "upload_failed";
await auditLog("import.health-connect.kickoff.denied", {
userId: user.id,
ipAddress: getClientIp(request),
details: { reason: "stream_to_disk_failed" },
emitSignal({
action: "import.health-connect.kickoff.denied",
level: "warn",
meta: { reason: "stream_to_disk_failed" },
});
return apiError(`Multipart upload failed: ${message}`, 422);
}
@@ -123,10 +124,10 @@ export const POST = apiHandler(async (request: NextRequest) => {
const boss = getGlobalBoss();
if (!boss) {
await auditLog("import.health-connect.kickoff.denied", {
userId: user.id,
ipAddress: getClientIp(request),
details: { reason: "worker_not_running" },
emitSignal({
action: "import.health-connect.kickoff.denied",
level: "warn",
meta: { reason: "worker_not_running" },
});
await discardStagedUpload(uploaded.filePath);
throw new HttpError(503, "Background worker is not running");