feat(seer): Add Seer project connected repo endpoint #115199
2 issues
sentry-backend-bugs: Found 2 issues (1 high, 1 medium)
High
New Seer project-repos endpoints use removed ORM fields, causing FieldError on every request - `src/sentry/api/urls.py:2462-2473`
SeerProjectRepository no longer has project or repository FK fields — they were removed by migration 0016_remove_old_fks (SafeRemoveField with MOVE_TO_PENDING removes the fields from the Django model state). The current model in src/sentry/seer/models/project_repository.py only declares the project_repository FK to sentry.ProjectRepository.
However, the new endpoints and helpers introduced in this PR repeatedly reference the removed fields:
src/sentry/seer/endpoints/project_seer_repos.py:_get_project_repos_queryset(≈ line 132):SeerProjectRepository.objects.filter(project=project, repository__status=ObjectStatus.ACTIVE).select_related("repository")and annotationReplace("repository__provider", ...)._serialize_project_repo(≈ line 67):project_repo.repositoryattribute access._get_project_repo/OrganizationSeerProjectRepoDetailsEndpoint.delete(≈ line 332):.filter(project=project, repository_id=repo_id, repository__status=...).
src/sentry/seer/autofix/utils.py:add_seer_project_repos(≈ line 891):.filter(project=project, repository_id__in=repo_ids)andSeerProjectRepository.objects.create(project=project, repository_id=...).replace_all_seer_project_repos(≈ line 916):.filter(project=project).delete()and.create(project=project, repository_id=...).
Existing working code (e.g. read_preference_from_sentry_db, has_project_connected_repos) correctly traverses project_repository__project=... and project_repository__repository__status=.... The new endpoints/helpers will raise django.core.exceptions.FieldError: Cannot resolve keyword 'project' into field (and repository) on every GET/POST/PUT/DELETE, and _serialize_project_repo will additionally raise AttributeError because repository is no longer a direct relation.
Fix: replace project=project with project_repository__project=project, repository_id=.../repository_id__in=... with project_repository__repository_id=.../__in=..., repository__status=... with project_repository__repository__status=..., repository__provider/repository__name with project_repository__repository__provider/__name, and access project_repo.project_repository.repository in _serialize_project_repo. For create/delete, construct/select via the ProjectRepository link (e.g. look up or create the ProjectRepository row and pass project_repository=<pr>).
Also found at:
src/sentry/seer/endpoints/project_seer_repos.py:250-282
Medium
Duplicate-repo check runs outside the transaction, causing unhandled IntegrityError under concurrent requests - `src/sentry/seer/autofix/utils.py:895-904`
The connected_ids duplicate check (lines 895–901) is performed before the transaction begins, so two concurrent requests for the same project+repo IDs can both pass the check; the second SeerProjectRepository.objects.create() then violates the unique constraint and raises an unhandled IntegrityError (500). Move the check inside the transaction after select_for_update.
⏱ 10m 24s · 2.8M in / 78.5k out · $3.36
Annotations
Check failure on line 2473 in src/sentry/api/urls.py
sentry-warden / warden: sentry-backend-bugs
New Seer project-repos endpoints use removed ORM fields, causing FieldError on every request
`SeerProjectRepository` no longer has `project` or `repository` FK fields — they were removed by migration `0016_remove_old_fks` (SafeRemoveField with MOVE_TO_PENDING removes the fields from the Django model state). The current model in `src/sentry/seer/models/project_repository.py` only declares the `project_repository` FK to `sentry.ProjectRepository`.
However, the new endpoints and helpers introduced in this PR repeatedly reference the removed fields:
- `src/sentry/seer/endpoints/project_seer_repos.py`:
- `_get_project_repos_queryset` (≈ line 132): `SeerProjectRepository.objects.filter(project=project, repository__status=ObjectStatus.ACTIVE).select_related("repository")` and annotation `Replace("repository__provider", ...)`.
- `_serialize_project_repo` (≈ line 67): `project_repo.repository` attribute access.
- `_get_project_repo` / `OrganizationSeerProjectRepoDetailsEndpoint.delete` (≈ line 332): `.filter(project=project, repository_id=repo_id, repository__status=...)`.
- `src/sentry/seer/autofix/utils.py`:
- `add_seer_project_repos` (≈ line 891): `.filter(project=project, repository_id__in=repo_ids)` and `SeerProjectRepository.objects.create(project=project, repository_id=...)`.
- `replace_all_seer_project_repos` (≈ line 916): `.filter(project=project).delete()` and `.create(project=project, repository_id=...)`.
Existing working code (e.g. `read_preference_from_sentry_db`, `has_project_connected_repos`) correctly traverses `project_repository__project=...` and `project_repository__repository__status=...`. The new endpoints/helpers will raise `django.core.exceptions.FieldError: Cannot resolve keyword 'project' into field` (and `repository`) on every GET/POST/PUT/DELETE, and `_serialize_project_repo` will additionally raise `AttributeError` because `repository` is no longer a direct relation.
Fix: replace `project=project` with `project_repository__project=project`, `repository_id=...`/`repository_id__in=...` with `project_repository__repository_id=...`/`__in=...`, `repository__status=...` with `project_repository__repository__status=...`, `repository__provider`/`repository__name` with `project_repository__repository__provider`/`__name`, and access `project_repo.project_repository.repository` in `_serialize_project_repo`. For `create`/`delete`, construct/select via the `ProjectRepository` link (e.g. look up or create the `ProjectRepository` row and pass `project_repository=<pr>`).
Check failure on line 282 in src/sentry/seer/endpoints/project_seer_repos.py
sentry-warden / warden: sentry-backend-bugs
[A9S-DU5] New Seer project-repos endpoints use removed ORM fields, causing FieldError on every request (additional location)
`SeerProjectRepository` no longer has `project` or `repository` FK fields — they were removed by migration `0016_remove_old_fks` (SafeRemoveField with MOVE_TO_PENDING removes the fields from the Django model state). The current model in `src/sentry/seer/models/project_repository.py` only declares the `project_repository` FK to `sentry.ProjectRepository`.
However, the new endpoints and helpers introduced in this PR repeatedly reference the removed fields:
- `src/sentry/seer/endpoints/project_seer_repos.py`:
- `_get_project_repos_queryset` (≈ line 132): `SeerProjectRepository.objects.filter(project=project, repository__status=ObjectStatus.ACTIVE).select_related("repository")` and annotation `Replace("repository__provider", ...)`.
- `_serialize_project_repo` (≈ line 67): `project_repo.repository` attribute access.
- `_get_project_repo` / `OrganizationSeerProjectRepoDetailsEndpoint.delete` (≈ line 332): `.filter(project=project, repository_id=repo_id, repository__status=...)`.
- `src/sentry/seer/autofix/utils.py`:
- `add_seer_project_repos` (≈ line 891): `.filter(project=project, repository_id__in=repo_ids)` and `SeerProjectRepository.objects.create(project=project, repository_id=...)`.
- `replace_all_seer_project_repos` (≈ line 916): `.filter(project=project).delete()` and `.create(project=project, repository_id=...)`.
Existing working code (e.g. `read_preference_from_sentry_db`, `has_project_connected_repos`) correctly traverses `project_repository__project=...` and `project_repository__repository__status=...`. The new endpoints/helpers will raise `django.core.exceptions.FieldError: Cannot resolve keyword 'project' into field` (and `repository`) on every GET/POST/PUT/DELETE, and `_serialize_project_repo` will additionally raise `AttributeError` because `repository` is no longer a direct relation.
Fix: replace `project=project` with `project_repository__project=project`, `repository_id=...`/`repository_id__in=...` with `project_repository__repository_id=...`/`__in=...`, `repository__status=...` with `project_repository__repository__status=...`, `repository__provider`/`repository__name` with `project_repository__repository__provider`/`__name`, and access `project_repo.project_repository.repository` in `_serialize_project_repo`. For `create`/`delete`, construct/select via the `ProjectRepository` link (e.g. look up or create the `ProjectRepository` row and pass `project_repository=<pr>`).
Check warning on line 904 in src/sentry/seer/autofix/utils.py
sentry-warden / warden: sentry-backend-bugs
Duplicate-repo check runs outside the transaction, causing unhandled IntegrityError under concurrent requests
The `connected_ids` duplicate check (lines 895–901) is performed before the transaction begins, so two concurrent requests for the same project+repo IDs can both pass the check; the second `SeerProjectRepository.objects.create()` then violates the unique constraint and raises an unhandled `IntegrityError` (500). Move the check inside the transaction after `select_for_update`.