Skip to content

fix: политика miniShopManagerPolicy и ACL полей заказа - #614

Open
Ibochkarev wants to merge 2 commits into
betafrom
fix/issue-613-access-policy
Open

fix: политика miniShopManagerPolicy и ACL полей заказа#614
Ibochkarev wants to merge 2 commits into
betafrom
fix/issue-613-access-policy

Conversation

@Ibochkarev

Copy link
Copy Markdown
Member

Описание

Исправляет #613:

  1. Политика miniShopManagerPolicy упаковывается как related object шаблона miniShopManagerPolicyTemplate (как в miniShop2). На install/upgrade resolver resolver_09_policies.php создаёт политику, если её нет, и привязывает orphan к шаблону без перезаписи существующих data.
  2. Форма заказа снова загружает блоки «Основная информация», «Дополнительно» и адрес у менеджера с msorder_save, но без mssetting_save: GET /model-fields и /extra-fields доступны любому аутентифицированному mgr (как read /config), мутации схемы по-прежнему требуют mssetting_save.

Тип изменений

  • Исправление бага (non-breaking change)
  • Новая функциональность (non-breaking change)
  • Breaking change (изменение, ломающее обратную совместимость)
  • Рефакторинг (без изменения функциональности)
  • Документация
  • Другое (опишите):

Связанные Issues

Closes #613

Как это было протестировано?

cd core/components/minishop3
php -l config/manager_access_policy.php
php -l config/routes/manager.php
php -l ../../../_build/resolvers/resolver_09_policies.php
php tests/ModelFieldsRouteAclTest.php          # exit 0
php tests/ExtraFieldsRouteAclTest.php          # exit 0
php tests/PoliciesPackagingTest.php            # exit 0
composer ci:php                                # exit 0 (92 smoke + PHPUnit 254)
  • Ручное тестирование
  • Автоматические тесты (composer ci:php / composer test, npm run lint:ci, composer stan / GitHub Actions CI)
  • Тестирование на разных версиях PHP/MODX

Конфигурация тестирования:

  • MiniShop3: branch fix/issue-613-access-policy
  • MODX: не требовался (smoke/unit без MODX)
  • PHP: 8.4.17

Скриншоты (если применимо)

До После
Секции заказа пустые без mssetting_save Секции грузятся при msorder_save; настройки схемы — по-прежнему только с mssetting_save

Чеклист

  • Код соответствует стилю проекта
  • Добавлены/обновлены комментарии в сложных местах
  • Изменения не ломают существующую функциональность
  • Лексиконы добавлены на двух языках (ru/en) — не требуется
  • PHPStan проходит без новых ошибок (composer stan / CI job PHPStan)
  • ESLint проходит без ошибок (npm run lint:ci для Vue) — Vue не менялся
  • Обновлён CHANGELOG.md (для значимых изменений) — по convention релиза

Дополнительные заметки

Review (Gate F): code-reviewer (gpt-5.6-sol-medium) — BLOCK/HIGH нет; security-review — write ACL без замечаний, условный medium по PII в customer combo через read /model-fields/combo-options (pre-existing data path, вынесено за scope #613).

Deferred: рефактор packaging (policies() no-op) и Router-based ACL-тесты вместо source parser — отдельный PR по желанию maintainers.

@AgelxNash

Copy link
Copy Markdown

Этот PR включён в тестовую интеграционную сборку всех открытых PR MiniShop3: AgelxNash/MiniShop3, ветка integration/open-prs-20260906 (28/28 открытых).

Сборка нужна, чтобы проверить совместимость взаимозависимых серий PR до их мержа — при последовательном слиянии они конфликтуют друг с другом. Это не ревью и не конкурирующий PR: авторство сохранено (1 PR = 1 коммит с исходным автором), ветка пересобирается по мере обновления PR.

Как вошёл в сборку: Слился чисто.

@AgelxNash

Copy link
Copy Markdown

Отличная работа! Желаю этому PR быстрого мержа и ни одного конфликта 🙌

@biz87

biz87 commented Sep 7, 2026

Copy link
Copy Markdown
Member

Спасибо за фикс orphan-политики — эта часть сделана правильно, проверил по коду.

Упаковка Policies как nested related object шаблона (_build/build.php:508-512, UNIQUE_KEY => ['name']) работает даже без резолвера: в xPDOObjectVehicle::_installObject() FK (template) выставляется на объект до сравнения с существующей записью, поэтому при $upgrade = true orphan-политика перелинкуется на верный template_id самой установкой вехикла. Резолвер тут backstop, а не единственный механизм — это снимает мой основной опасение по поводу «резолвер не отработает, а установка всё равно скажет успех». Сам резолвер идемпотентен: нет — создаёт, есть с чужим шаблоном — перелинковывает, совпадает — no-op, дублей не плодит.

Локально на ветке с домердженной актуальной beta (мержил дважды, база двигалась — оба раза без конфликтов): php -l чисто на всех пяти файлах, smoke 94/94, PHPUnit 271 теста / 675 assertions, --testsuite WebApi 22/22.

Но есть блокирующая вещь.

Чтение combo-options осталось без проверки прав, и это регрессия именно этого PR

config/routes/manager.php: группа /model-fields разрезана на читающую и пишущую. Пишущая закрывается }, [new PermissionMiddleware($modx, 'mssetting_save')], а читающая — та, где лежат GET /combo-options/{model} (строка ~1004) и GET /combo-options/{model}/{field_name} (~1008) — закрывается голым });, без массива middleware вообще.

Единственная оставшаяся защита — внешний AuthMiddleware($modx, 'mgr') на всю /api/mgr. Он проверяет isAuthenticated('mgr') и токен HTTP_MODAUTH, но прав не проверяет. В ModelFieldsController и ModelFieldService дополнительных проверок тоже нет — искал hasPermission/checkPermission, не нашёл.

В описании PR это помечено как «pre-existing data path, вынесено за scope #613». Проверил по базовому коммиту — не подтверждается:

git show d5aed2c2:core/components/minishop3/config/routes/manager.php

там группа /model-fields, включающая оба combo-options, закрывается через }, [new PermissionMiddleware($modx, 'mssetting_save')]. То есть до этого PR путь требовал права; ослабление введено этим диффом, а не унаследовано.

Почему это не про схему, а про данные: combo-options не отдаёт метаданные поля — он исполняет сконфигурированный источник (ComboConfigManager::resolveFromModel(), строки 245-294) и возвращает реальные записи. Дефолтный config/combos/msOrder.php:52-60:

'customer_id' => [
    'source' => [
        'type' => 'model',
        'class' => 'MiniShop3\\Model\\msCustomer',
        'valueField' => 'id',
        'labelTemplate' => '{first_name} {last_name}',
        'sort' => ['id' => 'DESC'],
    ],
],

То есть на стоковой установке, без единой кастомизации, GET /api/mgr/model-fields/combo-options/msOrder/customer_id отдаёт ФИО и id клиентов любому залогиненному в менеджер аккаунту, независимо от назначенной ему политики.

Это ровно тот класс риска, который мы уже закрывали в этом же файле: /references/customers защищён PermissionMiddleware($modx, 'view_document') с комментарием «block PII lookup for mgr-only sessions» (#378/#415).

Предложение. GET /extra-fields и читающие /model-fields (models, visible, sections, список, {id}) оставить как есть — это чистая схема, аналогия с /config reads из #404 корректна и возражений не вызывает. А combo-options вынести отдельно: либо вернуть под mssetting_save, либо повесить AnyPermissionMiddleware с набором прав, реально нужных для форм заказа и товара — такой паттерн в файле уже есть, на CategoryProductActionPermissions::mutationPermissions() (строки ~352-356).

Тесты фиксируют ослабление как ожидаемое поведение

ModelFieldsRouteAclTest, ExtraFieldsRouteAclTest и PoliciesPackagingTest — regex-парсеры текста manager.php и build.php, а не прогон роутера с реальным запросом. ModelFieldsRouteAclTest:106-114 прямо кодирует оба combo-options как perm === null, то есть закрепляет обсуждаемое ослабление в качестве правильного. Такой тест не заметит и выноса роута за пределы /api/mgr — внешнюю группу он не видит.

Ты сам пометил router-based ACL-тесты как отложенные в отдельный PR. Здесь они нужны сразу: именно в этом месте source-parser дал ложную уверенность.

Отдельно к сведению: phpstan.neon анализирует src/, elements/snippets/, elements/tasks/. Ни один из пяти изменённых файлов туда не входит, так что зелёный PHPStan-гейт про этот PR ничего не говорит — это не претензия к тебе, а замечание о границах гейта.

Мелочь

Комментарий в resolver_09_policies.php:53 — «Existing policy data is preserved (custom site ACL overrides)» — верен для кода самого резолвера, но не для пайплайна целиком. update.policies => true в _build/config.inc.php (этим PR не менялся) приводит к тому, что при каждом апгрейде _installObject() делает fromArray(..., true) и перезаписывает data политики дефолтным набором прав — ручные правки чек-боксов апгрейд не переживут. Поведение не новое, но комментарий обещает сохранность, которой нет. Лучше уточнить формулировку.

Package the default manager policy under its template, repair missing
policies on install/upgrade, and allow authenticated mgr reads on
model-fields/extra-fields without mssetting_save while keeping writes gated.

Closes #613
combo-options and visible execute combo sources (customer PII), so they
require AnyPermissionMiddleware instead of mgr-auth alone. Add router
ACL smoke coverage and clarify the policy resolver data comment.
@Ibochkarev
Ibochkarev force-pushed the fix/issue-613-access-policy branch from d9e57b1 to e90f852 Compare September 7, 2026 14:13
@Ibochkarev

Copy link
Copy Markdown
Member Author

Адрес ревью:

combo-options / PII

GET /combo-options/* вынесены из auth-only группы под AnyPermissionMiddleware с правами формы/настроек (msorder_*, msproduct_save, mscategory_save, mssetting_*, view_document). Mgr без этих прав получает 403.

Дополнительно то же самое для GET /visible/{model}: в getVisibleFields() уже встроены comboOptions через ComboConfigManager (не чистая схема), иначе PII оставался бы на этом пути. Чистые schema-reads (/models, /sections, list, /{id}) по-прежнему auth-only; writes — mssetting_save. Менеджер с msorder_save без mssetting_save по-прежнему открывает форму заказа (#613).

Тесты

  • Обновлён ModelFieldsRouteAclTest (source map)
  • Добавлен router-based ModelFieldsRoutePermissionsTest: 403 для mgr-only на combo/visible, pass gate при msorder_save, write всё ещё запрещён

Мелочь

Комментарий в resolver_09_policies.php уточнён: резолвер data не трогает; update.policies=true в transport — отдельный путь.

Rebase на актуальную beta. composer ci:php зелёный (smoke 95, PHPUnit 271).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Проблемы с политикой доступа

3 participants