169 Commits

Author SHA1 Message Date
Roman Donchenko 4aa0be3df5 Prevent source files from being modified by the Django user (#10575)
Currently, all source files are located in `/home/django`, and owned by
`django`. This means that if there's any vulnerability that lets an
attacker overwrite files in the server, they can replace source files
with their own code, and potentially get that code executed. That's
pretty bad, so I want to harden against that.

Make all source files owned by root, and move them to `/opt/cvat`. Add a
`manage.py` symlink in `/home/django` for backwards compatibility. It
happens that if a script is a symlink, Python does not add the symlink's
directory to `sys.path`, which is great for us, since that lets us avoid
a writable directory on there.

Still, even though `/home/django/manage.py` is owned by root, an
attacker could potentially be able to delete it and replace it with
their own malicious file. To be a bit more safe, replace `~/manage.py`
calls in backend scripts with `django-admin`.

To make sure CVAT can still find the data directory, add a new
environment variable, `CVAT_BASE_DIR` and set it in the Docker image.

This also fixes a minor bug: we no longer override the `HOME`
environment variable in the `Dockerfile`, so now it's automatically set
by `Docker` depending on the current user.
2026-07-23 13:22:24 +03:00
Maxim Zhiltsov 29ef4d7a33 Validate annotation source (#10521) 2026-07-06 12:42:40 +03:00
Aleksei Sosov 8c704275ba Add attempt and request_duration fields to webhook deliveries (#10693) 2026-06-09 13:08:47 +04:00
Maxim Zhiltsov 06f14c3768 Audio interval annotations, backups, and TSV dataset format (#10583) 2026-05-20 13:39:29 +03:00
Maxim Zhiltsov 134a5dd92b Audio media access (#10560) 2026-05-18 21:33:21 +03:00
Maxim Zhiltsov bf75521e96 Make test DB dump output more stable (#10605) 2026-05-18 19:51:47 +03:00
Maxim Zhiltsov f03d039681 Audio task creation (#10551) 2026-05-13 22:21:04 +03:00
Maxim Zhiltsov 06dd39feff Move some fields from search to filters (#10569)
### Summary

- Moved most enum-like fields from `search_fields` to `simple_filters`,
and `filter_fields` in viewsets
- Added field sorting for schema

### Motivation and context

Enum-like fields (e.g. `status`, `state`, `role`) were declared in
`search_fields` on several list endpoints. DRF's `SearchFilter` performs
case-insensitive substring matching across `search_fields`, so the
global `?search=` parameter would also match against these enum values,
which is rarely what users want. They are now exposed only via
`simple_filters` (exact match), e.g. `?status=completed`,
`?state=in_progress`, `?role=maintainer`.

In some cases, free-text fields are intentionally excluded from simple
filters, because exact matching is not very useful for them. By this
logic, `project_name` and `task_name` in task and job list endpoints
should be removed as well, but they are kept to avoid breaking changes
without a significant reason, as they're available for quite a long time
already.

The filters are now sorted for schema generation, which helps to avoid
spurious schema diffs.

#### Per-endpoint changes

| Endpoint | Removed from `search_fields` | Added to `simple_filters` |
Added to `filter_fields` |
|---|---|---|---|
| `GET /api/projects` | `status` | — | — |
| `GET /api/tasks` | `status`, `mode`, `dimension`, `validation_mode` |
— | — |
| `GET /api/jobs` | `state`, `stage` | — | — |
| `GET /api/memberships` | `role` | — | — |
| `GET /api/webhooks` | `type` | — | — |
| `GET /api/cloudstorages` | `provider_type`, `credentials_type` | — | —
|
| `GET /api/access_tokens` | — | `read_only` | — |
| `GET /api/invitations` | — | `user_id`, `accepted` | `id` |
| `GET /api/requests` | — | `org_id` | `org`, `org_id` |

For fields removed from `search_fields`: they remain exact-match
filterable as `simple_filters` (e.g. `?status=completed`).
For fields newly in `simple_filters`: they were previously available
only via the `filter` parameter and are now also exact-match filterable.
For fields newly in `filter_fields`: they were previously not available
for filtering.

The following endpoints were touched only for the construction-style
refactor (no field-level behavior change):
`GET /api/issues`, `GET /api/comments`, `GET /api/labels`, `GET
/api/users`, `GET /api/organizations`, `GET /api/consensus_settings`,
`GET /api/quality/conflicts`, `GET /api/quality/reports`, `GET
/api/quality/settings`.

### API response changes

The following list endpoints now return additional fields:

- `GET /api/requests` — `operation.org_id` (integer, nullable). Supports
`?org_id=` filtering.
- `GET /api/invitations` — `accepted` (boolean). Mirrors the existing
`accepted` filters.

### How has this been tested?

Added simple-filter test coverage for fields newly exposed in this PR:

- `tests/python/rest_api/test_access_tokens.py`: `read_only`.
- `tests/python/rest_api/test_invitations.py`: `user_id`, `accepted`.
- `tests/python/rest_api/test_requests.py`: `org`, `org_id`.

Filled in pre-existing simple-filter coverage gaps:

- `tests/python/rest_api/test_jobs.py`: `dimension`, `media_type`,
`mode`, `task_name`, `project_name`.
- `tests/python/rest_api/test_tasks.py`: `media_type`, `project_name`.

`TestRequestsListFilters` was refactored to class-scoped fixtures so the
heavy setup (3 projects + 3 tasks + ~13 RQ requests + the new
org-context project/task/exports) runs once for the whole class instead
of per parametrize case. Wall-clock for `pytest -k
TestRequestsListFilters` on the same hardware:

| | Before | After |
|---|---|---|
| Tests collected | 9 | 10 |
| Total time | 78.4 s | 13.1 s |
| Per-case `call` time | ~5.2 s | ~0.05 s |
| Per-case `setup` time | ~4.3 s every case | ~12.1 s once, then
negligible |

≈6× faster despite covering one more case.

The corrupted-meta test was also extracted out of the class to a
module-level function with `restore_db_per_function` /
`restore_redis_inmem_per_function` decorators since it has no class
dependencies.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:05:00 +03:00
Maxim Zhiltsov 6134a6c813 Introduce task media type (#10538) 2026-05-06 19:46:31 +03:00
Aleksei Sosov 43f7ccc310 Fix create data 500 for invalid server and remote files (#10554) 2026-05-04 16:20:07 +03:00
Oleg Valiulin 5a86cc11ea Add pytest --keep-data to keep test data volumes across sessions (#10480)
Co-authored-by: Oleg Valiulin <oleg.valiulin@cvat.ai>
2026-04-16 10:46:47 +01:00
Kirill Lakhov 2f0939adc4 Export resource list as csv (#10312)
The feature allows to export current list of Projects/Tasks/Jobs as .csv file via button in filters UI.

---------
Co-authored-by: Maxim Zhiltsov <zhiltsov.max35@gmail.com>
2026-03-06 15:23:00 +03:00
Roman Donchenko 3b948e09c2 Support using cloud storages as backing storage for local tasks (#10282)
This allows storing media data of "local" tasks in cloud storage,
transparently to the user. The CVAT administrator must explicitly move
tasks to backing cloud storage (or back) using the new management
commands.

Currently, only tasks with images using cached chunks are supported.
2026-03-05 15:18:29 +02:00
Dmitrii Lavrukhin 930338658a Remove consensus_replicas field from backup (#10294) 2026-03-03 14:56:59 +02:00
Roman Donchenko 41a00febd4 tests/python: simplify the _run function (#10287)
1. Don't capture stderr. Nobody needs it, and it seems unlikely that
   anybody will.

2. Don't exit the process if the subprocess fails. Since this function
   is now (indirectly) used within individual tests, this behavior causes
   the testsuite to exit prematurely.

We don't really need to print a custom error message, because the
default exception message already contains the command line and status;
and since we no longer capture stderr, it'll be printed too. Stdout
will, unfortunately, not be printed, but it's not as important for
debugging.

Also, fix an issue where the subprocess status is not checked if
`capture_output` is false.
2026-02-25 13:23:39 +02:00
Dmitrii Lavrukhin 5c458dead1 Flattening job list on a task page (#10217)
We are going to increase the possible number of replicas, and current
way of displaying replicas is not convenient if there are hundreds of
them.

So,
- flatten list of jobs
- on both jobs page and task page:
  - every parent job has a tag "parent"
  - every replica job has a tag "replica"
- every parent job has an action "go to replicas" which switches filters
on a page to show it's replicas
- every replica job has an action "go to parent" which switches filters
on a page to show it's parent
- task page be default does not show replicas
- added "replicas_count" field to api on job retrieving 

Co-authored-by: Maxim Zhiltsov <zhiltsov.max35@gmail.com>
Co-authored-by: Kirill Lakhov <kirill.lakhov@cvat.ai>
2026-02-24 14:15:27 +03:00
Roman Donchenko 40fbe9e44b Stop recreating the database after the REST API testsuite (#10288)
Frankly, I don't know why we're even doing this. It seems to only have
downsides:

* It slows down testsuite execution, which is especially annoying
because it happens _before_ detailed exception messages are printed.

* It erases evidence that could be used to investigate why a test
failed.

The DB gets reloaded every time the testsuite starts anyway, so a dirty
database should not affect any subsequent executions. To make sure
there's nothing left from a previous test execution, run `manage.py flush`
before `loaddata`.
2026-02-24 13:01:24 +02:00
Roman Donchenko 8153718702 Make RelatedFile.path a relative path (#10269)
Absolute paths don't fit very well here:

* Files can be stored in cloud storage, in which case the absolute path
  stored in the database doesn't actually exist.

* They make it unnecessarily hard to move storage to a different base
  directory.

* The code becomes simpler with relative paths.
2026-02-11 13:32:00 +02:00
Roman Donchenko bae2c9ceb9 Bump black and isort (#10234)
The isort update changes nothing, but black 2026 changes a lot (for the
better, I think).
2026-01-29 12:54:53 +02:00
Kirill Lakhov 8337ae0bed Improved consensus UX (#10172)
This PR implements a simplified consensus scoring system for merged annotations. Instead of filtering annotations based on quorum thresholds, all annotations are now merged and assigned a consensus score (0.0 to 1.0) that represents the level of agreement among annotators.

Also PR contains a bunch of improvements to review mode allowing to unlock and edit objects, navigate in between objects using shortcuts.
2026-01-29 12:48:31 +03:00
Maxim Zhiltsov b9ed804f37 Increase PAT staleness period in tests (#10187) 2026-01-14 16:25:51 +03:00
Maxim Zhiltsov 65c370bb57 Fix chapters for videos without manifest (#10152)
It's possible that some tasks with videos have no manifest. There are
several reasons for that, including manual playback speed manipulation
attepts. CVAT will generate no manifest for such videos, but the
chapters functionality will try to read the chapters from the manifest
regardless. It's technically possible to ignore bad keyframes, but it
can lead to invalid chapters.

- Fixed task access for tasks with videos with bad keyframes
2025-12-24 13:31:41 +02:00
Roman Donchenko 5e8de2e562 Use container.decode instead of container.demux (#10137)
This is a helper method that pretty much just wraps the double loop over
the packets and the frames in a packet. Using it makes the code simpler
and enables better type inference in IDEs, because the PyAV type stubs
are sufficient to infer that `container.decode(video_stream)` returns an
`Iterable[VideoFrame]` (whereas `packet.decode()` is declared to return
`list[SubtitleSet]` for some reason).

Also, add some imports and type annotations to ensure that the IDEs have
types to infer _from_.
2025-12-18 19:37:28 +02:00
Roman Donchenko f794d8254d tests: don't suppress failures in generate_manifest (#10116)
This just makes the failures harder to investigate.
2025-12-12 17:43:16 +02:00
MhhhxX 6b0c940dc5 Marks and navigation buttons for chapters of video files in the player navigation (#9924) 2025-12-10 12:43:02 +03:00
Roman Donchenko fdc3a24b83 tests: use PEP 604 syntax for optionals/unions (#10090)
This is a continuation of #10060.

I also added a couple of `TypeAlias` annotations where appropriate, and
changed the import style in `test_users.py` to be more consistent with
other files.
2025-12-09 13:51:52 +02:00
Roman Donchenko 56a4d22914 Remove imports that were deprecated in Python 3.10 (or earlier) (#10053)
Now that we've dropped Python 3.9 support, we can get rid of these. Some
of these were actually deprecated in Python 3.9 too, but they must've
slipped through after the last cleanup round.

Done with:

ruff check --select=UP006,UP035 --target-version=py310 --fix
--unsafe-fixes

plus a bit of manual cleanup.
2025-11-27 17:51:25 +02:00
Grigorii777 2ebc75e5d0 Cloud storage failed status fix (#10011)
Issue: https://github.com/cvat-ai/cvat/issues/9380
Incorrect exception handling for Cloud Storage non-existence and other
NOT_FOUND errors
I fixed the exception handling and tested all these cases on three types
of Cloud Storage.
2025-11-25 17:43:17 +02:00
Oleg Valiulin b991aec05c restapi test tags in removed images on project export (#10002) 2025-11-14 13:19:47 +00:00
Maxim Zhiltsov 650f2b204c Return only own tokens in api/auth/access_tokens (#9950) 2025-10-29 18:59:45 +03:00
Maxim Zhiltsov cf9ce57616 Support api access token auth in cli and sdk (#9563) 2025-10-22 14:29:34 +03:00
Maxim Zhiltsov 9427dc5ef8 API tokens (#9680) 2025-10-16 16:51:03 +03:00
Maxim Zhiltsov 9265fc473f Fix possible error in consensus tag merging (#9865) 2025-10-03 16:33:26 +03:00
Maxim Zhiltsov 5ddeda3330 Support context images in cloud storage-based tasks (#9757) 2025-09-18 18:12:09 +03:00
Oleg Valiulin 0e789ecc25 Fix cloud storage tasks tests (#9826) 2025-09-17 15:14:38 +03:00
Maxim Zhiltsov d553f7ea6d Support clickhouse migrations (#9689) 2025-09-11 16:04:27 +03:00
Andrey Zhavoronkov 41371c29a1 Revert "[DEV-710] Added helm push to public ECR (#9795)"
This reverts commit 611e3e9cc9.
2025-09-09 17:19:05 +03:00
Peter Iosipov 611e3e9cc9 [DEV-710] Added helm push to public ECR (#9795)
Required to push our Helm chart to our public ECR repo

I've tested in separate workflow
(https://github.com/cvat-ai/cvat/actions/runs/17459911830/job/49582057271)


- [x] I submit my changes into the `develop` branch
- [ ] I have created a changelog fragment <!-- see top comment in
CHANGELOG.md -->
- [ ] I have updated the documentation accordingly
- [ ] I have added tests to cover my changes
- [ ] I have linked related issues


- [x] I submit _my code changes_ under the same [MIT License]

---------

Co-authored-by: Petr Iosipov <petr.iosipov@cvat.ai>
Co-authored-by: Andrey Zhavoronkov <andrey@cvat.ai>
2025-09-08 17:01:14 +02:00
Maria Khrustaleva 75fc135808 Allow tasks and projects to be transferred between organizations and sandboxes (#9528) 2025-08-15 14:21:48 +03:00
ruslan 7c3e1c1b47 Fix webhook tests (#9708)
<!-- Raise an issue to propose your change
(https://github.com/cvat-ai/cvat/issues).
It helps to avoid duplication of efforts from multiple independent
contributors.
Discuss your ideas with maintainers to be sure that changes will be
approved and merged.
Read the [Contribution guide](https://docs.cvat.ai/docs/contributing/).
-->

This PR replaces `example.com` domain name with the new alias
`webhooks.internal` that exists inside a docker network. Previously
tests failed often because example.com does not return any response for
some requests, RQ had webhooks jobs that tried to finish within 10
seconds, but also failed due to timeout.

Also since there are webhooks created in a DB, they try to reach
example.com when a cluster starts, that sometimes fills up the worker's
queue.

Usage of subdomain is important because Django URL matcher does not
allow domains like `webhooks`

<!-- Provide a general summary of your changes in the Title above -->

### Motivation and context
<!-- Why is this change required? What problem does it solve? If it
fixes an open
issue, please link to the issue here. Describe your changes in detail,
add
screenshots. -->

### How has this been tested?
<!-- Please describe in detail how you tested your changes.
Include details of your testing environment, and the tests you ran to
see how your change affects other areas of the code, etc. -->

### Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply.
If an item isn't applicable for some reason, then ~~explicitly
strikethrough~~ the whole
line. If you don't do that, GitHub will show incorrect progress for the
pull request.
If you're unsure about any of these, don't hesitate to ask. We're here
to help! -->
- [ ] I submit my changes into the `develop` branch
- [ ] I have created a changelog fragment <!-- see top comment in
CHANGELOG.md -->
- [ ] I have updated the documentation accordingly
- [ ] I have added tests to cover my changes
- [ ] I have linked related issues (see [GitHub docs](

https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword))

### License

- [ ] I submit _my code changes_ under the same [MIT License](
https://github.com/cvat-ai/cvat/blob/develop/LICENSE) that covers the
project.
  Feel free to contact the maintainers if that's a concern.
2025-08-13 13:41:41 +02:00
Maxim Zhiltsov 3409f28ff2 Limit deleted frames in job meta to the job segment only (#9690) 2025-08-05 16:05:14 +03:00
Oleg Valiulin eb3629192b spell-checking integration (#9580)
Co-authored-by: Oleg Valiulin <oleg.valiulin@cvat.ai>
Co-authored-by: Roman Donchenko <roman@cvat.ai>

Typos spell-checker integration
Run `typos` to show typos in project
Run `typos -w` to autofix
2025-07-10 16:29:24 +01:00
Andrey Zhavoronkov a982e2b315 Merge branch 'develop' into dev-release-2.40.1 2025-07-07 22:23:15 +03:00
Andrey Zhavoronkov 6299d53953 Squashed commit of the following:
commit ae8fbbbe1a6199689ad77106bbb2f0308de5e5e2
Author: Boris Sekachevw <sekachev.bs@gmail.com>
Date:   Mon Jul 7 12:45:36 2025 +0000

    Aborted chunk size

commit 2c9d02e0eb318d905b029c2212002b105173e718
Author: Boris Sekachev <sekachev.bs@gmail.com>
Date:   Mon Jul 7 15:44:20 2025 +0300

    Update 20250707_115108_sekachev.bs_added_index.md

commit bccba7f98be102b9a0072553132ff434b5ff892e
Author: Boris Sekachevw <sekachev.bs@gmail.com>
Date:   Mon Jul 7 12:41:12 2025 +0000

    Removed extra join

commit 257a736b3aec83a42167fb309ccb4456e6c07b67
Author: Boris Sekachevw <sekachev.bs@gmail.com>
Date:   Mon Jul 7 11:53:21 2025 +0000

    Added changelog

commit b6ead16cb20649f2fb5d08fd9f8f3f404b32638c
Author: Boris Sekachevw <sekachev.bs@gmail.com>
Date:   Mon Jul 7 11:50:39 2025 +0000

    Updated test assets

commit d128ff5fc18dedf4e07965a2e1c1fd87ea77a171
Author: Boris Sekachevw <sekachev.bs@gmail.com>
Date:   Mon Jul 7 10:39:15 2025 +0000

    Applied linter

commit f9e353e7c8264fbb3529d2bdfe4fdef4d408ba70
Author: Boris Sekachevw <sekachev.bs@gmail.com>
Date:   Mon Jul 7 10:33:03 2025 +0000

    Added existing check

commit b089b5ae9a236ee23e3e347f80ae8a48a109975f
Author: Boris Sekachevw <sekachev.bs@gmail.com>
Date:   Mon Jul 7 10:30:57 2025 +0000

    Add job_id on save

commit dd3eca8545fc2e1b564d38e3e28d71eb51fc6a57
Author: Boris Sekachevw <sekachev.bs@gmail.com>
Date:   Mon Jul 7 10:20:48 2025 +0000

    Updated migrations

commit e538da79e0c03b16edb45491671c861c022ef6d9
Author: Boris Sekachevw <sekachev.bs@gmail.com>
Date:   Mon Jul 7 09:54:33 2025 +0000

    fixed queryset

commit 5e811e5a57d4c8c122fddd4b54a5cc6d20f9f513
Author: Boris Sekachevw <sekachev.bs@gmail.com>
Date:   Mon Jul 7 09:51:21 2025 +0000

    Optimized annotations fetching

commit 2271b5f81f13866d601fde3efc424e2872fdae3d
Author: Boris Sekachevw <sekachev.bs@gmail.com>
Date:   Mon Jul 7 09:36:20 2025 +0000

    Added extra Job indexes
2025-07-07 18:47:23 +03:00
Oleg Valiulin 45dd0c11a8 Split rest_api test runs in two to improve performance (#9550)
Co-authored-by: Oleg Valiulin <oleg.valiulin@cvat.ai>
2025-06-26 19:03:16 +01:00
Maxim Zhiltsov f80a711289 Project quality tests (#9400) 2025-05-23 19:20:42 +03:00
Maria Khrustaleva 55652ddbb1 Reusable requests functionality (#9230)
**API changes:**
- `POST /api/consensus/merges?rq_id=rq_id` returns 410 status code, this
endpoint no longer supports process status checking
- `GET /api/projects/id/dataset?action=import_status` returns 410 status
code, this endpoint no longer supports process status checking
- `POST /api/projects/backup?rq_id=rq_id` returns 410 status code, this
endpoint no longer supports process status checking
- `POST /api/tasks/backup?rq_id=rq_id` returns 410 status code, this
endpoint no longer supports process status checking
- `PUT /api/tasks/id/annotations?rq_id=rq_id&format=format` returns 410
status code, this endpoint no longer supports process status checking
- `PUT /api/jobs/id/annotations?rq_id=rq_id&format=format` returns 410
status code, this endpoint no longer supports process status checking
- `GET /api/events` is deprecated in favor of the following API:
  - [new] `POST /api/events/export` (returns 202 with Request ID)
  - GET /api/requests/rq_id
- [new] `GET /api/events/download?rq_id=rq_id` (private endpoint, should
be used only as result_url)
- `POST /api/quality/reports/rq_id=rq_id` is deprecated in favor of `GET
/api/requests/rq_id`

**Architecture visible changes:**
- Cache files containing events (created after using the API to export
events as a file) are stored in `/data/cache/export/` instead of
`/data/tmp/`. The `_clear_export_cache` function is deleted, since cache
files are deleted one day after creation (by default) by the
`cleanup_export_cache_directory` cron job.
 
**SDK backward-incompatible changes:**
- [requests_api.list] action/target/subresource filters now have string
type
- Several types were removed:
`DatasetWriteRequest`/`BackupWriteRequest`/`TaskAnnotationsWriteRequest`;
`JobAnnotationsUpdateRequest`/`TaskAnnotationsUpdateRequest`

---------

Co-authored-by: Roman Donchenko <roman@cvat.ai>
2025-05-20 18:01:23 +02:00
Maxim Zhiltsov b23b0ad14f Project quality (#9116)
- Added quality estimation for projects
- Updated quality report contents and quality report summary server API
-- frame_count field - deprecated in favor of the new validation_frames field
-- frame_share field - deprecated in favor of the new validation_frame_share field
- Added support for job filters in quality settings. This allows to include or exclude jobs based on filter criteria
- Added support for quality estimation in consensus replicas
- Task quality checks now can use individual settings or inherit ones from the parent project
- Project quality updates now trigger task quality updates for all nested tasks. Relevant task quality reports are reused
- [Server API] Optimized GET api/quality/reports, GET api/quality/conflicts requests
- [Server API] Optimized permission checks in api/quality/* requests
- [Server API] Improved endpoint descriptions in the schema
2025-05-12 19:17:02 +03:00
Dmitrii Lavrukhin ad008b943e Using datumaro ellipses on export (#9372) 2025-05-12 16:04:30 +03:00
Roman Donchenko 9f46fa2e4a Make the dump_objects.py script easier to use in the private repo (#9152)
This involves two things:

1. Make the output directory configurable.
2. Instead of hardcoding resource types, rewrite every file that already
   exists.
2025-04-28 17:47:01 +03:00