Audit cross-referenced every check_permission / _has_permission /
_has_global_permission / _require_calendar_permission call against
init_bootstrap.DEFAULT_PERMISSIONS. Three were enforced in code but
never seeded, so the Role Editor couldn't expose them:
- member.remove (projects.py:357 — remove project member)
- schedule_type.read (schedule_type.py + schedule_type_special_slot.py)
- schedule_type.manage (schedule_type.py + schedule_type_special_slot.py)
Seed only — default roles are NOT modified (admin still gets everything
via the "None = all perms" rule). Operators can grant via Role Editor.
Other audit notes (not fixed in this commit, separate decisions):
- GET /projects + GET /projects/{id}/members are completely unauthed
(no Depends(get_current_user_or_apikey)). Anonymous can list all
projects. Investigate whether this is deliberate (e.g. for monitor
external scrape) or an oversight.
- create_project hardcodes `if not current_user.is_admin: 403 "Only
admins can create projects"` — doesn't consult permissions at all.
Means manager-role users can't create projects even if they have
project.write or hypothetical project.create. Consider switching
to a perm-based gate.
- Several catalog perms (project.*, task.create/read/write/delete,
milestone.*) are seeded but never checked in code; basic CRUD on
task/project/milestone/comment is gated via the parallel
check_project_role (viewer/member/dev/mgr ladder) instead.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>