nessie

Створено в ЄС і де зберігаються ваші дані

Де створено Nessie, де зберігаються ваші дані і що ви контролюєте, коли розгортаєте його самостійно.

Хто це створює і за яким правом

Nessie створює UnlikeOtherAI s.r.o. — компанія, зареєстрована в Чехії і така, що діє за чеським правом.

Ця сторінка описує, як побудоване програмне забезпечення і де воно працює. Це не заява про відповідність вимогам: Nessie не має жодної сертифікації з безпеки, і нічого з написаного тут не слід розуміти як таку заяву. Які персональні дані обробляються і на якій підставі — тема політики конфіденційності, яка є окремою сторінкою.

Де працює хмарна версія

Nessie Cloud працює на європейських хостинг-провайдерах — Scaleway, Hetzner та інших. Ми обираємо найкращу послугу кожного провайдера, тож різні частини продукту можуть працювати в різних провайдерів, і всі вони в Європі.

Будь-які точніші відомості — конкретний майданчик, місто чи центр обробки даних — тут свідомо не наведено, бо вони застаріли б непомітно для всіх.

Власний хостинг залишає вибір за вами

Де працює ваш власний екземпляр — це параметр розгортання, а не параметр продукту. Шлях для однієї машини — це стек Docker Compose, який ви розміщуєте на обраній вами машині. У дереві Terraform для керованої хмари регіон — це вхідне значення без жодного типового: там нічого не можна вгадати, тож нічого немає за замовчуванням, а база даних, сховище об’єктів і сервіси слідують за регіоном, який ви вкажете.

Для цього самого питання важливі ще дві структурні деталі. Черга й транспорт реального часу — це обидва PostgreSQL: на цьому шляху немає ні Redis, ні брокера повідомлень, тож немає третьої системи, яку треба було б десь розмістити. А сховище об’єктів сумісне з S3 і не прив’язане до одного постачальника; еталонне розгортання запускає MinIO в контейнері в приватній мережі без власного вхідного доступу. Частини, які мають десь жити, — це база даних, сховище об’єктів і два сервіси Node, і всі вони живуть там, де ви їх розмістите. Як це розгорнути, описано на сторінці встановлення.

Що Nessie зберігає — і чого свідомо не зберігає

Ідентифікацію не копіюємо

За входу через UnlikeOtherAI ідентифікацію людей веде і зберігає постачальник ідентифікації: чинники автентифікації, профілі, членство в організаціях і командах та запрошення. Nessie — залежна сторона, а не друга система ідентифікації. Це рішення і про дані, і про архітектуру: ідентифікацію, яку Nessie ніколи не зберігає, він не може ані витекти, ані втратити, ані забути видалити.

У таблиці users насправді зберігається стабільний ідентифікатор користувача від постачальника — ключ, через який розв’язується все інше, — адреса електронної пошти, неавторитетна копія імені й аватара для відображення та локальні поля продукту (налаштування, займенники, версія токена для відкликання сесій). Копія існує лише для того, щоб показувати ім’я та зображення без окремого запиту на кожен рядок, і її повторно синхронізують із перевірених тверджень постачальника під час входу, перемикання команди та оновлення сесії. Жодного значення ніхто не вигадує: людина, якої постачальник не назвав, показується зі своєю адресою електронної пошти, доки не з’явиться ім’я. Хеш пароля існує лише для початкового власника екземпляра, де взагалі немає постачальника ідентифікації.

Те саме стосується структури. Одна організація постачальника — це одна організація Nessie, прив’язана за ідентифікатором організації від постачальника; команда без зв’язку з постачальником відповідає 404 TEAM_NOT_LINKED, а не вдається до локального припущення, і актуальне читання складу команди йде до постачальника ідентифікації й нічого не зберігає.

Дві копії ще не прибрано, і було б нечесно створювати інше враження. Назви організацій і команд досі зберігаються локально поруч з ідентифікаторами прив’язки, а локальні записи членства досі авторизують звичайні запити між синхронізаціями. Прибрати обидві — це відкрита робота, що відстежується в репозиторії, а не те, що вже завершено.

Нічого комерційного

