Преминете към основното съдържание

Отворени решения по сигурността

Констатации от външен преглед, които са проверени срещу кода и умишлено не са променени, защото всяка от тях е избор на политика, а не дефект. Записани са тук, за да бъде изборът направен веднъж и съзнателно, вместо да бъде откриван отново от следващия преглед.

Всичко останало от онзи преглед е поправено в 1.3.0 — вижте changelog.

1. VPN за изследвания огражда данните или само Browser?​

Какво е вярно днес. CIDR списъкът на research hostname пази едно нещо: reverse proxy към Browser. Клиничният host обслужва целия /v1/*, включително /v1/research/*, без мрежово ограничение — собственият му коментар го казва директно: „/v1 принадлежи на API на всеки host, който обслужва клиенти."

Оторизиран акаунт с research grant следователно може да достигне разрешените си изследователски данни извън research VPN, ако клиничният hostname е достъпен. Удостоверяването на акаунта и авторизацията по grant продължават да важат, така че това не е анонимен достъп. Това е по-тясна граница, отколкото документацията внушава.

Решението. Или VPN трябва да огражда изследователския интерфейс — тогава документацията трябва да го казва и така построеното е правилно — или трябва да огражда изследователските данни, и тогава ограничението трябва да се налага върху самите research маршрути, а не само на hostname.

Решено на 13 септември 2026: списъкът огражда изследователския интерфейс. Мрежовият списък за изследвания ограничава кой може да отвори уебсайта Research Browser. Той не огражда изследователските данни. Тях ги пазят влизането в акаунта и авторизацията по grant на всеки адрес, който обслужва API. Кодът не е променян. Документите за мрежата и сигурността вече казват точно това и нищо повече.

2. Трябва ли /api/internal/* да бъде блокиран на gateway?​

Какво е вярно днес. Caddy отговаря на /v1/internal/* с 404. Web приложението пренаписва /api/:path* към /v1/:path* на API без изключение за internal, а catch-all на Caddy насочва /api/* към web приложението. Така /api/internal/purge-deleted достига endpoint, на който /v1/internal/... е отказан.

Всеки internal endpoint продължава да изисква CRON_SECRET, така че това преодолява мрежовото ограничение, а не удостоверяването.

Решено и поправено на 13 септември 2026 (1.4.0). Caddy вече отговаря на /api/internal/* със същия 404 като на /v1/internal/*, преди общия маршрут към уеб приложението. На работеща система /api/internal/purge-deleted достигаше API преди промяната и получава 404 след нея. Същото важи за вариантите: главно Internal, кодирано i, двойна наклонена черта и сегмент ... Обикновените маршрути /api/* не са променени. caddy-boundaries.test.mjs пази съвпадението преди общия маршрут.

3. Трябва ли API да спре да се свързва като superuser на базата?​

Какво е вярно днес. POSTGRES_USER: lospor се създава от официалния image като superuser, и както DATABASE_URL, така и DIRECT_URL използват този акаунт. Няма понижаване и няма отделна роля за изпълнение.

Appliance вече познава шаблона: create-status-probe.sh създава lospor_status_probe като login роля с лимит на връзките и default_transaction_read_only. Тази дисциплина е приложена към Status probe, но не и към приложението.

Поправено в 1.4.0. Работещият API се свързва като lospor_app. Тази роля няма права на superuser, за създаване на бази данни и роли или за репликация, и има лимит на връзките. Тя може да чете и записва редовете на приложението, но не може да променя схемата, да записва историята на миграциите или да се свързва с базите данни за поддръжка. Миграциите, архивите, възстановяванията, изграждането на терминология и инструментите на оператора продължават да използват lospor.

  • Права. db-app-role-init изпълнява create-app-role.sh след миграциите и преди API при всяко стартиране чрез Compose. Така правата остават верни, след като обновяване добави таблици, след като възстановяване подмени базата данни и след смяна на поколение терминология. Възстановяванията използват pg_restore --no-privileges.
  • Смяна на данните за достъп. Обхватът database сменя и двете пароли.
  • Проверено на работеща система. API се свързва като lospor_app; DDL и записи в _prisma_migrations се отказват; всички таблици на приложението имат права; doctor минава; пробното възстановяване минава; и смяна в обхват database, и смяна в обхват ordinary бяха приложени и проверени.

4. Колко дълго да се пазят staging данните от EHR и кой ги изтрива?​

Какво е вярно днес. Импортите носят 14-дневен expiresAt, но изтичането е само филтър при четене. Нищо не изтрива изтекъл EhrImport или неговите EhrImportField редове, и нищо не почиства обработените или отхвърлени входящи файлове на диска. И двете могат да съдържат идентификатори и клинично съдържание.

Решението. Срокът на съхранение е въпрос на болнично управление, а не техническа стойност по подразбиране — четиринадесет дни не са законово изискване никъде. След като бъде избран срок, изтриването трябва да бъде реализирано, а неуспехите му да се виждат в Status, както при retention purge и автоматичното закриване на случаи. Мълчаливото неизтриване е текущото състояние и точно то не бива да се повтаря.

Решено на 13 септември 2026: 14 дни. Поправено в 1.4.0. Ежедневното почистване изтрива импортите след изтичане на срока им, заедно с полетата им, и файловете, запазени от транспорта с папка в processed/ и rejected/. То никога не засяга входящата и изходящата папка. Болницата може да съкрати срока в Управление от 1 до 14 дни, а ограничение в базата данни пази записаната стойност в този обхват. Неуспешно изтриване показва в Status показанието RETENTION_EHR_STAGING_REJECTED.

5. Кои AI модели да използва appliance?​

Какво е вярно днес. Маршрутите по подразбиране използват open-mistral-7b и pixtral-12b-2409. Нито MISTRAL_MODEL, нито MISTRAL_VISION_MODEL се предават от Compose, а HospitalExternalAiPolicy — запечатаният ред, който Status използва за конфигуриране на външния ИИ — също няма поле за модел. Така на appliance моделът не може да бъде избран по никой поддържан път; той е това, което файловете на маршрутите съдържат.

Дали точно тези модели са изведени от употреба не е проверено тук и трябва да се сверява с текущия каталог на доставчика.

Решението. Кои модели са клинично валидирани за извличане от лабораторни резултати и от монитор, и след това дали изборът на модел принадлежи на запечатания ред с политиката, до credential — където живее всяка друга настройка за външен ИИ.

Проверено и поправено на 13 септември 2026 (1.4.0). И двата модела по подразбиране са спрени: open-mistral-7b на 30 март 2025 и pixtral-12b-2409 на 31 декември 2025. Така всяка функция с ИИ би отказала веднага щом болницата добави ключа си. Изборът на модел вече е в запечатания ред с политиката. Всяка функция използва закрепен модел с дата от списък във версията: по подразбиране mistral-small-2603 за съветника и mistral-large-2512 за разчитане на лабораторни резултати и снимки на монитор. Модели на ИИ в Управление избира между тях с одит. Модел, който Mistral откаже, води до EXTERNAL_AI_MODEL_UNAVAILABLE и показание model-unavailable в Status. Така бъдещо спиране се решава с избор на друг модел, без да се чака обновяване. Вижте Управление на външния ИИ.

Клиничната проверка на качеството на извличане остава задача на болницата, преди да разчита на него, както беше и при старите модели.