Журнал змін
Что нового.
Все усовершенствования платформы, как только она будет запущена.
· SecurityService
Рекорд читає та відмовляється від нематеріальних експортів
ХІПА §164.312 (б) для Служби безпеки. Платформа записів кожного свинцю CHANGE (LeadHistory) і кожен логін (SystemAccessLog) і записи немає ВАЖКО СКАЗАТИ, тому «здивився на цьому позичальнику» — перше питання §164.402 порушена оцінка запитань — була незавершена. PhiAccessAuditor будує події з OTK/*** кінцева точка вже вирішена, тому ідентичність в аудиторському рядку така ж особистість, яка авторизація запиту. Клієнт IP отримує X-Forwarded-For; за Traefik, віддаленийДодаток записує інгрес-под і не варто для виявлення. Випадкові дані зафіксовані занадто — що виявлення дивиться на — і несхожих землях-підбирачів на сказаному не падає. Читає: один свинець fetch = VIEW, сітка = одна подія LIST на свинцю фактично відправлено (з проектованої ДТО, тому свинець відфільтровано VIEW UNASSIGNED LEADS ніколи не з'являється як один, який був прочитаний. 401/403/404 всі записи заперечення. Експорт не закритий — доступ до системи CSV, HMDA LAR, QC тренування корпусу і платформа-широкий корпус видобутку. Усі записи одного заходу за запис BEFORE файл будується, і не вдалося перевірити запис повертається 503: "Ми звернулися дані, але втратили запис" - це одна відповідь, що не можна ходити назад. Платформа-широкий корпу перетинає кожен тенант, тому Кожен запис приписується до того, що він володіє, а не оператора. Тільки ідентифікатори логуються, ніколи не вміст. **************************************************************************************************************************************************************************************************************************************************************** вести свої ряди для запису, які були в них.
· kamo-signer-monorepo
Публічний брендований цит/останційний документ на /{locale}/q/{token}
Поверхня замовника для системи котирування торгівлі. Сервер, що працює так Брендування org в першій фарбі — небрендований спалах на комерційному документі Саме те, що це не повинно зробити, і тому сторінка видає бренд на замовлення властивості в режимі онлайн через ЦитуватиБрендВари, а не стрибаючи їх після гідратації. Живе в камо-підставнику, тому що додаток вже має нагоду HostRegexp, автосертифікат покриття, DNS псевдоніми та тематичний пакет з hostnameOverride цитата -> приймати -> e-sign потім один хмелю, так як EsignGenericEnvelope зв'язується з будь-якими запис через (контекст тип, контекст id). Відправляючи це було тільки життєздатним після /{locale}/ i18n work landed; всі 31 рядки є переклад ключів, що виводяться з словника. Введіть номер мобільного, який Ви вказали при укладаннi договору з банком - для ідентифікації. Серверно-розчинний часовий пояс (попередній учасник -> org -> UTC), ніколи не пристрій перегляду. Термін дії, що надається в неправильній зоні, може назвати дату, на якій пропозиція вже мертвий. Додайте перший реальний блок друку платформи @media. "Принт Інвойс" в камо-інтерналі завжди друкується весь додаток хромом, тому що немає @mediaprint правило існувало в будь-якому місці; тут же розмітка друкується як чистий документ Листа з брендом акцент збережений (print-color-adjust: точний — безбарвний цитує як проект), пригнічена стрілка дії, а також стор.-всередині: уникнути на ряди і всього. Термінові стани терміналу навмисно асиметричні: EXPIRED отримує чесну брендовану сторінку Нагадати дату та контактні дані org, безпечно, оскільки телефоніст вже доведено володіння 256-бітним токеном; невідомий/відкликаний/wrong-org всі крапки до одного загальні сторінки, щоб поверхня не була прокладена. Клієнт відбілює причину перед рендерингом. Випробувано, що ви не подорожуєте в URL-адресі — сервер, який вирішить його в тіло, і BFF пересуває реальний клієнт IP прямо тому, що марки APIService X-Forwarded-For з власного запиту, який інакше кладуть глядач в одному режимі-лімітному відро, що закривається на под IP. Додаток SECURITYSERVICE URL до карти налаштувань (перевірено: kamowssecurity-service існує у просторі ім'я камо.
· SecurityService
Quote REST surface — staff management and public share links
Staff endpoints at /api/security/commerce/quotes and an unauthenticated resolver at /api/security/public/quotes. QuoteController extends BaseLosController rather than copying POSController's preamble: CallerSessionResolver accepts the X-OTK attribute, the X-***-Token header AND the *** cookie, where POSController's private getOrgId reads only the OTK attribute. Every handler is rights-gated (VIEW/MANAGE/SEND_QUOTES). Most of the commerce surface is session-only — any authenticated member of any org can mutate orders — and that is deliberately not repeated here, because a quote commits the org to a price in front of a customer. QuotePublicController needs no security-config carve-out: the Spring chain is anyRequest().permitAll() and OTKPreAuthFilter only acts on an X-OTK header, which a browser following an emailed link never sends. Design points: - The token arrives in the POST body, never a URL. APIApp.forward() logs request lines, and a bearer credential in a path would land in those logs. - Not an enumeration oracle: unknown, revoked and org-mismatched tokens all return one indistinguishable generic failure. Only EXPIRED gets a specific, honest answer, which is safe because the caller already proved possession of a 256-bit token. - The org derived from the request host is cross-checked against the org on the link row. Without it, a valid link for org A opened under org B's host would render A's pricing wearing B's branding — a phishing primitive. - no-store / Referrer-Policy: no-referrer / X-Robots-Tag: noindex on every response. The page loads logos from theme.<org>, and a Referer would carry the token off-origin. PublicLinkRateLimiter is Redis-backed because SecurityService is multi-replica — in-process counters would be a limiter in name only. It is explicitly DoS and log-hygiene protection, NOT the anti-guessing control: 256 bits of entropy is. Failures are counted far more harshly than successes, since one office opening a forwarded quote fifty times is normal while fifty misses is not. It fails open, so a Redis outage cannot take the quote page down. QuoteEmailClient reuses the EmailService transactional path (X-Internal-Auth, QUOTE_SENT template) and sends only the headline figure plus the link — never the itemised pricing, so a forwarded email is not itself the disclosure. Pre-existing test failures unchanged by this commit (verified by stashing this work and re-running on clean HEAD): **************** NPE on a null EntityManager, and the legacy com.retval SecurityServiceApplicationTests missing a @SpringBootConfiguration. REQUIRES a KamoInitializerService run before these endpoints work: the quote tables are new and ddl-auto is none here, so the service boots normally and only the quote endpoints 500 on a missing relation until KI has run.
· kamo-shared-library
Quote/estimate domain — entities, pricing engine, share links
Adds a first-class Quote alongside the existing commerce spine. The pre-existing "ServiceQuote" is an Intent plus a JSON blob carrying one offering and one flat amount, with no recipient, no expiry and no UI; it is not a foundation. Extending Intent directly was rejected too: commerce_intents is shared by LOAN_APPLICATION, RENTAL_REQUEST, SUBSCRIPTION_SIGNUP and PURCHASE_REQUEST, so ~25 quote columns would put permanent NULLs on the mortgage and rental paths. Entities **************** Quote engagement-linked, versioned, valid_until + valid_for_days QuoteLineItem snapshots name/sku/price so a sent quote never re-prices QuoteShareLink bearer credential, SHA-256 at rest, revoke/expiry/view counts QuoteLinkView per-open audit (ip, user-agent) QuoteEvent append-only lifecycle trail Totals are server-authoritative. QuoteTotals is the single writer of every money field and the request DTOs carry no totals at all — deliberately unlike createRetailOrder, which takes subtotal/tax/total verbatim and can be handed a populated order with total = 0. Line discounts apply before the quote-level discount, discounts can never exceed their base, intermediate maths stays at scale 4 and only the grand total rounds to the currency's minor unit. Share tokens: 32 bytes of SecureRandom as 43 base64url chars (256 bits). Same entropy as the e-sign signer token but 21 chars shorter, keeping the emailed URL under the 76-char plain-text wrap limit. Only the SHA-256 is persisted. Tax is honest rather than invented: the platform has no tax engine (TaxClass/ TaxZone/TaxRate are authorable and read by no calculation), so ENGINE mode reports NOT_CONFIGURED instead of fabricating a figure on a commercial document. QuoteLineItem.taxClassId is UUID, matching TaxClass's real PK — Offering.taxClassId is a Long against a UUID-keyed table and is structurally unresolvable. Also: rights 178-180 (VIEW/MANAGE/SEND_QUOTES) and the QUOTE_SENT canonical email template, registered in CANONICAL_KEYS (absent there means a permanent 404). 35 tests covering the pricing engine and token hygiene. Full suite: 896 passing. Schema note: these are new tables. KamoInitializerService must run before SecurityService serves the quote endpoints — ddl-auto is none there, so the service boots fine and the endpoints 500 on a missing relation until it does.
· KlusterServices
Егресний склад для аватарного розчинника, як CiliumNetworkPolicy
Reinstates what 8f6c672 reverted, в єдина форма, яка фактично працює тут. Попередня спроба не вдалося, тому що звичайна мережа топологія кластера. Три критичних залежностей у сфері безпеки вузол, не в под-мережі — cockroachdb-0 і nats-k1m1-0 запустити hostNetwork, podSelector ніколи не відповідає їм. Про нас ненав'язлива частина, і причина, що перша спроба патч також не вдалося, це те, що ipBlock для підмережі вузла не фіксує його або: Cilium класифікує вузол як Зарезервований хост/реот-нед, і правила CIDR свідомо не відповідають працевлаштування Зручності є єдиною структурою, яка виражає її. Обидва режими відмов були відтворені проти кисневого канарного пода перед написанням це, не проти виробництва. Канаріат переніс однакове правило, встановлене під мітка, яка є те, як версія ipBlock була спіймана мовно блокування CockroachDB, NATS і MinIO, які чудово виглядають. Перевірено на канарі, потім підтверджено на Служби безпеки без перезапусків і не помилки підключення: AllOW dns, crdb:26257, nats:4222, minio:9000, redis:6379, siblings:80, світ:443 БЛОК вузол:22, вершина:443, kube-api:443, redis-via-node:6379, 169.254.254, петляback:9000 Останній чотири - точка: SSRF в розчиннику тепер не має ніде йти. Про нас в-коді охоронець залишається основним управлінням — це єдиний шар, який розуміє DNS rebinding — і це захист за ним. Заголовок здійснює канарну процедуру. Будь-які зміни цього слід перезапустити його досить ніж причина про це; модель ідентичності Cilium не заважає шлях рівнини NetworkPolicy intuition пропонує, і там немає оточення.
· kamo-internal
Покажіть обличчя для групових розмов
Нитка з п'ять чоловік на ній була представлена однією довільною особою, яка читати як повідомлення від однієї особи. До трьох учасників тепер перекриття, тому «необхідні люди» легені на погляді без необхідності розпарювати лінію імен. Збитий на три: минуло, що кола усаджують нижче впізнаваності і ряду стає фактурою, а решта вже зазначена в текст "і N інші" праворуч від нього. Читач відфільтрований з власного переліку ниток, а інший учасник — особи, які читають зліва направо, тому первинний кореспондент повинен бути найнижчим і один несучий непрочитаний значок. Кожна особа отримує кільце в рядку фоновий колір; без нього стек подібних фотографій об'єднує в одну форму. Постанова тепер охоплює перші кілька учасників, а не тільки лідера, В іншому випадку другий і третій особі сидять як монограми назавжди.
· SecurityService
Інструмент ланцюга, перезаряджається записів, розкриття записів
Кожен режим відмови в цій функції мовчить. Засувний вимикач, працівник черга відхилення від кожного завдання, провайдера, який почав повертати HTML — кожен погляд точно так само, як "це кореспондент не має фото", що також є правильним як виглядає поведінка. Не існує різниці користувачів повністю мертвий, тому його потрібно виміряти. Метрики (Prometheus вже проводилася, тому це переважно напою): удар кешу співвідношення, тривалість ланцюжка позначений ярусом, який відповів, per-provider hit/miss, глибина черги працівника і загальний дисконт. Що раніше використовується DiscardPolicy, яка занурюється безшумно за дизайном; тепер піднятий лічильник, і Проголошується лічильник перед виконавцем, оскільки польові ініціатори працюють в замовлення джерела і повторення на захоплення лізи буде розірватися на нешкідливому порядку. Розкриття йдуть на свій власний логгер. Тільки ярус ідентичності є особистим розкриття — доменні яруси передають правою стороною адреси, яка ідентифікує не один — і він записується перед дзвінком, а не після того, щоб так було стежка існує навіть тоді, коли запит не вдається. Адреса письмова в повному обсязі навмисно: точка полягає в тому, щоб відповісти на "які були дані цієї особи, які поділилися з", і не можна відповісти на це. Реапер закриває витік: removeExpiredBefore і нічого не назвав його, так що виросла на будь-який час. Бідна поштова скринька торкається тисяч кореспондентів Одного разу і залишає негативний ряд за кожним. Тести покривають фетчер проти реального розетки, оскільки цікаві випадки всі поведінки провайдера, а не логіку: 404 проводить дійсне зображення (DuckDuckGo), м'який-404 сервірування HTML, походження підпорядкований контент-Length, a 1x1 stub, і перенаправлення, спрямоване на подмережу. Клієнт не може бути вказаний на сервері тестування петлю зворотного зв'язку - його DNS шпилька відмовляється вирішити що-небудь приватний, який є цілою точкою — так що ті, хто чинить проти розслабленого клієнта і шпилька стверджується окремо.
· kamo-internal
Сприяє відновленню матриці LLPA в налаштуваннях з консолі
Панель для запліднення може публікувати лише пропис. Для джерела LLPA MATRIX документ тепер показує картку "Промоте як LLPA": оберіть існуючий номінальна версія LLPAs регульована (+ додаткова група), і кожен затверджений FICO/LTV відро стає умовним регулюванням цін. Як результат багато були авторовані і, чесно кажучи, скільки рядків були пропущені через відро не можна прочитати безпечно або вже презентувати. JavaScript licenses API Веб-сайт Go1.13.8 пости на нову реле воріт.
· SecurityService
Реле шлюзу для просування матриці LLPA в умовні налаштування
**************************************************************************************************************************************************************************************************************************************************************** Сприяти реле листа: god-eligible gate, організаціяId server-stamped на перезавантаження через запис (), вниз потік 4xx відредагований дієслово. Дозвольте steward повернути рецензована матриця LLPA в реальні регулювання ціни на основі консольу.
· VOIPService
Запис дзвінків, голосова пошта та перегляд доступу
Запис відтворення вліво не слід. Зафіксований дзвінок є щільним PHI Магазини платформи — нередактна бесіда — і «який слухав до цього §164.402 порушення оцінка просить. Дроти CallRecordingAuditor в кожну прочитану, яка розкриває її: - GET /записи/{id}/audio CALL RECORDING / ЗАРАЗ *********************** CALL RECORDING / ЗАРАЗ - GET /записи/{id} CALL RECORDING + TRANSCRIPT / ПЕРЕГЛЯД *********************** CALL RECORDING / ЗАРАЗ - GET /instances/{id}/voicemail TRANSCRIPT / LIST, за ряд Розшифровка є тим, що приховує. Це не медіа завантаження; він їде всередині метаданих JSON і всередині кожного рядка голосової пошти, і це те ж саме PHI як аудіо у вигляді, яка затирає. Він отримує власний захід, оскільки облік розкриття зібрано на ресурс. Byte, що обслуговується, не закривається, тому PhiAuditAvailabilityAdvice перетворює нелогічно читати в 503 замість 500 — запит був дрібним, ми декодуємо ми не можемо врахувати. Бібліотеки записуються занадто; проблювання Що таке виявлення. Також закриває зазор авторизації, знайдений під час проводки: POST /записи/lookup взяли на себе екземпляр перевірив Юридичну фірму абонента, тому вона вирішила інший провайдер зателефонуйте кришки до запису. Кожен інший екземпляр-скопд кінцевої точки в служба вже йде через FindByIdAndOrgId; це зараз теж. Запис авторизації відтворення залишається як-і, так і задокументовано в місці: org право власності є єдиною перевіркою, тому будь-який учасник може відтворити будь-який запис їх орг. Вузьке це означає, якщо "поширення" є крайові та які праві підйомники — це рішення про продукт, не Здогадайте, щоб зробити тут, і кожен доступ принаймні записаний зараз.
· AIService
Запис PHI доступ до кожного читання історії розмови з ВІЛ
Дроти спільного §164.312 (b) обертаються на шляхах, які прочитають персистовані підказки і завершення. Помічник - модуль оцінки відповідності OUTSIDE крайові — підказка від вентилятора до зовнішніх постачальників без BAA та Чи зберігаються в певному порядку — так читає цей магазин є найбільш розкриттями в не було. Аудит: список та пошук історії (одна подія за бесіду, не один за запитом), метадані однієї розмови та її повідомлення, громадськість Віджет читання власного трафарету назад, а ручний пакет. Бібліотеки записано занадто — пров’язуючи ще одну пороги org — що виглядає виявлення — і неаутентифікована спроба приписується до відправника org замість скидання, Оскільки рекордер відхиляє те, що він не може бути атрибутом і це подія найбільшою варто тримати. ЗАМОВИТИ ЗАМОВЛЕННЯ, НЕ ПЕРЕГЛЯДУ: він несе відвідувачів розмова з AIService та перед людиною в іншому продукті. Що не закривається, тому загублений запис зараз, затримуючи розшифрування і відповіді 503, а не обслуговує дані, які не можуть обліковуватися. Виявлення тільки. Ніколи тіло повідомлення, назва або термін пошуку - учасник пошук історії помічника, вид на ім’я позичальника в неї, і Аудиторський шлях, який відтворив підказку, просто перемістив PHI в PHI Увійти потік. Завершується d428ee3, яка одночасна сесія перекриває середню зміну: аудитор був відсутній записDeniedInternalView, і PublicAiChatController новий аргумент конструктора не досягнув свого випробування.
· MediaService
Record chat message reads on the endpoints that return bodies
Sending a message left a row; reading one left nothing. Every chat, support and social thread on the platform renders from a handful of endpoints here, and none of them recorded anything, so "who read this conversation" had no answer — which is the first question a 164.402 breach assessment asks. ChatMessageAccessAuditor emits a PhiAccessEvent (CHAT_MESSAGE) from the five paths that hand a caller message text: GET **************** LIST GET /api/media/sessions/chat LIST POST **************** VIEW GET **************** LIST POST **************** VIEW One event per message, not one per request. "They opened the thread" is not an answer to "was this individual's message disclosed", and the message ids are already in hand at every call site, so a request-shaped row would have been a choice rather than a limitation. The thread read records AFTER the mute filter, so a row means a body that caller was actually handed. The chat list is in scope because each row carries up to 140 characters of the thread's last message — that is content, not metadata. Rows with an empty preview record nothing. Deliberately NOT recorded: unread counts, presence, last-seen, typing, read receipts, session-member lists, mutes, ticket detail (metadata plus status history, no bodies) and support reporting aggregates. A trail is only useful if a row means someone saw content; rows that stand for nothing bury the ones that do. Refusals are recorded too, against the thread guid — no message id exists yet at the point of refusal, and repeated refusals against thread guids is the shape probing has. An unauthenticated reader is attributed to a sentinel org rather than dropped: the recorder rejects unattributable events, and that is the single most interesting event this trail can hold. Client IP comes from X-Forwarded-For with remoteAddr as fallback — everything arrives via Traefik, so remoteAddr alone records the ingress pod. Public chat takes a second hop through APIService, which sets X-Forwarded-For to the visitor address and moves the browser's User-Agent to X-Original-User-Agent, so the auditor prefers that header; the literal User-Agent on that hop is APIService's own HTTP client and identifies nobody. Visitor reads are attributed to the org from X-Public-Chat-Org-Id with no member id: a visitor has no member identity of their own, but the org owns the records, so the read stays attributable. Identifiers only, never message text. An audit trail that reproduces the message it audits has just copied the PHI into the log stream. Also completes eed3817, which swept this work in mid-edit and left MediaController referencing PhiAccessKind before the import existed — that revision does not compile. This one does: mvn -o test is 16/16 green.
· DocsService
Записувати байтовий доступ на чотирьох шляхах документа, які записували нічого
/завантажити вже увійти через *********** і це був веб-сайт, www.te-access. Шнурні кінцеві точки, що подають точні ж байти — /stream, /bulk-download, шаблон перетворений-PDF і сторінка шаблону thumbnail — записано нічого, тому будь-який хоче документ байтів не залишаючи слідів, щоб отримати іншу URL-адресу. Всі чотири тепер випромінюють PhiAccessEvent на місці доступу було перевірено та перевірено байти про подачу. Завантажити букмекера випромінює одну акцію за документ, а не одну за запит. "Ай експортується 400 документів - це не відповідь на "відповідає цей обліковий запис" розкриті, і ряди документів, які роблять відповідь на шість років пізніше під §164.528. Клієнт IP отримує від X-Forwarded-For з віддаленимДодатком, як спадок: кожен запит прибуває через Traefik, так що дистанційнийДодаток, тільки записує подряпинний под для будь-який доступ і бути гідним для виявлення. Неаутентифікована спроба приписується до організації відправлення, а не скидання — рекордер відхиляє неприпустимі події, а запит на документ байти без сеансу – це саме подія, яка повинна триматися. Це sits поряд з існуючими ImgLogЗавантажити рядки замість їх заміни: це перехресний причіп обліку розкриття зібрано з. Примітка ImgLogService, який читає ті рядки, все ще має нульові дзвінки в будь-якій точці платформи.
· KlusterServices
Збережіть егрес від аватарного розсмоктування; зауважте, що Redis eviction pool
Служба безпеки тепер працює фетчером, цільовою URL-адресою якого вибрано ненадійним вечірка — запис BIMI опублікований тим, хто володіє доменом відправлення, і хтось стає відправкою домену, по електронній пошті. Ніщо в цьому кластері перенапругою, де такий запит може піти: Відповіді Redis неупереджені на 6379, MinIO на 9000 з кореневими показниками, CockroachDB на 26257 та метаданих вузлів кінцева точка досягається від будь-якого под. Вирішувач зобов'язується самостійно керувати в коді, а ті, хто залишається первинним захист, оскільки вони є єдиним шаром, який розуміє перев'язування DNS. Це друге, тому не можна дістатися до приватної адреси. Поглиблено дозволяйте більшості випадків, а не допускати. Ці послуги законно досягають ведучі, тому захоплюючі місця будуть незадовільні і будуть розірватися тихо. А замість того, як він отримує публічний інтернет з кожним приватним діапазоном, крім того, потім повторно перераховує конкретні порти, які фактично потрібні. Скопіювати до под що виконувати ненадійні fetches — застосувати його простір імен буде відрізати послуги, які ніколи не перевірили. Зміна Redis є коментарем та базами даних, не зміною поведінки. Він записів, чому кеш-пам'яті відправника-автара зберігає лише короткі рядки метаданих: maxmemory 2gb з allkeys-lru evicts по всій інстанції, і DB 0 тримає кожен жив сеанс, так що об'ємний кеш-пам'яті тут буде виводити користувачів на випадковому під тиском і бути неоднозначним протягом доби.
· kamo-internal
Показати відправник і фотографії одержувача
У поштовій скриньці надано окремий лист на один загальний градієнт для всіх, тому кожен ряд виглядав однаково і коло не несе інформації. Зараз показує фотографії кореспондента, коли один відомий, і дволеттерна монограма, коли він немає. Один SenderAvatar замінює сім ручних початкових кола. Що стосується більше консистенції: кожен переніс свою ідею, як розбити адресу, і аватарний кеш, що закривається на цей розщеплення, тому будь-яке незгоду між переліком і читати пане мовчазно занурить удар і покаже ту ж людину дві різні способи на одному екрані. parseAddress тепер єдине місце RFC 5322 адреса береться окремо. Список і види ниток також зупиняють друк сирих заголовків як "Jane Doe <jane@acme.com>" і показати ім'я. Ідентифікація життя власному магазині, що ведеться за адресою. Повідомляйте всі 30-ті та на кожному веб-додатку, кожен раз Заміна масиву повідомлень оптом — що-небудь зливається на повідомлення буде витріть двічі на хвилину, так що свічка в скриньці бажать фото на монограму і назад назавжди. Клавіатура за адресом також означає пізній відповідь не може пофарбувати на виворітний ряд, тому що ряди не те, що він закривається. Запити на вугілля в одну партію на екран: п'ятдесят рядків, які просять самостійно, буде п'ятдесят запитати, і так як кожен дзвінок на цю послугу заміняє перший ключ, насправді сто. Після 45-х, через сервер роздільна здатність - двофазна і невідома адреса відповіла тільки на пізній дзвінок. Конверситація СписокView тепер віртуалізації. Підходить 50 рядків на сторінку і повторно всі вони всередині AnimatePresence з периндексом, що на кожному питанню; додаючи зображення до кожного зробленого ним поверхні в поштовій скриньці. Відправки без реплів та листівок-дамонів отримують нейтральну позначку, а не монограму — face beside a bounce помітка є активно misleading. Фотографії декоративні (alt=""), тому що ім'я завжди видно текст, що вони знаходяться, і перевозять linkrpolicy="no-referrer" так ідентифікатор нитки ніколи не досягає образу. Кожен аватар подається з власного походження — сторонні зображення подаються, Випробувано новий сервер-захід — який дозволяє отримати новий запит Політика конфіденційності img-src передається на власні домени орендаря. Що будується політика проксі замість наступного. Налаштування, оскільки ця платформа біло-розкладена: статична політика повинна називати одну десятку і розбити зображення для відпочинку. Він також закриває до-випробування збережених відстежувань-пікселів, так як Контакт. ФотоУрл це безкоштовний URL-адреса, що надається безпосередньо в декількох <img src>. next/image не приймає дистанційного SVG. Це був прийнятний ризик, коли тільки SVGs були власні тематичні логотипи; це не зараз, що позначки платформи опубліковано в сторонніх DNS. Зв'язки абонентів знизили жорсткийкодований ORG ID = 1 і параметр orgId запиту, узгоджуючи зміни задньої частини, що тягне за собою від сеансу.
· EmailService
Avatar endpoints; fix unauthenticated reachability and contact tenancy
Adds the mailbox side of sender avatars, and fixes three pre-existing holes this work would otherwise have built on top of. AUTHENTICATION. OTKPreAuthFilter used to reject a *bad* OTK but treat *no* OTK as anonymous-and-allowed, falling straight through to the filter chain — and the Spring Security chain here is anyRequest().permitAll(). Every mailbox, contact and calendar endpoint was therefore readable by anything that could reach the ClusterIP. Protected prefixes now fail closed. The fix lives in the filter rather than in the security chain deliberately: reshaping the chain would touch thirty unrelated surfaces at once, including two servlets and the DAV endpoints. The exempt list is the complete set of genuinely session-less entry points — the CAN-SPAM opt-out link, the OAuth redirect target where the tenant rides in the signed state parameter, and the server-to-server surfaces that authenticate with X-Internal-Auth. CONTACT TENANCY. Every contacts endpoint took orgId as a query parameter, or reached a book by id with no ownership check at all, so changing a number in the URL read another tenant's contacts — names, addresses, phone numbers, notes. The org now comes from the session and every book- or group-scoped operation proves the target belongs to it. Absent targets return 404 rather than 403 so an id in another tenant is not confirmed to exist. orgId is still accepted on the two list endpoints and ignored, so clients do not break mid-deploy. That change also fixes a silent bug: searchContacts derived orgId from bookId and passed null when no book was selected, into a query whose first predicate is contactBook.organization.id = :orgId. Book-less search therefore always returned nothing — which is exactly how the mail recipient autocomplete calls it. EMAILLOGOSERVICE. It fetched an operator-supplied URL with no scheme or address check, and transcoded the result on a Batik that resolves external references by default. A logo SVG containing <image **************** would have been dereferenced from inside the cluster. Now guarded on both ends. MESSAGEINDEXER. resolveMemberIdFromEmail pulled the entire members table into heap and filtered it in Java, once per indexed message, on a 1Gi pod — the code said so in a TODO. Same semantics, one indexed query. The avatar surface is one batched endpoint rather than a field on the message DTOs. Both list views poll every 30s and replace their message array wholesale, so an avatar carried on a message would be wiped twice a minute and the UI would flicker forever; and EmailMessage is shared by the folder list, reading pane, thread view and search, so changing its shape would touch all of them at once. The directory-photo endpoint is server-to-server only — exposed to a browser it would be a directory-enumeration oracle for the tenant.
· SecurityService
Sender-avatar resolution chain for the mailbox
Resolves a correspondent's email address to a picture, working outward from what Kamo already knows: member photo, then a photo someone attached to a contact, then the tenant's connected Microsoft/Google directory, then the sender domain's BIMI mark, then its favicon, then Gravatar. Anything unresolved renders a monogram, so the chain always terminates locally. The directory tier is worth calling out: the connect flows here already request admin.directory.user (Google) and User.ReadWrite.All + Directory.Read.All (Microsoft) alongside the mail scopes, so for Workspace and 365 tenants this returns authoritative photos with no re-consent and no third party involved. It should beat anything on the public internet and usually will. Two phases, never one. A request reads cache only; unknowns go to a bounded worker with DiscardPolicy — running an overflowed task on the caller would hand a request thread to a third-party host, and a discarded resolve costs nothing because the next poll asks again. A full-miss chain is DNS plus four HTTP calls, and a page carries dozens of addresses; nothing about opening a folder may depend on third-party availability. Decoupling also keeps resolution from correlating with a human opening a message, which would make it a read receipt — the exact behaviour the mailbox already blocks by default for remote images. This is the platform's first fetcher whose target URL is chosen by an untrusted party: a BIMI record is DNS content published by whoever owns a sending domain, and anyone becomes a sending domain by emailing a tenant. There is no egress NetworkPolicy and no forward proxy, so the controls are in code. SafeImageFetcher pins DNS — a custom resolver hands OkHttp only the addresses that passed PublicHostGuard, closing the rebinding window that defeats a naive pre-flight check — refuses redirects, caps bytes as they stream rather than trusting Content-Length, and requires an image content-type. SvgSanitizer parses and re-serializes against an allowlist instead of rasterizing. Batik 1.17 resolves external resources by default, so handing it a hostile SVG would dereference <image **************** from inside the cluster after the URL check already passed. The Tiny PS profile forbidding that is a statement about conforming files, not about bytes fetched from an attacker's URL. Provider miss semantics are all different and all cache-poisoning if treated as hits: Gravatar is asked with d=404 because every other default returns 200 with a placeholder; Google's no-match is a 404 carrying a byte-identical globe, so it is rejected by content hash; DuckDuckGo returns 404 with a real image body, so status decides. Bytes are re-hosted under a random name — never one derived from the address, which would let anyone probe whether a given person corresponds with this platform — and served through an authenticated route. Redis holds metadata only. That instance is 2GB with allkeys-lru on an emptyDir, sharing a keyspace with every live session; caching image bytes there would evict sessions and sign users out at random.
· kamo-shared-library
Sender Identity model + org-scoped партії електронних листів
Резервне зберігання та запити для відправки поштових скриньок SenderIdentityEntity – міцний ярус кешу аватара. org id є частиною EnglishDeutschPусский简体中文中國傳統EspañolالعربيةFrançaisελληνικάDanskАнглійскаябългарски провайдер, тому відповідь, отримана від десяткових даних, не повинна бути видима на інший тенант. Відповіді на зовнішні рівні (BIMI/Favicon/Gravatar) дійсно глобальні та Поділитися з відправником org, щоб кожен десятець поділився швидкістю удару. Місця зберігаються як ряди, не відсутні — без цього, кожен нерозчинний відправник переходить на весь Мережа провайдерів на кожному блоці inbox. OrgAvatarSettingsEntity розбиває ланцюг, що насправді залишає будівлю. За замовчуванням ідентичності OFF, оскільки він розкриває дайджест кореспондента повна адреса третьої сторони, яка на кредитування CRM є рішенням про позичальник ідентифікатор, а не перевага відображення. Репозиторійні добавки існують, тому що жоден з них не досягається: - Зв'язатися з намиРепозиторій не мав ніякого вигляду за адресою - тільки substring LIKE для автозаповнення — так зв'язок, що мав фото, не можна вирішити з З: заголовок. - Часті пошуки членів/користувачів є org-scoped і приймати до-нижчий вхід. LOWER() застосовується тільки до збереженого стовпця; електронні листи зберігаються дієслово (EmbEmail не має нормалізатора) і CockroachDB рівноправність є випадковим. - Аватар-ідеальні проекції повертаються ids, а не суб'єктів з метою. І Учасник.avatar і User.avatar є мереживними асоціаціями на ієрархію JOINED: Зателефонуючий за межами угоди отримує LazyInitializationException, і один всередині отримує базовий тип проксі, який ніколи не звужує до AvatarPhoto, що надягає файл розширення потрібного для створення URL-адреси з точки зору досягнення. ****************************************************************************************************************************************************************************************************************************************************************************** замінює пошукВсі() повний графік сканування, який ран один раз за індексоване повідомлення. PublicHostGuard поділився не дублюється, оскільки це безпека контроль: вирішує, чи є адреса десь, ми надішлемо запит, що ненадійна партія обрана. Випробувано проти реальних методів обходу — IPv4-збитих IPv6, 6to4, NAT64, CGNAT та посилання-локальні метадані. Право 177 воріт розкриття рішення.
· kamo-shared-library
Audit spine for PHI access — §164.312(b)
The Security Rule requires recording access to ePHI, which means reads. The platform records changes well — LeadHistory, SystemAccessLog, UserHistory, LoanAuditEvent — and reads almost nowhere, which is why "who viewed this record" is currently unanswerable. That is also the first question a §164.402 breach assessment asks, so this one gap blocks both the audit control and the four-factor analysis. Capture layer only; no schema. The durable store sits behind PhiAccessLogWriter so call sites can be wired now and the sink can evolve — plain table, then append-only with a hash chain, then a signed export to object-locked storage — without rippling back through hundreds of call sites. Two properties carry the weight: - Failure handling belongs to the access kind, not the caller. EXPORT, DOWNLOAD and DISCLOSE fail closed: an unlogged bulk export is exactly the event you cannot reconstruct afterwards, and "we served the data but lost the record" is the worst answer to give an investigator. VIEW, LIST and SEARCH fail open and log loudly, because losing one line is not worth taking the product down. That asymmetry is deliberate and wants signing off rather than assuming. Callers under pressure resolve policy questions in whichever direction unblocks them, so the policy is not at the call site. - A denied read is still a read. Refused attempts are recorded, because the access pattern of someone probing records they cannot reach is what detection needs and is invisible if only successes are logged. Startup safety, which nearly went wrong: PhiAccessRecorder is a @Component and every service component-scans com.kamo, so a hard dependency on a writer bean would have failed context startup across ~40 services at once — a whole-platform outage from a feature nothing had called. The first fix, a @Configuration with @ConditionalOnMissingBean, does not work: component-scanned configuration is processed alongside user configuration rather than after it, so both writers register and injection fails on ambiguity. PhiAuditContextWiringTest caught that. The fallback now lives in the recorder via ObjectProvider.getIfUnique, where no ordering question exists, and ambiguous writers degrade to the default rather than failing startup. The default Slf4j writer is a starting point, not the destination — log lines are not tamper-evident and retention is 14 days against a six-year obligation. It exists so call-site wiring does not wait on the store. Identifiers are logged, content never is: an audit trail that reproduces the record it audits has just moved the PHI into the log stream.
· SecurityService
403, а не 500, коли обмежена кількість відмов
Два сайти викликів функціїService.enableFeature тепер розуміють межу HIPAA: - /enable карти PhiModuleNotPermittedException to 403 перенесення причини, віддзеркалення прикладної моделіВідеокремленняОбробляється безпосередньо над ним. Без категорії Цей широкий лов нижче перетворив свідому відмову в політиці 500. - Автознімна петля у списку дощільнювачів з isPhiPermitted і лижі. Це працює над кожним завершеним сервісомType під час merely *listing* Особливості організації, що кидають на першому заблокованому модулі сторінки функцій, що вивантажуються для PHI, замість того, щоб приховати один запис. Вставити сьогодні — кожна організація ручитьПі=false.
· kamo-shared-library
Закріпити ліміт відповідності при перемикачі функції
Дроти PhiTenantGuard в ФункціональніПослуги, єдиний пункт курка через який Модуль перемикається на організацію. Це там, де крайові зупинки політико-правовий об'єкт і починається виконання. І половинки, так як або поодинці залишає зазор: - Увімкніть FiModuleNotPermittedException, тому PHI орендаря не може Переключення на модуль Kamo не може стояти за бізнесом. - isFeatureEnabled(Організація, ServiceType) повідомляє модуль вимкнено, коли тенантні ручки PHI і модуль зовні кордону, що б OrgFeature ряд каже. Ряд може законно сказати активне — це було ввімкнено перед тим, як десять став тенантом PHI, і увімкніть перехід. isPhiPermitted є невиліковною формою для абонентів, які ітерують. ФункціяController автоматично вимикає всі заповнені функції при *listing*, щоб кинути на перший заблокований модуль не буде весь сайт функцій, а не пропустити один запис. PhiServiceTypeMapping binds ServiceType to PhiModule, з тестом не вдається будувати на будь-якій незрівняній вартості. Що тест заробив його тримати на першому запустити: він спійманий ServiceType.STORAGE, який був пропущений, а потім AI CHAT, DOC MANAGER, DOCS EDITOR та DOC CLASSIFIER. Без нього п'ять послуг типи були безшумні за межі — така ж відмова від бездіяльності Конструктор PhiModule закривається, переоснащений одним шаром. Нові модулі для раніше незрівнянних типів послуг, кожен з явним Призначення: зберігання об'єктів, редактор документів та класифікація, підтримка квитків, HR, інвентаризація, правовий, калькулятор і активність кормів всередині; клубний будинок і ігри БЛОКED PENDING WORK на підставах, які вони не були оцінені, що є причина блокування, а не припустити. Кожна організація ручаєPhi=false сьогодні, тому ці зміни не залежать від поведінки виробництво. Він стає навантажувальним моментом, що перший тенант закріплюється.
· kamo-shared-library
Автозабезпечити MERS-сумісний кредитний номер при створенні програми
КредитФайл.loanКількість була наголена на створення (як порожній, так і свинець-промот) і тільки коли-небудь встановлено, коли тип steward один - який твердоблокований MERS MIN minting (а 10-цифровий сегмент МІНУ Є номер кредиту) і кожен вниз ідентифікатор для безголовного кредиту. ДодатокПослуга тепер призначає номер кредиту на обох сайтах створення: чистий 10digit numeric (MinMinter strips non-digits and need a <=10-цифровий сегмент, так чистий нумерик є єдиною безпечною формою, унікальною для org через звичай (org id, кредит number) індекс з обмеженим терміном. ЗАРАЗ ВІДКРИТТЯ НА НОВИНКУ Зіткнення стейку або безоплатного репо — деградація до попереднього посібника Поведінка, а не коли-небудь перерву додатків. Лендер-постачальник номер все ще перенаречений через патч-патчовий шлях. Немає зміни схеми стовпчик вже існує, індексований.
· kamo-signer-monorepo
Терміни входу в адресний час
Ознайомитися з ESigService з зони членів одержувача, потім org, потім UTC. Ласкаво просимо переходить на форматування, тому дата закінчення залежить від ні Налаштування пристроїв перегляду, а не за замовчуванням провайдера UTC. Виготовлення поля необов'язково спійманий на одному літровому місці (preview.ts) у часі компіляції. Також: - виклик setRequestLocale в локальному макеті, щоб переклади зв'язалися з URL відрізок, а не спираючись на головку середнього програмного забезпечення - стверджувати в Dockerfile, що повідомлення/ пережили `turbo prune`, і документ чому .dockerignore повинен тримати .gitignore з контексту збірки; без цього муфта призупиняє переклади та зображення суден, що надають сирі ключі з нічого не вдається до моменту відкриття реєстраційного документа
· ESigService
Зарядити таймер відображення таймера від учасника, потім org
В будь-якій зоні клієнт за замовчуванням, тому конверт, expiring 2026-08-03T05:00Z може прочитати "Aug 3" на Тихоокеанський знак для кого посилання вже загиблий на вечору серп. 2. SigningSession тепер несе сервер, що замінює IANA timeZone. власний член.timezone, коли вони є членом і мають один, інше відправлення Організація.timezone, інші UTC. SignerZone - це чистий розчинник з тестами, включаючи всі карти TimezoneType у власній зоні не може відправляти клієнт-за межами RangeError. Також фіксує SigningSession.locale, яка введена в дію імена («SPANISH») замість коду BCP-47 ("es") використовується в локальному сегменті URL-адреси.
· InitializerService
Створіть HANDLES PHI та PHI EFFECTIVE DATE на orgs
Дзеркала двох нових організаційних полів, за допомогою OrgBrandingFieldsMigration конвенції, тому стовпчики відтворюються на будь-якому середовищі, а не тільки існуючий де відбувався ddl-auto. HANDLES PHI не є NULL DEFAULT FALSE, тому існуючі орендарі явно зовні ліміт відповідності. PHI EFFECTIVE DATE TIMESTAMP, не TIMESTAMPTZ, Оскільки поле суб’єкта господарювання є LocalDateTime. Тест - це охоронець дрифта, а не решта: він читає імена стовпців суб’єкт господарювання шляхом відображення та невиконання структури, коли суб’єкт господарювання не має ALTER. Що є фактичний режим відмови конвенції — хтось додає поле, забуває поле міграція, і з ддл-ауто:он в послугах, які вона поверхнями як виробництво похибка запиту замість часу збирання. Перевірено мутації: видалення PHI EFFECTIVE DATE АЛТЕР не дає повідомлення, відновлюючи його йде зелений. У кластері вже присутні стовпці, які є демппотентом.
· kamo-shared-library
Персистські ручкиПі та фіЕффективнаДата про організацію
Backs PhiTenantGuard з реальним стовпцем. HANDLES PHI НЕ NULL DEFAULT FALSE next the ******** візерунок, тому кожен існуючий явно за межі відповідності, а не мовчки всередині нього. PHI EFFECTIVE DATE об'єднує оцінку порушень та зобов'язання щодо збереження Правове вікно — «звідси, коли» — перше питання, яке запитало після «відкритого». Перетворення в політику з *********** охоронець сам залишається безкоштовним суб'єктом господарювання, тому абонентський холдинг тільки засвідчений прапор не потрібно навантажувати ряд. Сейфінг: як стовпчики вже існують в кластері, так і кожен з 12 організації читають помилково. Перевірено на інформацію шмама перед посадкою — ручки фі boolean НЕ NULL DEFAULT false, phi real date timestamp NULL. Дивитися міграцію KamoInitializer для відтворюваної форми.
· kamo-shared-library
PhiTenantGuard та лімітування модуля
Ключниця з дотриманням HIPAA: які модулі можна досягти, за умови, чи захищена інформація про здоров’я. Про нас внизу ключі від нього — які інтеграції вимкнені, чи є MFA примусово, які сеанси отримують строгий час, який повинен закривати аудиторію. Караки не залежать від схеми. Попередня спроба вішати це від нового Організація.handlesPhi стовпці і повинні бути перевернуті: сервіс CI clones Головний в процесі будівництва, коли KamoInitializer працює вручну, тому колонка суб’єкта господарювання на основних розривах наступної служби, що розгортається до тих пір, поки хтось мігрує. Відмовлення політики від суб’єкта господарювання означає, що її землі та можуть застосовуватися зараз, і стовпчик стає незалежним кроком. Три властивості конструкції побудовано навколо: - Замкнені в’язниці. Конструктор PhiModule вимагає PhiDisпозиція і причина, тому модуль додано пізніше не може поспадкувати дозвіл на відключення — це не буде без прийняття рішення, і що інше, ніж PERMITTED заперечення. Що таке режим невиконання ліміту повинен вижити: модульні кораблі, нікому Подумайте про компанію PHI. - Нерозчинний тенант небезпечний. охоронець приймає тридержаву PhiTenantStatus, а не boolean, тому "Я не можу завантажити організацію" не може бути написаний таким же чином, як "це організація не PHI". З boolean, шлях похибки isPermitted(false, ...) — легко дістатися до, неможливо помітити в огляді. ЗНИЖКА ЗНАТИ все. - Ніщо не підніматися. Рішення є чистою функцією (статус, модуль) без caller, сеанс, право або god-mode параметр. "Наші співробітники підтримки можуть перетворювати його off" - відповідь, що не вдається рецензії суб'єкта. Розпорядження слідують скопійним аналізом в камо-інтерналі ****************************************************************************************************************************************************************************************************************************************************************************** Випробувано: CRM, контакти, документобіг, e-sign, примітки, завдання, календар, внутрішній чат, in-cluster JavaScript licenses API Веб-сайт Go1.13.8 Заблоковано безоплатно BAA: соціальна messsaging, Canva, e-commerce sync, MCP шлюз. Заблоковане закінчення названої роботи: АІ маршрутизатор, RAG пошук, записи наради, VOIP записи, маркетингові кампанії, експорт аналітики. Ніщо викликає охорону ще, тому це вставляється до дроту.
· InitializerService
Створіть HANDLES PHI та PHI EFFECTIVE DATE на orgs
Дзеркально два нових полів на суб’єкті організації в камо-Шаред-лібері, після конвенції OrgBrandingFieldsMigration. НЕ NULL DEFAULT FALSE так що кожен існуючий тенант явно поза комплаєнсом межа не мовчазно всередині неї. PHI EFFECTIVE DATE TIMESTAMP, НЕ TIMESTAMPTZ, оскільки суб’єкт господарювання є локальним ПРОПОЗИЦІЯ — це потрібно для запуску до наступного розгортання сервісу. Послуги шпильки kamo-shared-library в фіксованій версії, яка переобрано в місці, тому перший послуги для відновлення після того, як бібліотека змінює початок вибору цих стовпчиків і з ddl-auto:on в сервісах, які не виконуються до цього бігуна. Супроводжуючий тест - охоронець дрифта, а не решта: він читає стовпчик імена суб’єкта господарювання шляхом відображення та невиконання структури, якщо суб’єкт не має АЛТЕР. Що таке режим невиконання цієї цілі конвенції — хтось додає поле, забуває міграцію, і її поверхні як продакшн-повідомлення замість час будівництва. Перевірено шляхом мутації: видалення PHI EFFECTIVE DATE ALTER робить його не вдається в дію повідомлення, відновлюючи його йде зелений.
· ESigService
Визначте локальний сегмент підписки
Витягувати theбайт-for-byte дубліковані buildSignLink в SignLinkBuilder і додає локальний сегмент, що виводиться з організації.language, падаю Повернутися до англійської для чотирьох значень мовного типу без перекладів. Потрібні kamo-signer /{locale} / маршрути, щоб бути розгорнуті першими.
· kamo-shared-library
Додати ручкиPhi тенантний прапор і PhiTenantGuard
Ключниця з дотриманням HIPAA: заочний прапор плюс охоронець позбавляючи які модулі, які можуть досягати. Все вниз ключі від неї — які інтеграції вимкнені, чи є MFA примусово, що сесії отримують строгий час, який аудит хребта має накривати. Організація отримує HANDLES PHI (BOOL DEFAULT FALSE) і PHI EFFECTIVE DATE, після існуючого************************** За замовчуванням false, Отже, це інерція для існуючої іпотечної та CRM книги. Три властивості конструкції побудовано навколо: - Замкнені в’язниці. Конструктор PhiModule вимагає PhiDisпозиція і причина, тому модуль додано пізніше не може поспадкувати дозвіл на відключення — це не буде без прийняття рішення, і що інше, ніж PERMITTED заперечення. Що таке конкретний режим збою має вижити обмежену відповідність: модульні кораблі, Небо думають про PHI, клініка починає її використовувати. - Не обійтися. Рішення є чистою функцією (організація, модуль) з no caller, сеанс, право або god-mode параметр, тому немає нічого визволення. "Наші співробітники підтримки можуть вимкнути його" - відповідь, яка не вкривається Огляд суб'єкта господарювання. - відмова нести причину, тому що лезо "знімається" не несе відповідальності за підтримку інженер або замовник. Розпорядження слідують скопійним аналізом в камо-інтерналі ****************************************************************************************************************************************************************************************************************************************************************************** Представлений сьогодні: CRM, контакти, документ vault, самоhosted email, e-sign, примітки, завдання, календар, внутрішній чат, MLOS. Заблоковано без отримання BAA: соціальний обмін, Canva, e-commerce sync, MCP шлюз. Заблоковане закінчення імен робота: маршрутизатор AI, пошук RAG, записи зустрічі, записи VOIP, маркетинг рекламні кампанії, експорт аналітики. Замітка: HANDLES PHI і PHI EFFECTIVE DATE матеріалізують на наступній KamoInitializer працює, після того, як CI публікує цю спільну роботу. Ніщо читання прапор ще, тому замовлення є безпечним.

Твій всесвіт чекає.
Почати безкоштовно за декілька хвилин. Додати продукти, коли ви будете готові — без перенесення, без нових реєстрацій.
Безкоштовно назавжди — не потрібна кредитна карта