fix: закрыть P0/P1 расхождения с целевой моделью
- академический отпуск: readOnly, запрет submit/start/finish защиты - черновики лабораторных скрыты от студентов в списке/деталях/по UUID - удалено действие «Убрать из группы» из UI и API - импорт: restoreInactiveStatuses, skipped-отчёт, разблокировка архивного аккаунта - глобальные материалы STUDENTS/TEACHERS с JWT-фильтрацией и сменой аудитории - LDD-AUTH-005 переведён на unit-evidence, clean check проходит по P0 - backup: безопасный парсинг .env, verify-latest, кавычки cron - robots/noindex, комментарии без автора, профиль без черновиков - docs/18-goal-audit.md; baseline 57 claims / 366 тестов / release PASS
This commit is contained in:
@@ -43,11 +43,11 @@
|
||||
"oracle": "401/404 для приватного; 200 только для ALL; состав публичного дерева",
|
||||
"evidence": [
|
||||
"ru.ysu.lms.academic.content.CourseContentIntegrationTest#anonymous cannot read course content()",
|
||||
"ru.ysu.lms.academic.content.CourseContentIntegrationTest#public tree contains only global chapters with ALL audience()",
|
||||
"ru.ysu.lms.academic.content.CourseContentIntegrationTest#anonymous tree contains only global chapters with ALL audience()",
|
||||
"ru.ysu.lms.academic.content.ContentAssetAccessIntegrationTest#course asset requires authentication()",
|
||||
"ru.ysu.lms.academic.content.ContentAssetAccessIntegrationTest#published global ALL asset stays public()"
|
||||
],
|
||||
"limitations": "Legacy-активы без article_assets остаются публичными и вынесены в отдельный риск."
|
||||
"limitations": "Legacy-активы без article_assets закрыты отдельными claims LDD-ASSET-002/003."
|
||||
},
|
||||
{
|
||||
"id": "LDD-ACCESS-004",
|
||||
@@ -659,16 +659,18 @@
|
||||
},
|
||||
{
|
||||
"id": "LDD-AUTH-005",
|
||||
"title": "Refresh/logout работают через реальный gateway",
|
||||
"title": "Gateway пропускает refresh/logout без access-JWT",
|
||||
"criticality": "P0",
|
||||
"status": "active",
|
||||
"requirement": "docs/16-stage6-report.md, §4",
|
||||
"claim": "Через gateway refresh без access-токена выдаёт новую пару, новый access работает, logout отзывает refresh, повторный refresh — 401.",
|
||||
"oracle": "runtime.auth_refresh",
|
||||
"runtime": [
|
||||
"runtime.auth_refresh"
|
||||
],
|
||||
"limitations": "Проверено на одноразовом стеке; TTL не истекает в рамках smoke."
|
||||
"claim": "Gateway не требует access-JWT для /api/v1/auth/refresh и /api/v1/auth/logout; защищённый маршрут без токена получает 401. Полный цикл refresh/logout через реальный gateway проверяется отдельным P1 runtime-claim.",
|
||||
"oracle": "JwtAuthenticationFilterTest: public paths пропущены, protected path без токена — 401",
|
||||
"runtime": [],
|
||||
"limitations": "Unit-тест проверяет маршрутизацию gateway; полный обмен пары и отзыв refresh — LDD-AUTH-008.",
|
||||
"evidence": [
|
||||
"ru.ysu.lms.gateway.security.JwtAuthenticationFilterTest#refresh and logout are public()",
|
||||
"ru.ysu.lms.gateway.security.JwtAuthenticationFilterTest#protected route without bearer token is rejected()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "LDD-AUTH-006",
|
||||
@@ -747,6 +749,97 @@
|
||||
"ru.ysu.lms.web.admin.LegacyAssetsTemplateTest#renders empty legacy assets state()"
|
||||
],
|
||||
"limitations": "Удаление файлов остаётся ручной операцией на стороне academic-service; UI только инвентаризирует."
|
||||
},
|
||||
{
|
||||
"id": "LDD-AUTH-008",
|
||||
"title": "Refresh/logout через реальный gateway",
|
||||
"criticality": "P1",
|
||||
"status": "active",
|
||||
"requirement": "docs/16-stage6-report.md, §2.3",
|
||||
"claim": "Через gateway refresh без access-токена выдаёт новую пару, новый access работает, logout отзывает refresh, повторный refresh — 401.",
|
||||
"oracle": "runtime.auth_refresh",
|
||||
"runtime": [
|
||||
"runtime.auth_refresh"
|
||||
],
|
||||
"limitations": "Проверено на одноразовом стеке; TTL не истекает в рамках smoke."
|
||||
},
|
||||
{
|
||||
"id": "LDD-ACCESS-010",
|
||||
"title": "Черновики лабораторных скрыты от студентов",
|
||||
"criticality": "P0",
|
||||
"status": "active",
|
||||
"requirement": "docs/07-groups-courses.md, §5",
|
||||
"claim": "Студент не видит черновик лабораторной ни в списке, ни в пакетных деталях, ни по прямому UUID; преподаватель и админ видят черновик.",
|
||||
"oracle": "HTTP 200/404 и фильтрация списков",
|
||||
"evidence": [
|
||||
"ru.ysu.lms.academic.lab.LabDetailsIntegrationTest#student sees published labs but not drafts in list details or by id()",
|
||||
"ru.ysu.lms.academic.course.CourseAccessServiceTest#student cannot access a draft lab of own course()"
|
||||
],
|
||||
"limitations": "Проверены academic API и список; отдельный тест прогресса на сдачу черновика не добавлялся, так как academic отдаёт 404."
|
||||
},
|
||||
{
|
||||
"id": "LDD-LIFE-004",
|
||||
"title": "Академический отпуск: вход только для чтения",
|
||||
"criticality": "P0",
|
||||
"status": "active",
|
||||
"requirement": "docs/07-groups-courses.md, §0.3",
|
||||
"claim": "Студент в ACADEMIC_LEAVE может войти и читать, но не может сдавать лабораторные и начинать/завершать защиту.",
|
||||
"oracle": "readOnly в login/me, ForbiddenException на submit/start/finish",
|
||||
"evidence": [
|
||||
"ru.ysu.lms.identity.roster.StudentLifecycleIntegrationTest#academic leave login is read only()",
|
||||
"ru.ysu.lms.progress.SubmissionServiceTest#academic leave student cannot submit()",
|
||||
"ru.ysu.lms.progress.DefenseServiceAcademicLeaveTest#academic leave student cannot start or finish defense()"
|
||||
],
|
||||
"limitations": "Запрет проверяется на progress-service; UI скрывает кнопки, но не является единственной защитой."
|
||||
},
|
||||
{
|
||||
"id": "LDD-LIFE-005",
|
||||
"title": "Действие «Убрать из группы» удалено",
|
||||
"criticality": "P1",
|
||||
"status": "active",
|
||||
"requirement": "docs/14-stage4-report.md, §3",
|
||||
"claim": "В админском UI и API больше нет отдельного действия unenroll; доступны только перевод, академ, отчисление, архив и восстановление.",
|
||||
"oracle": "Отсутствие маршрута/кнопки/метода и отрицательные проверки шаблона",
|
||||
"evidence": [
|
||||
"ru.ysu.lms.web.admin.AdminStage4TemplateTest#renders group lifecycle buttons by student status()",
|
||||
"ru.ysu.lms.web.admin.TeacherGradebookTemplateTest#teacher gradebook has no admin-only controls()"
|
||||
],
|
||||
"limitations": "Удалённый API-маршрут не проверяется отдельным HTTP-тестом; отсутствие метода компилятор проверяет по коду."
|
||||
},
|
||||
{
|
||||
"id": "LDD-IMPORT-002",
|
||||
"title": "Импорт не воскрешает неактивных студентов без флага",
|
||||
"criticality": "P1",
|
||||
"status": "active",
|
||||
"requirement": "docs/07-groups-courses.md, §9",
|
||||
"claim": "Повторный импорт сохраняет EXPELLED/GRADUATED/ARCHIVED/ACADEMIC_LEAVE без явного флага restoreInactiveStatuses и сообщает строку в skipped; с флагом активирует и зачисляет.",
|
||||
"oracle": "Статус/зачисление/ImportResult.skipped",
|
||||
"evidence": [
|
||||
"ru.ysu.lms.identity.roster.GroupServiceIntegrationTest#import does not resurrect expelled student without explicit flag()",
|
||||
"ru.ysu.lms.identity.roster.GroupServiceIntegrationTest#import restores expelled student with explicit flag and records import history()",
|
||||
"ru.ysu.lms.identity.roster.GroupServiceIntegrationTest#import preserves academic leave without explicit flag()",
|
||||
"ru.ysu.lms.identity.roster.GroupServiceIntegrationTest#import still updates an active student()",
|
||||
"ru.ysu.lms.web.admin.AdminStage4TemplateTest#group import form requires explicit restoration flag()",
|
||||
"ru.ysu.lms.web.admin.AdminStage4TemplateTest#group import result shows skipped inactive rows()"
|
||||
],
|
||||
"limitations": "Флаг восстанавливает статус студента; архивный аккаунт может потребовать отдельного lifecycle-восстановления."
|
||||
},
|
||||
{
|
||||
"id": "LDD-CONTENT-003",
|
||||
"title": "Глобальные материалы STUDENTS/TEACHERS",
|
||||
"criticality": "P1",
|
||||
"status": "active",
|
||||
"requirement": "docs/07-groups-courses.md, §6",
|
||||
"claim": "Аноним видит только ALL; студент — ALL+STUDENTS; преподаватель — ALL+TEACHERS; прямой доступ к чужой аудитории даёт 404; админ может создать/сменить аудиторию.",
|
||||
"oracle": "Фильтрация дерева/статей по JWT-роли и authoring audience",
|
||||
"evidence": [
|
||||
"ru.ysu.lms.academic.content.GlobalAudienceAccessIntegrationTest#global tree is filtered by role audience()",
|
||||
"ru.ysu.lms.academic.content.GlobalAudienceAccessIntegrationTest#global article access follows audience and role()",
|
||||
"ru.ysu.lms.academic.content.GlobalAudienceAccessIntegrationTest#authoring creates requested audience and rejects invalid()",
|
||||
"ru.ysu.lms.academic.content.GlobalAudienceAccessIntegrationTest#changing audience immediately changes access()",
|
||||
"ru.ysu.lms.academic.content.GlobalAudienceAccessIntegrationTest#course chapter never gets audience and cannot change it()"
|
||||
],
|
||||
"limitations": "Админ видит все аудитории через админское дерево; публичное дерево с админским JWT также не скрывает аудитории."
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user