docs(server): getPageBreadCrumbs — предки не утекают (нисходящее наследование ограничений), задокументировано (#471) #550
Reference in New Issue
Block a user
Delete Branch "docs/471-breadcrumb-permission"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
#471 разбор: утечки title предка в breadcrumbs НЕТ — задокументировал почему (по решению владельца: документировать, не добавлять пофамильную фильтрацию). closes #471. Изменение comment-only (JSDoc + 5 строк у контроллера), логику не трогает.
Ключевое: премиса #471 невозможна by-construction
Ограничения наследуются ВНИЗ по дереву. Чтобы просмотреть целевую страницу P,
validateCanView→canUserAccessPage→canUserEditPageсчитаетbool_and(pp.id IS NOT NULL)по КАЖДОМУ ограниченному предку в ПОЛНОЙ родительской цепочке P (page-permission.repo.ts:400-410) — причём рекурсия permission-CTE безгранична по глубине и безdeletedAt-фильтра, тогда как breadcrumb-CTE ограниченMAX_PAGE_TREE_DEPTH=10000 +deletedAt IS NULL. Значит permission-обход — НАДмножество breadcrumb-обхода: любой ограниченный предок, попадающий в крошки, уже прошёл permission-проверку. Cross-space невозможен (parentPageIdструктурно не пересекаетspaceIdна всех трёх путях записи). Неограниченный предок в том же space виден участнику по CASLRead. Итог: пользователь, видящий P, доказуемо вправе видеть каждого предка из цепочки → «вижу P, но не вижу предка A» невозможно.Важно (расхождение с формулировкой в теле #471): исходный вариант «space-membership даёт видимость ВСЕХ страниц» — фактически НЕВЕРЕН (ограниченные подписи внутри member-space реально скрывают страницы). Настоящая причина отсутствия утечки — нисходящее наследование (выше), а не «membership = всё видно». JSDoc это явно дезавуирует и сужает гарантию до «видишь потомка ⇒ вправе видеть предков».
How verified
git diff— только комментарии/пустые строки, ровноpage.service.ts+page.controller.ts;tsc -p apps/serverне затронут (кроме пред-сущ. drawioimport.meta). node_modules 0.Осознанная развилка
Документировал как safe-by-construction (утечки нет), а не «accepted title-only exposure» — потому что премиса утечки доказуемо невозможна, а не «терпимо мала». Если предпочтёшь формулировку-хедж «принятая экспозиция» — скажу кодеру, поправит; но truthful-вариант — именно by-construction.
Checklist
Ревью — документация breadcrumb-permission (#471). Вердикт: approved ✅
Comment-only (+28, логика не тронута). Документируемый инвариант безопасности проверен против кода (сам + агент, независимо) — точен, не завышен. Эскалаций нет.
📋 Проверка doc-vs-code
Заявление дока: getPageBreadCrumbs отдаёт всю цепочку предков без пофамильной permission-фильтрации, и это НЕ утечка title, т.к. ограничения наследуются ВНИЗ: чтобы видеть целевую страницу, вызывающий уже обязан иметь доступ к КАЖДОМУ ограниченному предку.
Сверено:
canUserEditPage(page-permission.repo.ts:383) строитWITH RECURSIVE ancestorsот цели вверх поparent_page_id,bool_and(pp.id IS NOT NULL)(:410) → false, если у ЛЮБОГО ограниченного предка нет permission-строки. Полная цепочка ограниченных предков, не только прямой родитель/цель.validateCanView→canUserAccessPage→это. Описание дока точное.parent_page_idот той же цели, но breadcrumb-CTE накладывает СТРОГО больше фильтров (deletedAt IS NULLна anchor+recursive,depth < MAX_PAGE_TREE_DEPTH), а permission-CTE — НИ deletedAt, НИ depth-бонд. Значит breadcrumb-предки ⊆ permission-проверенные. Крайние случаи (soft-deleted середина цепи → breadcrumb ОБРЫВАЕТСЯ там, отдаёт короче; cross-space parent → оба покрывают; цикл → permission безграничен, покрывает ≥) — нет случая, где breadcrumb вернёт предка, которого permission не проверил.git grep): единственный user-facing —/breadcrumbs(page.controller.ts:828) валидируетvalidateCanView(page,user)на ЦЕЛИ первым (:818); внутренний (page.service.ts:1009) — move cycle-check, читает толькоancestor.id, титлы юзеру не отдаёт. Все прочие — тесты.getPage//infoперепроверяетvalidateCanViewWithPermissions).Docs-only, гейт не нужен (комментарии не ломают tsc). Независимо подтверждено субагентом. База develop
03eafa6c. Готово к мержу.