Skip to content

fix: port legacy invite integrity hardening to dev - #767

Merged
TThanos3000 merged 1 commit into
devfrom
fix/dev-invite-integrity-to-dev
Sep 29, 2026
Merged

TThanos3000 merged 1 commit into
devfrom
fix/dev-invite-integrity-to-dev

Conversation

@TThanos3000

@TThanos3000 TThanos3000 commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Что изменено

Replacement delivery for #764.

#764 был корректно реализован и протестирован, но был merged в stacked base fix/dev-team-security-errors вместо dev. Этот PR переносит только incremental changes #764 на актуальный dev после merge #763.

Legacy Invite transitions используют общий atomic service и единый lock protocol. Accept создаёт Collaborator и завершает Invite в одной транзакции; stale PATCH не возвращает обработанный Invite в pending. Partial unique index защищает один pending Invite на (project, user), а проигравший конкурентный INSERT получает controlled 409.

Зачем

Изменения original PR #764 не попали в dev, потому что PR был merged в stacked feature base. Этот Draft PR доставляет тот же incremental B scope отдельной веткой непосредственно в dev, без повторного переноса PR A и без изменений PR C.

Реализация

  • Original PR: fix: make legacy invite transitions atomic and race-safe #764.
  • Original B head: 3a513846c81dd36e5f3393957ec3450c9fcfb2f7.
  • Current dev base: 64a97a87b789aa2ac1f3ebabba2ef43e1b785bca.
  • New head: 11547cab5af868125c150e53c8f4061d94b1554b.
  • Перенос: один cherry-pick original incremental commit B; конфликтов не было.
  • Tree нового head совпадает с original B head; origin/dev...HEAD содержит ровно один commit и 9 файлов B.
  • Scope: docs/invite-integrity-api.md; invites/migrations/0003_legacy_pending_invite_constraint.py; invites/models.py; invites/serializers.py; invites/tests/test_invite_api.py; invites/tests/test_invite_integrity.py; invites/tests/test_pending_invite_migration.py; invites/views.py; projects/team_service.py.
  • PR A authorization/service code остаётся базой и не дублируется в diff. PR C team_policy, migrations 0004/0019, Angular и React отсутствуют.

API

Успешные ответы сохранены: create 201, accept/decline 200, edit 200, revoke pending 204. State conflicts имеют {code, detail} и 409: duplicate_pending_invite, invite_already_processed, not_program_member, already_project_member, already_project_leader, invalid_team_member. Permission conflicts остаются 403. Malformed input остаётся 400.

Concurrent revoke-first/accept-second может вернуть accept 404: Invite уже удалён, Collaborator не создаётся. Lifecycle fields нельзя изменить PATCH/PUT; edit сохраняет только разрешённые mutable fields.

UI

Не менялся. Angular и React отсутствуют в diff.

Permissions

Исправления PR A сохранены: только текущий leader управляет командой; object authorization повторно проверяется внутри service после Project lock. Outsider не может switch leader или удалить collaborator публичного/приватного проекта. Разрешённые pre-submission remove/switch текущим leader продолжают работать. Direct member add остаётся controlled 405 после authorization.

Проверки

  • PostgreSQL 18.1 targeted: invites.tests, projects.tests.test_project_collaborators, projects.tests.test_team_security — 72 tests PASS.
  • Targeted покрывает atomic accept, injected rollback, duplicate pending, concurrent duplicate create, double accept, accept+decline, accept+revoke, stale PATCH+accept, membership removed before accept, unique INSERT → 409, processed Invite state.
  • PostgreSQL 18.1 full backend suite — 957 tests PASS, 563.952 s.
  • PR A regression checks: outsider switch/remove public/private, service actor recheck, current leader remove/switch, former leader denial, controlled direct add.
  • Migration forward/backward и duplicate preflight без выбора победителя — PASS.
  • python manage.py check и check --tag models — PASS.
  • python manage.py makemigrations --check --dry-run — No changes detected.
  • python manage.py showmigrations invites показывает единственную цепочку 0001, 0002, 0003 на source; на чистой test DB migration 0003 и partial unique index применены ровно один раз.
  • Black для 8 изменённых Python-файлов, Flake8 для всех tracked Python-файлов, git diff --check — PASS.
  • GitHub Lint / Tests — PASS.
  • GitHub PostgreSQL CI — PASS: PostgreSQL connection/locks, checks, migration consistency, empty-DB migrate, targeted locking tests и full suite.

Acceptance criteria

  • Base нового PR — dev / 64a97a87b789aa2ac1f3ebabba2ef43e1b785bca.
  • Diff содержит только incremental scope B: 9 ожидаемых файлов и один commit.
  • A не повторён в diff; его authorization behavior подтверждён regression tests.
  • C, Angular и React отсутствуют.
  • Migration 0003_legacy_pending_invite_constraint присутствует и применена ровно один раз.
  • PostgreSQL targeted и full suite зелёные.
  • GitHub Lint / Tests / PostgreSQL CI зелёные.
  • PR создан как Draft; merge/deploy не выполняются.

Не проверено

Повторный live DEV SQL preflight не выполнен: у Codex нет read-only credentials/SSH к DEV DB, а публичный API не предоставляет безопасный SQL/count surface. Ранее предоставленный результат аудита — duplicate pending Invite (project,user) = 0 — не выдаётся за повторную проверку. Workflow/PR #766 не использовался. Production/DEV data не изменялись.

Browser не применим к backend-only diff. Live DEV mutations, merge и deploy не выполнялись.

Риски / migration

Единственная migration invites/0003_legacy_pending_invite_constraint.py сначала выполняет read-only duplicate preflight, затем добавляет partial unique index uniq_legacy_pending_invite(project,user) WHERE is_accepted IS NULL. Если на момент rollout появились duplicates, migration остановится без удаления данных и без выбора победителя; требуется отдельное решение владельца данных.

Откат удаляет constraint и сохраняет Invite. PROD имеет другой migration graph/lifecycle; этот PR направлен только в dev. PR C #765 намеренно не изменялся и должен обновляться относительно свежего dev отдельным этапом после merge этого PR.

@TThanos3000
TThanos3000 marked this pull request as ready for review September 29, 2026 22:53
@TThanos3000
TThanos3000 merged commit 99cfb3e into dev Sep 29, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants