From b0e385b2c604f4d0f2c4c9473a63b4e2fb1d5749 Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Wed, 3 Jun 2026 14:11:52 +0300 Subject: [PATCH] =?UTF-8?q?feat(permissions):=20A2=20=E2=80=94=20=D0=B3?= =?UTF-8?q?=D0=B8=D0=B3=D0=B8=D0=B5=D0=BD=D0=B0=20=D1=80=D0=B5=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=B0=20(lint-=D1=82=D0=B5=D1=81=D1=82)=20+=20?= =?UTF-8?q?=D1=8F=D1=81=D0=BD=D1=8B=D0=B5=20=D0=BC=D0=B5=D1=82=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Тест permissions-registry: каждый ключ из requirePermission/perm('…') в backend есть в registry (ловит опечатки/дрейф; perm() падал на старте, сырой requirePermission — нет). Заодно логирует ключи реестра, не используемые в requirePermission (информативно — часть гейтится на клиенте через /me). Метки theory.access/simulations.access переформулированы: «… доступен роли» (видимость конкретного контента — по классам в «Доступ · контент»). Co-Authored-By: Claude Opus 4.8 (1M context) --- backend/src/permissions/registry.js | 8 ++-- backend/tests/permissions-registry.test.js | 55 ++++++++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 backend/tests/permissions-registry.test.js diff --git a/backend/src/permissions/registry.js b/backend/src/permissions/registry.js index f107080..f34403e 100644 --- a/backend/src/permissions/registry.js +++ b/backend/src/permissions/registry.js @@ -144,14 +144,14 @@ const PERMISSIONS = { }, 'theory.access': { role: 'student', roles: ['student', 'free_student'], default: 1, - label: 'Доступ к теории', - desc: 'Просматривать теоретические курсы и уроки', + label: 'Раздел теории доступен роли', + desc: 'Включает раздел теории для роли. Какие именно курсы видны — настраивается по классам в «Доступ · контент»', requireConfirmOff: true, }, 'simulations.access': { role: 'student', roles: ['student', 'free_student'], default: 1, - label: 'Доступ к симуляциям', - desc: 'Открывать лабораторию с физическими, химическими и биологическими симуляциями', + label: 'Лаборатория доступна роли', + desc: 'Включает раздел лаборатории для роли. Какие именно симуляции видны — настраивается по классам в «Доступ · контент»', requireConfirmOff: true, }, 'simulations.quiz': { diff --git a/backend/tests/permissions-registry.test.js b/backend/tests/permissions-registry.test.js new file mode 100644 index 0000000..b99be91 --- /dev/null +++ b/backend/tests/permissions-registry.test.js @@ -0,0 +1,55 @@ +'use strict'; +/** + * Гигиена реестра прав (A2): каждый ключ, переданный в requirePermission('…') / + * perm('…') в коде backend/src, ДОЛЖЕН существовать в registry.js. Ловит опечатки + * и дрейф (раньше perm() падал на старте, но «сырой» requirePermission — нет). + * Дополнительно: список ключей реестра, не используемых в requirePermission (это + * НЕ ошибка — многие студенческие ключи гейтятся на клиенте через /me — просто + * выводим для обзора). + */ +const { describe, it } = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); +const registry = require('../src/permissions/registry'); + +const SRC = path.join(__dirname, '..', 'src'); +const USE_RE = /\b(?:requirePermission|perm)\(\s*['"]([\w.]+)['"]/g; + +function walk(dir, out = []) { + for (const e of fs.readdirSync(dir, { withFileTypes: true })) { + const p = path.join(dir, e.name); + if (e.isDirectory()) walk(p, out); + else if (e.isFile() && e.name.endsWith('.js')) out.push(p); + } + return out; +} + +describe('permissions registry hygiene', () => { + const files = walk(SRC); + const used = new Map(); // key -> first file where seen + for (const f of files) { + const txt = fs.readFileSync(f, 'utf8'); + let m; + while ((m = USE_RE.exec(txt)) !== null) { + if (!used.has(m[1])) used.set(m[1], path.relative(SRC, f)); + } + } + + it('все ключи requirePermission/perm(...) в коде есть в реестре', () => { + const unknown = [...used.entries()].filter(([k]) => !registry.isKnown(k)); + assert.equal(unknown.length, 0, + 'неизвестные ключи прав (опечатка / не добавлены в registry): ' + + unknown.map(([k, f]) => `${k} (${f})`).join(', ')); + }); + + it('обзор: ключи реестра, не используемые в requirePermission (информативно, не ошибка)', () => { + const unused = registry.listKeys().filter(k => !used.has(k)); + // Не падаем: часть прав enforce-ится на клиенте через /permissions/me. + if (unused.length) { + // eslint-disable-next-line no-console + console.log('[perm-hygiene] не используются в requirePermission (ок, могут гейтиться на клиенте):', unused.join(', ')); + } + assert.ok(Array.isArray(unused)); + }); +});