docs: правда про флаг прекращения обработки — 14 пометок в 5 бумагах, решение Р110
Бумаги проекта обещали, что флаг processing_restricted всё блокирует: особое исключение при попытке тронуть человека, охранник, не пускающий сотрудников в его карточку, «все операции обязаны проверять флаг и отказывать». Не построено ничего — флаг ставится и лежит. Рядом с каждым обещанием дописан замер «06.08.2026: не построено» с командой, которой это перемеряется. Прежний текст оставлен дословно, ноль удалённых строк. Галочка «закрыт» у Ю-9 на месте, версии в шапках не тронуты. План называл четыре места. Перечень собран заново прибором — их четырнадцать. Три самых опасных были вне списка: «реализовано через guard-исключение» в перечне сильных сторон, и два раздела ТЗ, написанных как описание готовой работы вплоть до текста заглушки и кода ответа 403. Два хвоста переданы владельцу. Первый: контрольный лист аудита 152-ФЗ в .claude/skills/pdn-152fz-audit несёт ту же ложь — путь запрещён к правке. Второй: отчёт по безопасности от 17.06.2026 остался непомеченным — сторож правописания краснеет там на пяти чужих словах, а поправить их значит удалить чужие строки. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -727,6 +727,14 @@ public function recalculate(Project $project): int {
|
||||
|
||||
**Из решения интервью OPEN-Д-1 (Прил. Д v8.2):**
|
||||
|
||||
> 🔴 **ЗАМЕР 06.08.2026 (Р110): подпись столбца ниже обещает защиту, которой нет.** Столбец
|
||||
> `processing_restricted` в базе есть. А вот блокировки, которую обещает его подпись, не существует:
|
||||
> ни на уровне сервиса, ни на уровне базы. Класса `ProcessingRestrictedException` в проекте нет —
|
||||
> ни файла, ни строки; RLS-политики по этому флагу нет тоже. Флаг сегодня только ставится и лежит.
|
||||
> Замерено: `git ls-files | grep -i "ProcessingRestriction"` и
|
||||
> `grep -rn "class ProcessingRestrictedException" app/` — обе команды дают пустой ответ.
|
||||
> Сам канон схемы уже поправлен решением Р103, здесь текст оставлен дословно как историческая копия.
|
||||
|
||||
```sql
|
||||
ALTER TABLE pd_subject_requests
|
||||
ADD COLUMN processing_restricted BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
|
||||
@@ -29,6 +29,13 @@
|
||||
- **Биз-22 (§10.X)** — простой lead-scoring: `lead_score = supplier.quality_score × (time_in_form_seconds / 60)`, clamped в `[0, 99.99]`. Без ML. Триггер `calc_lead_score()` BEFORE INSERT/UPDATE на `deals`.
|
||||
- **CTO-14 (§12.5.5)** — UTM-поля для когортной аналитики: `deals.utm_source/utm_medium/utm_campaign/utm_content` + индекс `(tenant_id, utm_source)`.
|
||||
- **CTO-15 (§22.X + §23.10.X)** — two-person impersonation для тенантов с `pd_subject_request.processing_restricted=TRUE` ИЛИ `chargeback_unrecovered_rub > 0`. `impersonation_tokens.second_approver_id` + `second_approval_at` (роль `compliance` обязательна).
|
||||
|
||||
🔴 **ЗАМЕР 06.08.2026 (Р110): столбцы есть, проверки нет.** `second_approver_id` и `second_approval_at`
|
||||
в таблице заведены, но их никто не заполняет и никто не требует: токен на вход под клиента сегодня
|
||||
создаётся для любого тенанта, независимо от `processing_restricted`. Класса `SaasAdminAuthService`,
|
||||
который по замыслу сверял бы флаги и требовал второго одобряющего, в проекте не существует —
|
||||
`grep -rn "class SaasAdminAuthService" app/app/` даёт пустой ответ. Подробнее — пометка к §22.13.7.
|
||||
|
||||
- **CTO-16 (§10.X)** — `project_user_assignments(project_id, user_id, skills JSONB)` — пул менеджеров проекта для `assignment_strategy IN ('round_robin','least_loaded')` Post-MVP.
|
||||
- **OPEN-И-17 (§22.X + Прил. И)** — TTL 365 дней на API-ключах. Cron `secrets:notify-expiring` уведомляет за 30 дней до expiry. UI «продлить» ставит `+365d`.
|
||||
- **OPEN-И-18 (§19.10.X)** — DNS-rebinding защита для outbound webhook: resolve→pin IP→connect, blacklist RFC1918 на pinned IP, ≤3 redirect, max body 1 MB.
|
||||
@@ -37,6 +44,13 @@
|
||||
- **OPEN-И-21 (§22.X + Прил. И)** — Anti-DDoS стек: Nginx `limit_req_zone` 1000 RPS глобально + Yandex SmartCaptcha на `/register` + disposable-email-blacklist (~50К доменов).
|
||||
- **Ю-9 (§22.X)** — hard-блок impersonation для всех ролей кроме `compliance` при `pd_subject_request.processing_restricted=TRUE` (152-ФЗ ст.21 ч.5). Реализация совместно с CTO-15 — единый guard в `SaasAdminAuthService`.
|
||||
|
||||
🔴 **ЗАМЕР 06.08.2026 (Р110): это решение, а не построенная защита.** Единого охранника нет:
|
||||
класса `SaasAdminAuthService` в проекте не существует — ни файла, ни строки
|
||||
(`grep -rn "class SaasAdminAuthService" app/app/` — пусто), а `ImpersonationController` в своей шапке
|
||||
прямо пишет «на MVP не реализовано». Вход под клиента флаг `processing_restricted` не смотрит вовсе:
|
||||
войти можно к любому тенанту и любой ролью. Пункт Ю-9 в реестре открытых вопросов при этом стоит
|
||||
с галочкой «закрыт» — закрыто **решение**, работа не сделана.
|
||||
|
||||
**7 P2 — реализация в фазах 1–3:**
|
||||
|
||||
- **Биз-23 (§10.X)** — `deals.region_code VARCHAR(8)` + `deals.city VARCHAR(100)` + автоопределение по prefix phone через `PhonePrefixService`.
|
||||
@@ -158,6 +172,11 @@
|
||||
### Решения внутри приложений
|
||||
|
||||
- **OPEN-Д-1 ✅:** `pd_subject_requests` дополняется полем `processing_restricted BOOLEAN DEFAULT FALSE` — флаг полной остановки обработки ПДн по требованию субъекта (ст.21 152-ФЗ).
|
||||
|
||||
🔴 **ЗАМЕР 06.08.2026 (Р110): полной остановки обработки не происходит.** Поле добавлено — это правда.
|
||||
Но «флаг полной остановки» на сегодня останавливает ноль операций: ни один сервис портала его не читает,
|
||||
класса `ProcessingRestrictedException` не существует (`git ls-files | grep -i "ProcessingRestriction"` —
|
||||
пусто). Закрыт вопрос «нужно ли такое поле», а не задача «останавливать обработку».
|
||||
- **OPEN-Д-5 / OPEN-И-1 ✅:** создаём таблицу `incidents_log(id, type, severity, started_at, resolved_at, summary, root_cause, postmortem_url, related_pd_subject_request_ids)` — единый журнал инцидентов для compliance и runbook.
|
||||
- **OPEN-Ж-3 ✅:** способ принятия оферты — **Click-wrap**: 3 чекбокса при регистрации (с офертой согласен / с Политикой согласен / даю согласие на ПДн). Юридически достаточно, технически просто.
|
||||
- **OPEN-И-2 ✅:** интеграция с внешними CRM — **Уровень 1 (webhook outbound) на MVP** + архитектурный задел для Уровня 2 (готовые коннекторы). **amoCRM-коннектор — в спринте 14–15** как пилотный. Bitrix24, RetailCRM — Post-MVP по запросу клиентов.
|
||||
@@ -5154,6 +5173,15 @@ const safe = DOMPurify.sanitize(userInput, SAFE_HTML_CONFIG);
|
||||
|
||||
### 22.13.1. Yandex 360 SSO для админов SaaS (OPEN-И-13)
|
||||
|
||||
> 🔴 **ЗАМЕР 06.08.2026 (Р110): весь раздел ниже — замысел, не построенная работа.** Он описывает
|
||||
> `SaasAdminAuthService` так, будто это существующий кусок портала («наш `SaasAdminAuthService` — RP»,
|
||||
> «`SaasAdminAuthService::handleSsoCallback($payload)`»). Такого класса в проекте нет — ни файла,
|
||||
> ни строки: `grep -rn "class SaasAdminAuthService" app/app/` даёт пустой ответ. Значит ни единый вход
|
||||
> через Yandex 360, ни обязательный TOTP, ни ограничения аварийного входа кодом не проверяются:
|
||||
> столбцы `saas_admin_users.sso_provider` и `is_break_glass` в базе есть, охранника нет.
|
||||
> То же самое уже помечено в каноне схемы решением Р103. Читать раздел как описание работающей защиты
|
||||
> нельзя — это техническое задание на неё.
|
||||
|
||||
**Решение DO-5 (04.05.2026):** Yandex 360 SSO для админов SaaS. **v8.5 (OPEN-И-13):** полный flow.
|
||||
|
||||
**Архитектура:**
|
||||
@@ -5271,6 +5299,24 @@ const safe = DOMPurify.sanitize(userInput, SAFE_HTML_CONFIG);
|
||||
|
||||
### 22.13.7. Two-person impersonation + Ю-9 hard-block (CTO-15 + Ю-9)
|
||||
|
||||
> 🔴 **ЗАМЕР 06.08.2026 (Р110): описанная ниже защита НЕ ПОСТРОЕНА. Проблема, названная ниже как
|
||||
> «до v8.5», жива сегодня.** Раздел читается как описание готового механизма — вплоть до порядка шагов,
|
||||
> имён столбцов и текста заглушки. На деле нет ни одного его куска:
|
||||
>
|
||||
> - класса `SaasAdminAuthService` в проекте не существует — ни файла, ни строки
|
||||
> (`grep -rn "class SaasAdminAuthService" app/app/` — пусто);
|
||||
> - вход под клиента делает `ImpersonationController`, и он в своей же шапке пишет
|
||||
> «на MVP не реализовано»: флаг `processing_restricted` он не читает вовсе;
|
||||
> - токен создаётся для любого тенанта и любой ролью; `second_approver_id` и `second_approval_at`
|
||||
> никто не заполняет и не требует; писем второму одобряющему никто не шлёт;
|
||||
> - записи `impersonation.second_approval_granted` / `..._denied` в журнал не пишет никто.
|
||||
>
|
||||
> То есть человек, запретивший обработку своих данных, сегодня **не защищён** от входа сотрудника
|
||||
> в его карточку — ровно та «юридически это нарушение», о которой говорит абзац ниже.
|
||||
> Прежний текст оставлен дословно: это техническое задание, и как задание оно верно. Как описание
|
||||
> работающей защиты читать его нельзя. **Проверить заново:** команда выше перестанет быть пустой —
|
||||
> значит защиту построили, и эту пометку снимает тот, кто её построил.
|
||||
|
||||
**Проблема:** до v8.5 `SaasAdminAuthService::createImpersonationToken()` создавал токен для любого тенанта без проверки compliance-флагов. Если у тенанта `pd_subject_request.processing_restricted=TRUE` (152-ФЗ ст.21 ч.5 — субъект ПДн запретил обработку) — admin SaaS мог несмотря на это войти в кабинет тенанта и просмотреть/изменить данные. Юридически это нарушение.
|
||||
|
||||
**v8.5 решение:**
|
||||
@@ -5912,6 +5958,14 @@ DDL `pd_subject_requests` — [`db/schema.sql`](../db/schema.sql) v8.4.
|
||||
|
||||
### 23.10.11. v8.5: Yandex 360 SSO + break-glass + two-person impersonation
|
||||
|
||||
🔴 **ЗАМЕР 06.08.2026 (Р110): ни один из пяти экранов ниже не построен.** Раздел описывает готовую
|
||||
админку: серый замок «Two-person required», очередь одобрений, скрытую кнопку «Войти как клиент»
|
||||
и ответ 403 с записью `imp_blocked_152fz_st21` при попытке зайти по прямой ссылке. На сегодня всего
|
||||
этого нет: класса `SaasAdminAuthService`, который по замыслу и возвращал бы 403, в проекте не
|
||||
существует (`grep -rn "class SaasAdminAuthService" app/app/` — пусто), флаг `processing_restricted`
|
||||
при входе под клиента не читается, кнопка не скрывается и не блокируется, экрана
|
||||
`/admin/imp/pending-approvals` нет. Прежний текст оставлен дословно как задание на работу.
|
||||
|
||||
> **Источник:** реестр v1.12 §13.10 (OPEN-И-13, CTO-15, Ю-9). Для углублённого описания см. также §22.13.1 (SSO flow), §22.13.7 (two-person + Ю-9).
|
||||
|
||||
**Изменения в админке SaaS v8.5:**
|
||||
|
||||
@@ -2,9 +2,28 @@
|
||||
|
||||
**Версия:** 8.2 от 04.05.2026 (правки после интервью с заказчиком).
|
||||
|
||||
> 🔴 **ЗАМЕР 06.08.2026 (решение владельца Р110): флаг «прекратить обработку моих данных» НИЧЕГО НЕ БЛОКИРУЕТ.**
|
||||
> Этот документ ниже обещает, что при поднятом `processing_restricted` все операции с данными человека
|
||||
> проверяют флаг и отказывают. На 06.08.2026 такой защиты в портале **нет**: флаг ставится, хранится — и всё.
|
||||
> Ни одна проверка на него не смотрит. Класса `ProcessingRestrictedException` в проекте не существует —
|
||||
> ни файла, ни строки.
|
||||
> **Чем замерено** (обе команды дают пустой ответ): `git ls-files | grep -i "ProcessingRestriction"` и
|
||||
> `grep -rn "class ProcessingRestrictedException" app/`.
|
||||
> Прежний текст ниже оставлен дословно: это принятое решение, а не построенная работа, и пометки лишь
|
||||
> отделяют одно от другого. **Проверить заново** — теми же двумя командами; как только они перестанут
|
||||
> быть пустыми, пометки снимает тот, кто построил защиту.
|
||||
|
||||
## Что нового в v8.2 относительно v8.1
|
||||
|
||||
- ✅ **OPEN-Д-1 закрыт.** В таблицу `pd_subject_requests` добавляется новое поле `processing_restricted BOOLEAN NOT NULL DEFAULT FALSE` — флаг полной остановки обработки ПДн субъекта по требованию (ст.21 152-ФЗ, право на ограничение обработки). При установке этого флага все последующие операции с ПДн данного субъекта в системе должны проверять флаг и отказывать. Имплементация: `if (subject.processing_restricted) throw new ProcessingRestrictedException()` в сервисном слое + RLS-политика на чтение в БД-слое (опционально, для defense-in-depth).
|
||||
|
||||
🔴 **ЗАМЕР 06.08.2026 (Р110): это решение, а не построенная защита.** Поле в таблице есть — это правда.
|
||||
Всё остальное в пункте выше — замысел, который не выполнен: ни одна операция портала флаг не проверяет
|
||||
и никому не отказывает, класса `ProcessingRestrictedException` не существует, RLS-политики по этому флагу
|
||||
тоже нет. Замерено командами `git ls-files | grep -i "ProcessingRestriction"` и
|
||||
`grep -rn "class ProcessingRestrictedException" app/` — обе дают пустой ответ. Читать пункт выше как
|
||||
описание работающей защиты нельзя.
|
||||
|
||||
- ✅ **OPEN-Д-5 закрыт.** Создаётся таблица **`incidents_log`** для журнала инцидентов (объединена с OPEN-И-1). DDL:
|
||||
|
||||
```sql
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
# Отчёт помощника — З-0-11 «Правда про флаг прекращения обработки» — 06.08.2026
|
||||
|
||||
Круг работы: только бумаги. Кода не тронуто ни строки. Ветка `feat/prospects-manual-testing-kp`.
|
||||
|
||||
## Разбор задания
|
||||
|
||||
Задание описывает беду верно, а число мест — неверно.
|
||||
|
||||
**Что подтвердилось.** Флаг `pd_subject_requests.processing_restricted` ставится и лежит.
|
||||
Ни класса `ProcessingRestrictedException`, ни охранника `SaasAdminAuthService` в проекте нет.
|
||||
Замерено двумя приборами независимо от надзирателя — см. «Разведка».
|
||||
|
||||
**С чем не согласился — число «четыре».** Мест оказалось **четырнадцать** в шести бумагах.
|
||||
Пометки поставлены в тринадцати из них плюс баннер в шапке — четырнадцать пометок в пяти
|
||||
бумагах. Четырнадцатое место править не дал сторож проекта, о нём отдельно.
|
||||
Ещё одно место — в запрещённом мне пути, о нём ниже громко.
|
||||
|
||||
**С чем не согласился — «врезка рядом».** Надзиратель сам назвал слабость: читатель приходит
|
||||
по оглавлению прямо в пункт. Я усилил правило: **пометка ставится там, где читатель ВХОДИТ,
|
||||
а не там, где её удобно приткнуть.** Отсюда три следствия:
|
||||
|
||||
- в таблицу нельзя дописать пометку строкой — читатель таблицы бежит глазами по строкам;
|
||||
поэтому пометка стоит **сразу под заголовком раздела, до таблицы**, мимо неё не пройти;
|
||||
- у раздела, который целиком описывает несуществующую защиту (§22.13.1, §22.13.7, §23.10.11),
|
||||
пометка стоит **между заголовком и первым абзацем**;
|
||||
- у бумаги, чей предмет — сам этот флаг (Приложение Д), пометка стоит **баннером в шапке**,
|
||||
сразу под строкой версии.
|
||||
|
||||
**Ограничение, которое переписало форму работы.** Мерка «ноль удалённых строк» означает, что
|
||||
**ни одна существующая строка не может быть изменена** — правка строки в git считается как
|
||||
удаление + добавление. Поэтому все пометки — только целиком новые строки. Соблазн дописать
|
||||
правду прямо в ячейку таблицы (где читатель её точно увидит) пришлось отвергнуть именно
|
||||
по этой причине, а не по вкусу.
|
||||
|
||||
## Разведка
|
||||
|
||||
### Прибор проверен на подставной строке ДО того, как я ему поверил
|
||||
|
||||
Предупреждение надзирателя подтвердилось: `grep -i` кириллицу не складывает.
|
||||
|
||||
```text
|
||||
$ printf 'ДИСКА ещё НЕТ\nБлокируется ОТКАЗ\n' > decoy.md
|
||||
$ grep -i "диска" decoy.md ; echo "rc=$?"
|
||||
rc=1 # ничего не нашёл — прибор негоден
|
||||
```
|
||||
|
||||
Работал `ripgrep` (инструмент Grep), проверенный на тех же двух подставных строках,
|
||||
которые он ОБЯЗАН поймать:
|
||||
|
||||
```text
|
||||
rg -i "диска" decoy.md → 1:ДИСКА ещё НЕТ ✅
|
||||
rg -i "блокируется" decoy.md → 2:Блокируется ОТКАЗ ✅
|
||||
```
|
||||
|
||||
Только после этого перечень мест собирался им.
|
||||
|
||||
### Чего в коде нет — перепроверено мной, не принято на слово
|
||||
|
||||
```text
|
||||
git ls-files | grep -i "ProcessingRestriction" → пусто
|
||||
grep -rn "class ProcessingRestrictedException" app/ → пусто
|
||||
grep -rn "class SaasAdminAuthService" app/app/ → пусто
|
||||
```
|
||||
|
||||
Плюс третий, независимый прибор: сквозной перечень всех упоминаний
|
||||
`processing_restricted` по хранилищу — **103 совпадения в 33 файлах**. В коде портала
|
||||
(`app/**`) флаг встречается только там, где его записывают, читают из базы и объявляют тип:
|
||||
контроллер, модель, интерфейс. Ни одной проверки «если поднят — отказать».
|
||||
|
||||
### Перечень мест лжи — собран командой, не по списку надзирателя
|
||||
|
||||
Найдено четырнадцать мест в шести бумагах, пометки поставлены в тринадцати плюс баннер.
|
||||
|
||||
| # | бумага | место | что обещано | в списке надзирателя |
|
||||
|---|---|---|---|---|
|
||||
| 1 | `docs/Workflow_pd_subject_requests_v8_2.md` | шапка (баннер) | — | — |
|
||||
| 2 | то же | «✅ OPEN-Д-1 закрыт», п.1 | «все операции **должны проверять флаг и отказывать**», `throw new ProcessingRestrictedException()`, RLS-политика | ✅ да |
|
||||
| 3 | `docs/Analiz_originala_v8_3.md` | §3.3, перед DDL | «блокируются на уровне сервиса и БД (RLS)» | ✅ да |
|
||||
| 4 | `docs/CRM_bp-gr_Инструкция_v8_5.md` | решение CTO-15 в списке v8.5 | two-person одобрение обязательно | ❌ нет |
|
||||
| 5 | то же | решение Ю-9 в списке v8.5 | «hard-блок … единый guard в `SaasAdminAuthService`» | ✅ да |
|
||||
| 6 | то же | «Решения внутри приложений», OPEN-Д-1 | «флаг **полной остановки** обработки» | ❌ нет |
|
||||
| 7 | то же | §22.13.1 SSO | «наш `SaasAdminAuthService` — RP», `::handleSsoCallback()` | ❌ нет |
|
||||
| 8 🔴 | то же | §22.13.7 | целый готовый механизм: порядок шагов, письма, текст заглушки | ❌ нет |
|
||||
| 9 🔴 | то же | §23.10.11 | пять экранов админки, «кнопка **полностью скрыта**», «вернёт 403 + audit» | ❌ нет |
|
||||
| 10 | `docs/Открытые_вопросы_v8_3.md` | §8.1, перед таблицей | ✅ OPEN-Д-1 «Ограничение обработки ПДн — закрыто» | ❌ нет |
|
||||
| 11 | то же | «12 P1 закрытий» | two-person impersonation закрыт | ✅ да (строка 2163) |
|
||||
| 12 🔴 | то же | §13.7 «Что хорошо покрыто» | «`processing_restricted` — **реализовано** через guard-исключение» | ❌ нет |
|
||||
| 13 | то же | §13.10.2, перед таблицей | ✅ CTO-15 и ✅ Ю-9 | ❌ нет |
|
||||
| 14 | `docs/Объединённый_конспект.md` | «Что хорошо покрыто (из C-2)» | `processing_restricted` в перечне сильных сторон | ❌ нет |
|
||||
| 15 ⛔ | `docs/security/2026-06-17-go-live-security-report.md` | Режим 2, ✅ ст.21 ч.5 | галочка соответствия закону | ❌ нет |
|
||||
|
||||
Строка #1 — баннер, не отдельная ложь. Строка #15 — место лжи есть, но пометку поставить
|
||||
не дал сторож проекта; правка откачена, разбор ниже. Итого: **мест четырнадцать,
|
||||
пометок поставлено четырнадцать в пяти бумагах** — тринадцать у мест плюс баннер.
|
||||
|
||||
**Из четырёх мест надзирателя все четыре подтвердились** — ни одного ложного. Но найдено
|
||||
ещё десять. Число «четыре» было занижено втрое.
|
||||
|
||||
### Три самых опасных места — все вне списка надзирателя
|
||||
|
||||
- **#12** — единственное место во всех бумагах, где стоит слово **«реализовано»**. И стоит
|
||||
оно в разделе «Что хорошо покрыто», среди правдивых пунктов. Читатель, проверивший
|
||||
соседние строки и убедившийся, что они верны, принимает эту на веру заслуженно.
|
||||
- **#8 и #9** — не одна фраза, а два развёрнутых раздела, написанных как описание готовой
|
||||
работы: с порядком шагов, именами столбцов, текстом заглушки для пользователя, кодом
|
||||
ответа 403 и именем записи в журнале `imp_blocked_152fz_st21`. Такое не читается как
|
||||
замысел — такое читается как «сделано, вот подробности».
|
||||
- **#8** особенно: он начинается словами «**Проблема:** до v8.5 … admin SaaS мог войти
|
||||
… Юридически это нарушение» и продолжается «**v8.5 решение:**». То есть прямо утверждает,
|
||||
что нарушение устранено. Оно не устранено — оно живо сегодня.
|
||||
|
||||
### 🔴 Два места, которые я НЕ имел права трогать — эскалирую
|
||||
|
||||
1. **`.claude/skills/pdn-152fz-audit/references/checklist.md:175–176`** — контрольный лист
|
||||
для аудита по 152-ФЗ утверждает: «при `TRUE` `ProcessingRestrictedException` **блокирует
|
||||
операции с ПДн субъекта**». Это опаснее всех четырнадцати мест вместе: **прибор, которым
|
||||
проверяют соблюдение закона, сам несёт ложь**. Аудит, запущенный этим листом, поставит
|
||||
галочку и уйдёт довольным. Путь `.claude/**` мне запрещён — правку должен сделать владелец.
|
||||
Там же `SKILL.md:49` спрашивает «Реализовано ли право на ограничение обработки?» — этот
|
||||
вопрос честный, его трогать не надо.
|
||||
2. **`db/CHANGELOG_schema.md`** — уже поправлен решением Р103, ничего не требуется.
|
||||
|
||||
Проверил и **не стал** править (лжи нет, обещаний защиты не содержат):
|
||||
`docs/Приложение_Б_В_БД_диаграммы_v8_3.md` (перечисляет добавленные столбцы — столбцы
|
||||
и правда есть), `docs/README_АРХИВ_v8_5.md` (описывает состав приложений),
|
||||
`docs/CHANGELOG_claude_md.md` (исторические записи, где two-person честно помечен как TODO
|
||||
на будущее), `docs/Открытые_вопросы_v8_3.md` §13.5 (таблица вариантов A/B/C — честно
|
||||
предлагает варианты, ничего не утверждает).
|
||||
|
||||
## Что сделал
|
||||
|
||||
Четырнадцать пометок вида «🔴 **ЗАМЕР 06.08.2026 (Р110): …**» в пяти бумагах — все одним
|
||||
голосом, по образцу решения Р103 в каноне схемы.
|
||||
|
||||
Три границы соблюдены:
|
||||
|
||||
1. **Ничего не удалено и не переписано.** `git diff --numstat`, второй столбец — ноль
|
||||
по каждому из пяти файлов. Прежний текст стоит дословно, пометка добавлена рядом.
|
||||
2. **Галочка «закрыт» у Ю-9 на месте.** Более того, две пометки (#11 и #13) прямо
|
||||
объясняют, почему её не снимают: «Галочки „закрыт" остаются: решения приняты.
|
||||
Пометка говорит лишь, что работа по ним не сделана».
|
||||
3. **Версии в шапках не тронуты.** Ни одна изменённая строка не содержит номера версии —
|
||||
доказано тем же нулём удалений: все строки с версиями остались нетронутыми байт в байт.
|
||||
|
||||
### ⛔ Место #15 — отчёт по безопасности: пометку поставить НЕ ДАЛ сторож проекта
|
||||
|
||||
Правку я сделал, а потом откатил. Рассказываю честно, потому что тут спорили два правила
|
||||
круга и одно из них пришлось признать главнее.
|
||||
|
||||
**Почему трогал.** Строка в отчёте от 17.06.2026 гласит: «✅ … `processing_restricted`
|
||||
(ст.21 ч.5) … — **присутствуют в схеме**». Она **дословно верна**: столбец в схеме есть.
|
||||
Но это единственная бумага в хранилище, которую по замыслу показывают проверяющим, и
|
||||
галочка рядом со ссылкой на статью закона читается как «требование закона выполнено» —
|
||||
ровно тот вред, который назван в задании. Я дописал туда семь строк, помеченных не «ЗАМЕР»,
|
||||
а «ПРИПИСКА 06.08.2026, дописана позже прогона, ничего в нём не меняет».
|
||||
|
||||
**Почему откатил.** Сторож правописания завалил коммит. Оказалось, в этом отчёте **уже
|
||||
лежат пять слов не из словаря** — «незакоммиченные», «доустановки», «регекс», «десинка» —
|
||||
и все пять появились там задолго до меня. Замерено: ни одно из них не встречается ни в одной
|
||||
из моих семи строк, а `git diff --numstat` по этому файлу показывал `7 0` — ни одна чужая
|
||||
строка не тронута. То есть сторож краснел на чужом долге, но красный он от моего коммита.
|
||||
|
||||
Выходов было три, и два запрещены:
|
||||
|
||||
- поправить пять чужих слов — это правка существующих строк, то есть удаления в `numstat`.
|
||||
Мерка «ноль удалённых строк» названа в задании самой важной. **Отпадает.**
|
||||
- дописать слова в общий словарь `cspell-words.txt` — файл прямо запрещён к правке. **Отпадает.**
|
||||
- откатить свои семь строк. **Сделано.**
|
||||
|
||||
Файл вернулся дословно к прежнему виду — доказано: `git status` по нему пуст.
|
||||
Место лжи при этом **никуда не делось**, и я передаю его владельцу вместе с готовым текстом
|
||||
пометки — он лежит выше в этом же разделе, в кавычках. Чтобы его поставить, нужно сперва
|
||||
решить, что делать с пятью чужими словами: либо владелец разрешает их поправить, либо
|
||||
разрешает добавить в словарь. Своей властью я ни того, ни другого сделать не могу.
|
||||
|
||||
## Ножи
|
||||
|
||||
### Нож 1. Допущение «мест лжи ровно четыре»
|
||||
|
||||
Случай мимо: **девять лишних мест**, из них три опаснее всех четырёх названных.
|
||||
Допущение вырезано: перечень собран прибором с нуля, а не сверен со списком.
|
||||
|
||||
### Нож 2. Допущение «ложь узнаётся по имени класса»
|
||||
|
||||
Случай мимо найден и он не один:
|
||||
|
||||
- **#6** — «флаг **полной остановки обработки** ПДн» — ни одного имени класса, чистое
|
||||
обещание по-русски;
|
||||
- **#12** — «**реализовано** через guard-исключение» — слово «guard» есть, имени нет;
|
||||
- **#14** — `processing_restricted` просто стоит в перечне «что хорошо покрыто», без единого
|
||||
утверждения. Ложь тут в самом факте присутствия в списке.
|
||||
|
||||
Поиск по именам классов не нашёл бы ни одного из трёх. Нашёл сквозной поиск по имени
|
||||
**столбца** плюс чтение окружающего текста глазами.
|
||||
|
||||
### Нож 3. Допущение «врезка рядом — значит читатель её увидит»
|
||||
|
||||
Случай мимо, названный надзирателем: человек приходит по оглавлению прямо в пункт.
|
||||
Проверил на себе — и нашёл случай мимо ЕГО поправки тоже: **пометка после таблицы
|
||||
не работает вовсе**, потому что таблицу читают строками и до низа не доходят.
|
||||
Отсюда правило «пометка там, где входят» и три его следствия (см. «Разбор задания»).
|
||||
|
||||
### Нож 4. Мой собственный прибор
|
||||
|
||||
Допущение: «`ripgrep` складывает регистр кириллицы». Проверено на двух подставных строках
|
||||
ДО работы. Не проверь я — весь перечень мог бы оказаться выборочным, а отчёт — уверенным.
|
||||
|
||||
### Нож 5. Допущение «ноль удалённых строк достигается аккуратностью»
|
||||
|
||||
Случай мимо: правка **внутри существующей строки** даёт удаление в `git diff --numstat`,
|
||||
хотя ничего не стёрто по смыслу. Именно этот случай чуть не произошёл: дописать правду
|
||||
внутрь ячейки таблицы было лучшим решением для ножа 3. Отвергнуто.
|
||||
|
||||
### Нож 6. Допущение «зелёные сторожа означают, что круг чист»
|
||||
|
||||
Случай мимо нашёлся сам: сторож правописания **покраснел на чужом долге**, лежавшем
|
||||
в файле задолго до меня, — и завалил мой коммит. Обратное тоже верно и опаснее: сторож
|
||||
мог бы **промолчать** о моей ошибке, если бы файл уже был в исключениях. Так и вышло:
|
||||
`docs/superpowers/**` целиком в списке исключений `cspell.json`, поэтому мой собственный
|
||||
отчёт **сторожем правописания не проверен вовсе** — он числится в «6 файлов проверено»
|
||||
только потому, что я его туда вписал, а на деле пропущен. Знать это важнее, чем видеть
|
||||
зелёное: зелёное здесь означает «не смотрели», а не «чисто».
|
||||
|
||||
## Что осталось незакрытым
|
||||
|
||||
### 1. 🔴 Контрольный лист аудита 152-ФЗ несёт ту же ложь — путь запрещён
|
||||
|
||||
`.claude/skills/pdn-152fz-audit/references/checklist.md:176`. Правку должен сделать
|
||||
владелец. Считаю это самым срочным хвостом круга: остальные бумаги вводят в заблуждение
|
||||
читателя, а эта — **инструмент проверки**.
|
||||
|
||||
### 2. ⛔ Отчёт по безопасности от 17.06.2026 остался непомеченным
|
||||
|
||||
Место #15. Готовый текст пометки — в разделе «Что сделал». Ставить его нельзя, пока владелец
|
||||
не решит, что делать с пятью чужими словами не из словаря, которые уже лежат в том файле:
|
||||
поправить их или добавить в словарь. Оба действия — за пределами моих прав.
|
||||
Пока этого нет, галочка «✅ ст.21 ч.5» в отчёте продолжает читаться как доказательство
|
||||
соблюдения закона.
|
||||
|
||||
### 3. Ответ на вопрос владельца: не станет ли пометка новой ложью, когда защиту построят
|
||||
|
||||
Станет — если оставить её простым утверждением. Сделано три вещи, и предложена четвёртая.
|
||||
|
||||
**Что сделано.** Каждая пометка называет **команду, которой её можно перемерить**, а не
|
||||
только вывод. Пометка утверждает не «защиты нет», а «вот команда, и она даёт пустой ответ».
|
||||
Такое утверждение опровергается за десять секунд кем угодно, включая непрограммиста:
|
||||
команда перестала быть пустой — пометка устарела. В ключевых местах это сказано словами:
|
||||
«**Проверить заново** — теми же командами; как только они перестанут быть пустыми, пометки
|
||||
снимает тот, кто построил защиту».
|
||||
|
||||
**Чего это не решает.** Никто не обязан их снимать. Через месяц пометки могут остаться
|
||||
и начать врать в другую сторону — ровно опасение владельца.
|
||||
|
||||
**Предложение (код, я его не писал — за пределами круга).** В проекте уже живёт сторож
|
||||
`app/tests/Unit/Schema/KanonNeObeshchaetOhrannikaTest.php`, поставленный решением Р103.
|
||||
Правило у него точно то, что нужно: «кто называет несуществующее имя, тот пишет
|
||||
„не существует" в том же куске текста». Но он собирает бумаги **только из папки `db/`** —
|
||||
проверено чтением: `kanonBumagiProBazu()` обходит `db/` и ничего кроме. **Вся папка `docs/`
|
||||
у него вне охраны.** Отсюда два предложения владельцу:
|
||||
|
||||
- **расширить сторожа на `docs/`** — тогда возврат лжи в бумаги ловится сам, без человека;
|
||||
- **добавить ему вторую половину:** сегодня он требует пометку, пока класса нет, но не
|
||||
требует **убрать** пометку, когда класс появится. Достроить: «класс появился → пометка
|
||||
про его отсутствие обязана исчезнуть». Тогда механизм становится симметричным и вопрос
|
||||
владельца закрывается насовсем, а не обещанием.
|
||||
|
||||
Ни того, ни другого я не делал: `app/**` запрещён, там работает другой помощник.
|
||||
|
||||
### 4. Оговорка про мою мерку полноты
|
||||
|
||||
Тринадцать мест — это то, что нашли **сквозной поиск по имени столбца, по `Ю-9`, по именам
|
||||
двух классов и чтение окрестностей глазами**. Обещание, не содержащее ни одного из этих
|
||||
четырёх якорей (например, «человек может запретить обработку, и портал это исполнит»,
|
||||
без слова `processing_restricted` и без «Ю-9»), моим перечнем **не поймано бы**. Я такого
|
||||
не встретил, но и утверждать, что его нет, не могу. Честная граница мерки.
|
||||
|
||||
### 5. Версии бумаг
|
||||
|
||||
Не тронуты, как велено. Шесть бумаг изменены содержательно — **владельцу решать**, требует
|
||||
ли это подъёма версий и записи в квинтете нормативки. Сам не делал: у нормативных бумаг
|
||||
свой порядок изменения.
|
||||
@@ -1420,6 +1420,12 @@ OPEN-И-12 ⏸ Где хранить контакты эскалации (P1,
|
||||
|
||||
**Что хорошо покрыто (из C-2):** 34/34 RLS, CSP без `unsafe-inline`, HMAC SHA-256+timestamp+replay, SSRF-фильтр, impersonation Ю-1, atomic billing, processing_restricted, four-eyes >50К ₽. Выпадает только DNS-rebinding (P1 OPEN-И-18).
|
||||
|
||||
🔴 **ЗАМЕР 06.08.2026 (Р110): `processing_restricted` в списке «хорошо покрыто» стоит зря.** Покрыт
|
||||
только столбец в таблице. Запрета обработки по этому флагу в портале нет: ни один сервис его не
|
||||
читает, класса `ProcessingRestrictedException` не существует —
|
||||
`git ls-files | grep -i "ProcessingRestriction"` даёт пустой ответ. Строка оставлена дословно,
|
||||
пометка лишь снимает с неё обманчивую уверенность.
|
||||
|
||||
**Закрытий нет** в этом коммите — по правилу §2.2.
|
||||
|
||||
## 5. Реализация v8.5 (07.05.2026, вечер)
|
||||
|
||||
@@ -2161,6 +2161,12 @@
|
||||
- **Сводный список закрытий с импактом на schema/narrative** — новый §13.10 «Закрытия аудита C — 27 решений (07.05.2026)».
|
||||
- **8 P0 разблокированы** для триггера фазы 1 (`composer create-project`). Архитектурные следствия: `projects.assignment_strategy='manual'` (Биз-17), `deals.duplicate_of_id` + 24ч-дедуп (Биз-19), e2e-тест `SET LOCAL`+PgBouncer в спринте 1 (CTO-13), `WITH CHECK` + REVOKE на saas-таблицах (OPEN-И-14), append-only triggers + hash-chain + роль `crm_audit_writer` на 5 audit-таблицах (OPEN-И-15), Sentry whitelist+regex для 6 паттернов ПДн (OPEN-И-16), OIDC+JIT+break-glass для admin SSO (OPEN-И-13), TTFR-15-мин default (Биз-18).
|
||||
- **12 P1 закрытий** — все попадают в фазы 1–2: UTM-поля (CTO-14), `project_user_assignments` (CTO-16), TTL ключей 365 дней (OPEN-И-17), DNS-rebinding pin-IP (OPEN-И-18), hard-limit `api_keys` ≤10 (OPEN-И-19), presigned URL 24ч + триггер audit (OPEN-И-20), Nginx rate-limit + Yandex SmartCaptcha + disposable-blacklist (OPEN-И-21), two-person impersonation для `compliance` (CTO-15, Ю-9), Telegram-бот в спринте 9 (Биз-20), generic outbound `marketing.conversion` (Биз-21), простой scoring (Биз-22).
|
||||
|
||||
🔴 **ЗАМЕР 06.08.2026 (Р110): «two-person impersonation для `compliance` (CTO-15, Ю-9)» закрыто как
|
||||
решение и не построено.** Ни запрета входа под клиента при поднятом `processing_restricted`, ни
|
||||
требования второго одобряющего в портале нет; класса `SaasAdminAuthService` не существует
|
||||
(`grep -rn "class SaasAdminAuthService" app/app/` — пусто). Подробности — пометка к §13.10.2.
|
||||
|
||||
- **7 P2 закрытий** — все либо мелкие schema-добавки (`deals.region_code/city` Биз-23, закомментированный DDL `call_recordings` OPEN-И-26), либо infra-задачи (Yandex KMS per-tenant DEK OPEN-И-22, `pg_anonymizer` процедура OPEN-И-24), либо cron-регламенты (Биз-24, OPEN-И-25), либо документная фиксация роли `crm_audit_writer` (OPEN-И-23, уже взято в P0 OPEN-И-15).
|
||||
- **Сводка §0:** 67 ✅ / 5 🟦 / 5 ⏸ (1 P0 Б-1, 4 P1 Диз-1/Диз-3/DO-2/DO-4 — все ждут Б-1 или у Claude). **Все P2 продуктовые закрыты повторно.**
|
||||
- **Импакт на schema/narrative:** schema.sql v8.4 → **v8.5** (12 column-add + 2 новых таблицы + 5 audit-триггеров + 1 новая роль + WITH CHECK на 2 политики + REVOKE на 5 таблиц), narrative v8.4 → **v8.5** (правки §10 дедуп, §12.5.5 TTFR, §22.7 SSO, §22.X Sentry PII, §23.10 admin flow). Реализация — отдельный коммит после фиксации решений.
|
||||
@@ -2380,6 +2386,13 @@
|
||||
|
||||
### 8.1. Прил. Д (Workflow_pd_subject_requests)
|
||||
|
||||
🔴 **ЗАМЕР 06.08.2026 (Р110): галочка у OPEN-Д-1 означает «решили», а не «работает».** Решено было
|
||||
завести поле `processing_restricted` — поле завели. Но ограничения обработки, ради которого поле
|
||||
заводилось, в портале нет: флаг ставится, хранится и не запрещает ни одной операции. Класса
|
||||
`ProcessingRestrictedException` в проекте не существует — `git ls-files | grep -i "ProcessingRestriction"`
|
||||
даёт пустой ответ. Галочку не снимаем — решение принято и остаётся в силе; пометка говорит только
|
||||
о том, что под ней пусто.
|
||||
|
||||
| ID | Вопрос | Статус |
|
||||
|----|--------|--------|
|
||||
| ✅ **OPEN-Д-1** | **Ограничение обработки ПДн — BOOLEAN флаг `processing_restricted` в `pd_subject_requests`** (ст.21 152-ФЗ) | Закрыто 04.05 |
|
||||
@@ -2725,6 +2738,14 @@ reminders {
|
||||
- **§22.12 антипаттерны оригинала** — явная защита от DOM-plaintext credentials.
|
||||
- **Atomic billing** — `gateway_idempotence_key UNIQUE` + `lockForUpdate` + `late_webhook_ignored` — двойного списания не будет.
|
||||
- **`processing_restricted` BOOLEAN** (152-ФЗ ст.21 ч.5) — реализовано через guard-исключение.
|
||||
|
||||
🔴 **ЗАМЕР 06.08.2026 (Р110): слово «реализовано» здесь неверно — не реализовано ничего.** Это самая
|
||||
опасная строка в списке: остальные пункты говорят «сделано хорошо», и читатель разумно принимает
|
||||
на веру и эту. На деле есть только столбец в таблице. Охранника нет: класса
|
||||
`ProcessingRestrictedException` в проекте не существует — `git ls-files | grep -i "ProcessingRestriction"`
|
||||
даёт пустой ответ. Ни один сервис флаг не читает и никому по нему не отказывает. Строка оставлена
|
||||
дословно, чтобы было видно, откуда пошло заблуждение.
|
||||
|
||||
- **Four-eyes** > 50 000 ₽ + лимиты `support` 1000 ₽/24ч — anti-fraud для админов.
|
||||
- **Изоляция тенантов 4 уровня** — сильнее, чем у HubSpot multi-tenant.
|
||||
- **Kanban+DnD виртуализация** (§11) — на уровне Pipedrive.
|
||||
@@ -2768,6 +2789,15 @@ reminders {
|
||||
|
||||
#### 13.10.2. P1 — 12 закрытий (фазы 1–2)
|
||||
|
||||
🔴 **ЗАМЕР 06.08.2026 (Р110): две строки этой таблицы — CTO-15 и Ю-9 — закрыты как РЕШЕНИЯ, но не
|
||||
построены.** Обе обещают защиту человека, запретившего обработку своих данных: запрет входа сотрудника
|
||||
в его карточку и обязательное одобрение вторым админом. Ни того, ни другого в портале нет. Единого
|
||||
охранника `SaasAdminAuthService`, названного в обеих строках, не существует — ни файла, ни строки
|
||||
(`grep -rn "class SaasAdminAuthService" app/app/` — пусто); `ImpersonationController`, который вход
|
||||
под клиента и делает, в своей шапке пишет «на MVP не реализовано» и флаг `processing_restricted`
|
||||
не читает; столбцы `second_approver_id` / `second_approval_at` заведены, но их никто не заполняет.
|
||||
Галочки «закрыт» остаются: решения приняты. Пометка говорит лишь, что работа по ним не сделана.
|
||||
|
||||
| ID | Решение (вариант A) | Импакт |
|
||||
|---|---|---|
|
||||
| ✅ **Биз-20** | Telegram-бот для нотификаций — спринт 9 (после биллинга) | Narrative: §17 (нотификации) + roadmap. Schema (фаза 2): `users.telegram_user_id BIGINT NULL`, `tenants.telegram_bot_token TEXT NULL` (зашифровано) |
|
||||
|
||||
Reference in New Issue
Block a user