Платежами керує центральний платіжний сервіс. Nessie не зберігає ні клієнта платіжного провайдера, ні підписки, ні рахунку-фактури, ні ціни, ні кредитного балансу, ні політики поповнення, ні платіжної згоди, ні виписки, ні стану скасування, і він не розраховує тарифи. Він читає готові до показу значення й показує їх.

Секрети

Щоб зберегти секрет, потрібне налаштоване сховище секретів. Резервного варіанту в базі даних і шляху з відкритим текстом свідомо немає: без сховища збереження, ротація й відкликання секрету повертають помилку, а не переходять на менш безпечний спосіб. Власні записи Nessie про секрет не містять ні значення, ні шифротексту, ні ключа, ні токена сховища — лише непрозоре посилання та метадані, — а шляхи у сховищі будуються тільки зі структурних ідентифікаторів і ніколи з назви організації, команди, проєкту чи імені людини.

Облікові дані, які Nessie мусить зберігати сам, щоб діяти як клієнт OAuth, — облікові дані конекторів і поштових скриньок, секрети вебхуків, матеріал для оновлення сесій, корисне навантаження виконавців — запечатані в цільових конвертах AES-256-GCM під версійним набором ключів, що є окремим коренем відносно секрету підписання сесій, із задокументованою процедурою ротації.

Є й правило щодо моделей: секрет може бути відомий як такий, що існує, і може бути дозволений до використання, але вміст секрету не повинен потрапляти в контекст моделі, запити, аргументи інструментів, результати інструментів, пам’ять, ембедінги, пошук, журнали чи повідомлення. Агентові можна дозволити використовувати секрет. Дозволити йому розкрити секрет не можна ніколи.

Чи зашифровані диски під цим, залежить від машини, на якій працює розгортання. Репозиторій не гарантує шифрування на рівні томів для баз даних і томів сховища об’єктів, тому ця сторінка цього не стверджує.

Ізоляція орендарів

Nessie за задумом багатоорендний: одна база даних, у якій кожен рядок належить рівно одній організації, а кожна дочірня таблиця має organization_id. Ізоляція забезпечується в двох місцях — умовою області, яку містить кожен запит, і справжніми зовнішніми ключами на цьому стовпці; їх додали у сорока двох обмеженнях після того, як внутрішній аудит виявив, що стовпець є, але без обмежень, у десятках таблиць.

Набір перевірок відповідності утримує цей інваріант на межі HTTP. Він створює максимально привілейованого зловмисника — повноцінного власника власної організації — і стверджує, що кожне канонічне читання ресурсів іншої організації повертає 403, 404 або порожній результат, а кожна канонічна зміна відхиляється, а рядок іншої організації лишається недоторканим. Він охоплює канали, схвалення, журнал аудиту, тригери, агентів і їхні прив’язки, запуски, проєкти, завдання, гілки, підключення, встановлення робочих процесів, екземпляри MCP, базу знань і сповіщення.

Щоб бути точними щодо механізму: це забезпечення на рівні застосунку плюс зовнішні ключі, а не захист на рівні рядків PostgreSQL (row-level security). Політики RLS немає й немає страховки на боці бази даних, а набір перевірок відповідності виконується на достовірному сховищі в пам’яті, а не на живій базі, тож він доводить умови області, які пише код, а не SQL, який виконує сервер. Репозиторій каже про це у власній документації до набору перевірок, і ця сторінка теж.

Журнал аудиту

Кожна значуща дія записується: хто діяв і в якій ролі — людина, агент, служба, — що зробив, з яким ресурсом, у якій організації, проєкті, команді чи каналі, чи вдалося це, чи було відмовлено, чому, а також ідентифікатор запиту, адреса та user agent, з якими він надійшов.

Журнал за задумом доступний лише для додавання, і записати в нього ззовні неможливо: POST /api/audit-log не існує, і це свідомо. Записи пов’язані в ланцюг: кожен містить дайджест SHA-256 власних канонічних полів плюс дайджест попереднього запису цієї організації, тож змінений або видалений рядок розриває ланцюг, і це можна виявити. Власник або адміністратор організації може пройти цим ланцюгом на вимогу й дізнатися, де він уперше розірвався, якщо таке сталося.

