From e9cf3c1b15f223caf05a45e73365adaeeec31bb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sat, 26 Sep 2026 22:07:11 +0200 Subject: [PATCH] fix: carry the cross-branch rules through offhost keys, the Telegram test mock and the OIDC reason list --- docs/api/openapi.yaml | 8 +++++--- src/app/api/telegram/webhook/__tests__/route.test.ts | 5 ++++- src/lib/jobs/offhost-backup.ts | 3 ++- src/lib/openapi/routes/auth.ts | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/api/openapi.yaml b/docs/api/openapi.yaml index 5953a81d8..6243f7b3f 100644 --- a/docs/api/openapi.yaml +++ b/docs/api/openapi.yaml @@ -3433,9 +3433,11 @@ paths: listed here, because the identity provider drives it rather than a client), which ends the native leg at `healthlog://oidc-callback` with `code=`, with `mfa_ticket=&methods=`, or with `error=`, where reason is one of `oidc_disabled`, `oidc_rate_limited`, `oidc_denied`, - `oidc_no_email`, `oidc_email_unverified`, `oidc_identity_conflict`, `oidc_registration_disabled`, - `oidc_failed`. The reasons are this exact snake_case vocabulary on both legs; a client maps a value it does - not know to a generic sign-in failure. + `oidc_no_email`, `oidc_email_unverified`, `oidc_identity_conflict`, `oidc_link_required`, + `oidc_registration_disabled`, `oidc_failed`. `oidc_link_required` means the provider's e-mail matches an + existing local account that is not linked yet; the owner links it by signing in once with that account's own + password or passkey in a browser. The reasons are this exact snake_case vocabulary on both legs; a client + maps a value it does not know to a generic sign-in failure. /api/auth/passkey/register-options: post: tags: diff --git a/src/app/api/telegram/webhook/__tests__/route.test.ts b/src/app/api/telegram/webhook/__tests__/route.test.ts index 6b41c470b..57c37c310 100644 --- a/src/app/api/telegram/webhook/__tests__/route.test.ts +++ b/src/app/api/telegram/webhook/__tests__/route.test.ts @@ -54,7 +54,10 @@ vi.mock("@/lib/telegram-cleanup", () => ({ TELEGRAM_AUTO_DELETE_DELAY_MS: 30 * 60 * 1000, })); -vi.mock("@/lib/measurement-reminders/satisfy", () => ({ +vi.mock("@/lib/measurement-reminders/satisfy", async (importOriginal) => ({ + ...(await importOriginal< + typeof import("@/lib/measurement-reminders/satisfy") + >()), satisfyReminder: vi.fn().mockResolvedValue({ satisfied: true }), })); diff --git a/src/lib/jobs/offhost-backup.ts b/src/lib/jobs/offhost-backup.ts index 5317d450f..a2f2e34fa 100644 --- a/src/lib/jobs/offhost-backup.ts +++ b/src/lib/jobs/offhost-backup.ts @@ -36,6 +36,7 @@ import { createRawStreamEncryptor, decryptRawStream } from "@/lib/crypto"; import { createBackupKeyIdTextScanner } from "@/lib/export/backup-key-ids"; import { streamFullBackupJson } from "@/lib/export/full-backup-stream"; import { annotate, getEvent } from "@/lib/logging/context"; +import { envValue } from "@/lib/env"; const ALGORITHM = "aes-256-gcm"; const IV_LENGTH = 12; @@ -120,7 +121,7 @@ export function loadOffhostConfig(): OffhostBackupConfig | null { secretKey, region: envOr("BACKUP_S3_REGION", "auto"), encryptionKey: decodeBackupKey(encRaw), - previousEncryptionKeys: (process.env.BACKUP_ENCRYPTION_PREVIOUS_KEYS ?? "") + previousEncryptionKeys: (envValue("BACKUP_ENCRYPTION_PREVIOUS_KEYS") ?? "") .split(",") .map((raw) => raw.trim()) .filter((raw) => raw.length > 0) diff --git a/src/lib/openapi/routes/auth.ts b/src/lib/openapi/routes/auth.ts index 4a43548a5..ce5f0d759 100644 --- a/src/lib/openapi/routes/auth.ts +++ b/src/lib/openapi/routes/auth.ts @@ -2011,7 +2011,7 @@ export const authPaths: NonNullable = { responses: { "302": { description: - "Always a redirect. To the provider on success. On failure to `/auth/login?error=` (browser) or `healthlog://oidc-callback?error=` (native), where reason is one of `oidc_disabled`, `oidc_rate_limited`, `oidc_invalid_request`, `oidc_failed`. The provider then returns to the callback (not listed here, because the identity provider drives it rather than a client), which ends the native leg at `healthlog://oidc-callback` with `code=`, with `mfa_ticket=&methods=`, or with `error=`, where reason is one of `oidc_disabled`, `oidc_rate_limited`, `oidc_denied`, `oidc_no_email`, `oidc_email_unverified`, `oidc_identity_conflict`, `oidc_registration_disabled`, `oidc_failed`. The reasons are this exact snake_case vocabulary on both legs; a client maps a value it does not know to a generic sign-in failure.", + "Always a redirect. To the provider on success. On failure to `/auth/login?error=` (browser) or `healthlog://oidc-callback?error=` (native), where reason is one of `oidc_disabled`, `oidc_rate_limited`, `oidc_invalid_request`, `oidc_failed`. The provider then returns to the callback (not listed here, because the identity provider drives it rather than a client), which ends the native leg at `healthlog://oidc-callback` with `code=`, with `mfa_ticket=&methods=`, or with `error=`, where reason is one of `oidc_disabled`, `oidc_rate_limited`, `oidc_denied`, `oidc_no_email`, `oidc_email_unverified`, `oidc_identity_conflict`, `oidc_link_required`, `oidc_registration_disabled`, `oidc_failed`. `oidc_link_required` means the provider's e-mail matches an existing local account that is not linked yet; the owner links it by signing in once with that account's own password or passkey in a browser. The reasons are this exact snake_case vocabulary on both legs; a client maps a value it does not know to a generic sign-in failure.", }, }, },