Два чесні застереження. Ланцюг робить журнал таким, що виявляє втручання, а не захищеним від втручання: за ним немає ні скасування прав на запис на рівні бази даних, ні сховища з одноразовим записом, тож гарантія полягає у виявленні, а не в запобіганні. І записи за замовчуванням зберігаються безстроково — налаштовуване зберігання з експортом перед видаленням задумане, але не створене. Записам також заборонено містити секрети чи повні тіла запитів, а фіксований набір назв чутливих полів метаданих приховується під час запису.

Журнал витрат

Кожен виклик моделі записується на організацію, а також на користувача, команду, проєкт, канал, агента й запуск, з яких він походить, разом із витраченими токенами; вартість, повідомлена провайдером, і власна оцінка Nessie зберігаються поруч. Показник, який провайдер не повідомляє, зберігається як null, а не вгадується. Звіти може читати власник або адміністратор організації.

Цей журнал — операційна телеметрія: скільки організація витратила і від чийого імені. Це не рахунок-фактура і не платіжний авторитет.

Треті сторони, коли ви користуєтеся хмарною версією

Хмарне розгортання звертається до невеликого фіксованого набору сервісів. Трафік моделей і вебпошук не йдуть до провайдерів напряму: обидва виходять через один шлюз, яким керує UnlikeOtherAI, і саме там розташовані провайдери моделей і пошуку. Вхід і виставлення рахунків ідуть до автентифікатора UnlikeOtherAI. Сховище секретів розміщене на власних ресурсах поруч із застосунком. Посилання на відеодзвінки, які створює сервер, за замовчуванням ведуть на публічний сервіс Jitsi.

Майже все інше вимкнено, доки оператор його не налаштує, і про це прямо сказано, а не мовчки не працює: підключені облікові записи Google, Microsoft і Slack; електронна пошта агентів через Amazon SES, яку розгортання запускає у власному обліковому записі без посередників; push-сповіщення для мобільних пристроїв і браузерів; конектори досліджень і джерел дошок; хмарні браузери. Дві деталі варто назвати, бо вони змінюють, куди потрапляють дані:

  • Підключені поштові скриньки лишаються у вашого провайдера. Пошта читається наживо у вашого провайдера через IMAP і SMTP або через власний вхід провайдера; Nessie зберігає запечатані облікові дані й більше нічого про обліковий запис. Виняток — скринька, яку ви підключаєте до вхідних у розділі Клієнти: ви просите зберігати її розмови разом із кожним клієнтом, тому їх копіюють.
  • Голосові дзвінки в застосунку не проходять через Nessie. API лише видає облікові дані, а клієнт сам відкриває аудіоз’єднання. Диктування й телефонні дзвінки — інша річ: їхній звук проходить через Nessie до провайдерів розпізнавання мовлення й моделей, які його обробляють.

Ще одна деталь, що стосується запитів до моделей, дотримується того самого принципу: підписані заголовки з ідентифікацією викликача надсилаються лише на налаштований хост чату, тож якщо спрямувати ембедінги на іншу кінцеву точку, вона ніколи не отримає твердження про делегування щодо людини, чий текст перетворюється на ембедінги.

Хмарний продукт використовує кількох провайдерів інференсу й обирає між ними за вартістю та якістю. Згодом організація зможе в адмін-панелі обирати, якими провайдерами можуть користуватися її агенти: лише західними, лише європейськими, лише китайськими або без уподобань — найефективнішим провайдером для кожного завдання. Самостійно розгорнутий екземпляр обирає власних.

Власний хостинг змінює все це

Кожна третя сторона вище — це вибір конфігурації на власному екземплярі. Запити до моделей можна спрямувати на будь-яку кінцеву точку, сумісну з OpenAI, зокрема на вашому власному обладнанні. Конектори вимкнені, доки ви їх не ввімкнете. Вхід через UnlikeOtherAI — підтримуваний шлях, а розгортання зовсім без постачальника ідентифікації працює як одна неприв’язана організація з початковим власником.

У цьому й увесь сенс: програмне забезпечення те саме, а рішення про те, де воно працює і до чого може звертатися, належать тому, хто його запускає. Як саме, описано на сторінці встановлення.