When a tag is deleted and re-pushed, pull statistics now start fresh
at 0 instead of persisting from the deleted tag.
Changes:
- Clear TagPullStatistics in _delete_tag()
- Clear TagPullStatistics in remove_tag_from_timemachine()
- Add tests for tag deletion clearing pull statistics
- Add test for re-push scenario starting with fresh stats
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
* fix(oauth): prevent redirect URI validation bypass (PROJQUAY-9849)
Co-authored-by: Claude <noreply@anthropic.com>
* test(oauth): add comprehensive coverage for redirect URI validation (PROJQUAY-9849)
Co-authored-by: Claude <noreply@anthropic.com>
* fix(oauth): add percent-encoding protection and improve test coverage (PROJQUAY-9849)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
pullstats: updated bulk upsert function to track correct pull count and timestamp in case of race condition
Co-authored-by: shudeshp <shudeshp@redhat.com>
feat: Add image pull statistics API endpoints and UI integration
- Add new API endpoints for tag and manifest pull statistics
- Integrate pull metrics into web UI with new table columns
- Add FEATURE_IMAGE_PULL_STATS feature flag and PULL_METRICS_REDIS config
- Add pullstatsredisflushworker to supervisord configuration
- Add comprehensive test coverage for pull statistics functionality
Co-authored-by: shudeshp <shudeshp@redhat.com>
Implements global read-only superuser permissions for v1 endpoints, adjusts superuser write checks, and updates app token listing and detail endpoints; includes comprehensive tests.
---------
Co-authored-by: Claude <noreply@anthropic.com>
* mirror: Add job timeout to mirror configurations (PROJQUAY-7249)
Previous global job timeout of 5 minutes was inadequate for big images. The timeout should now be configurable in much the same way as sync is. Minimum job length is 300 seconds/5 minutes.
The PR is still work in progress.
* Fix init db, remove reference to user data in logs
* Fix tests, change repo mirror configuration
* Fix tests, make mirroring cancellable through UI
* Add cancel mirror test, change HTML document to reflect mirror timeout
* Flake8 doesn't like when '==' is used with 'None'
* Fix mirror registry tests
* Add new cypress data to fix cypress tests
* Added ability to define upload chunk size to RADOS driver, small changes to repo mirror HTML page
* Fix database migration to follow HEAD
* Upload new database data for Cypress tests
* Make skopeo_timeout_interval mandatory on API calls
---------
Co-authored-by: Ivan Bazulic <ibazulic@redhat.com>
fixing CVE-2025-4374 by extending the create_repository method to understand if we are requesting a proxy_cache repository
added unittests for create_repository when proxy_cache.
* db: use iterator chain for _get_user_repo_permissions (PROJQUAY-8839)
Unwrapping can cause increase in CPU. Use iterator chain to let
the caller unwrap
* db: optimize _get_user_repo_permissions to send to read replica (PROJQUAY-8839)
it uses a union query which doesn't invoke the replica selection
logic. Make this into 2 seperate queries
* fix unit tests
Adds an include_orgs param to the active users query used by the reconciler and sets it to true for reconciler runs
Reconciler is not including orgs as a candidate for creating corresponding RH entitlements. As a result it misses users with stripe billing that are considered orgs.
* marketplace: splittable sku for MW02702 (PROJQUAY-8151)
* Alembic migration to drop unique constraint on the orgrhsubscriptions
table
* Can split sub quantities of MW02702 across multiple orgs
* Can specify quantity for the MW02702 SKU across orgs on react UI
* Update angular UI to allow user to specify quantities for MW02702
* notifications: fetch autoprune tags with multiple policies for image expiry notification(PROJQUAY-8117)
* don't fetch notifications if tags expiry is greater than notification days + add tests
robots: Add robot federation for keyless auth (PROJQUAY-7652)
adds the ability to configure federated auth for robots by
using external OIDC providers. Each robot can be configured
to have multiple external OIDC providers as the source for
authentication.
* health: Add statement timeout to health check (PROJQUAY-7950)
Currently, our query to check team roles (part of the db health check) does not time out after a certain period but runs indefinitely. This causes worker timeouts after 30 seconds, which ends up in worker being killed by the master gunicorn process.
We limit the maximum execution time of the query to 5000 ms so that proper exception is raised if that timeout is reached.
PostgreSQL logs:
~~~
2024-09-16 09:38:56.431 EDT [115775] testuser@quayclone2 LOG: duration: 0.011 ms statement: BEGIN
2024-09-16 09:38:56.431 EDT [115775] testuser@quayclone2 LOG: duration: 0.034 ms statement: SET statement_timeout=5000
2024-09-16 09:38:56.431 EDT [115775] testuser@quayclone2 LOG: duration: 0.010 ms statement: COMMIT
2024-09-16 09:38:56.432 EDT [115775] testuser@quayclone2 LOG: duration: 0.004 ms statement: BEGIN
2024-09-16 09:38:56.432 EDT [115775] testuser@quayclone2 LOG: duration: 0.300 ms statement: SELECT "t1"."id", "t1"."name" FROM "teamrole" AS "t1" LIMIT 1
2024-09-16 09:38:56.433 EDT [115775] testuser@quayclone2 LOG: duration: 0.010 ms statement: COMMIT
2024-09-16 09:38:56.433 EDT [115775] testuser@quayclone2 LOG: duration: 0.005 ms statement: BEGIN
2024-09-16 09:38:56.433 EDT [115775] testuser@quayclone2 LOG: duration: 0.012 ms statement: SET statement_timeout=0
2024-09-16 09:38:56.433 EDT [115775] testuser@quayclone2 LOG: duration: 0.006 ms statement: COMMIT
~~~
Quay logs:
~~~
gunicorn-web stdout | 2024-09-16 13:38:56,412 [287] [DEBUG] [peewee.pool] Created new connection 127610088683136.
gunicorn-web stdout | 2024-09-16 13:38:56,417 [287] [DEBUG] [data.model.health] Validating database connection.
gunicorn-web stdout | 2024-09-16 13:38:56,418 [287] [INFO] [data.database] Connection pooling disabled for postgresql
gunicorn-web stdout | 2024-09-16 13:38:56,431 [287] [DEBUG] [peewee] ('SET statement_timeout=%s', (5000,))
gunicorn-web stdout | 2024-09-16 13:38:56,431 [287] [DEBUG] [data.model.health] Checking for existence of team roles, timeout 5000 ms.
gunicorn-web stdout | 2024-09-16 13:38:56,432 [287] [DEBUG] [peewee] ('SELECT "t1"."id", "t1"."name" FROM "teamrole" AS "t1" LIMIT %s', [1])
gunicorn-web stdout | 2024-09-16 13:38:56,433 [287] [DEBUG] [peewee] ('SET statement_timeout=0', None)
gunicorn-web stdout | 2024-09-16 13:38:56,434 [287] [DEBUG] [app] Ending request: urn:request:d039265b-414e-4d03-b29f-3e481286bf0f (/health/instance)...
~~~
* Fix generator function
Allows users to specify a regex tag pattern when creating namespace/repository autoprune policies via the new UI. Users will have the option to prune tags that only match the tag pattern or exclude tags that match the tag pattern.
during manifest push, we generate a map of blobs which
are part of the manifest layers. This is done using a
UNION query which can overload the worker if the
number of layers is too large. Instead, run each
query individually to prevent the crash
This allows a more refined search than just the repo name. When two
organizations contain the same name repo, e.g: org1/python and
org2/python, you can now search via org1/python to get the specific
result instead of both.
* storage: Disable pushes on registry (PROJQUAY-6870)
The current read-only option for Quay is not sometimes feasible, since it requires an insert of the service key and other manual config changes. For instance, if you want to just recalculate quota on the registry, but would like to allow all registry operations (including UI) without the possibility of pushes until recalculation is done, setting the whole registry `read-only` cannot be done since it makes the database read only as well.
This PR introduces a new flag called `DISABLE_PUSHES` which allows all registry operations to continue (changing tags, repo editing, robot account creation/deletion, user creation etc.) but will disable pushes of new images to the registry (i.e. backend storage will not change). If a registry already contains the image and a new tag is simply being added, that operation should succeed.
The following message would appear in the logs:
~~~
gunicorn-registry stdout | 2024-03-13 20:19:49,414 [369] [DEBUG] [endpoints.v2] sending response: b'{"errors":[{"code":"METHOD NOT ALLOWED","detail":{},"message":"Pushes to the registry are currently disabled. Please contact the administrator for more information."}]}\n'
gunicorn-registry stdout | 2024-03-13 20:19:49,414 [369] [INFO] [gunicorn.access] 172.17.0.1 - - [13/Mar/2024:20:19:49 +0000] "PUT /v2/ibazulic/mariadb/manifests/sha256:c4694ba424e0259694a5117bbb510d67340051f0bdb7f9fa8033941a2d66e53e HTTP/1.1" 405 169 "-" "skopeo/1.9.3"
nginx stdout | 172.17.0.1 (-) - - [13/Mar/2024:20:19:49 +0000] "PUT /v2/ibazulic/mariadb/manifests/sha256:c4694ba424e0259694a5117bbb510d67340051f0bdb7f9fa8033941a2d66e53e HTTP/1.1" 405 169 "-" "skopeo/1.9.3" (0.002 3813 0.002)
~~~
The flag defaults to `False` (pushes enabled), unless set otherwise.
* Removed constraint on storage replication when pushes are disabled
* Rebase
* Fix isort sorting
* Fix isort sorting #2
* Removed constraint on storage replication when pushes are disabled
* Rebase
* Remove constraint on storage replication worker
* Fix linting on config.py
Previous assumption made use of the config media type only, which is not the case
if a manifest's artifact type is explicitly set. i.e the config's media type and
artifact type are different, and the artifact type take precedence for filtering.
* database: adding subject_backfilled index to manifest table (PROJQUAY-7360) (#2963)
adding subject_backfilled index to manifest table
* Rebasing with main
* updating cypress data
* Rebasing with latest
* Forcing an empty commit.
* minor fixes
* Autoprune model changes
* fixing failing tests
* format fix
---------
Co-authored-by: Brandon Caton <bcaton@redhat.com>
* database: adding subject_backfilled index to manifest table (PROJQUAY-7360) (#2963)
adding subject_backfilled index to manifest table
* Rebasing with main
* updating cypress data
* fixing conflicts and rebasing with latest code
* adding tests
* Forcing an empty commit.
* Forcing an empty commit.
* skip_locked test fix
* adding tests
* minor fixes
---------
Co-authored-by: Brandon Caton <bcaton@redhat.com>
* registry: implements the OCI 1.1 referrers API
Migrations:
- Adds a subject column for lookup
- Adds a subject_backfilled column to track status of the backfilling
of existing manifests
- Adds a manifest_json column making use of postgres' JSONB support,
for future use.
Manifestsubjectbackfillworker: Indexes existing manifests for possible
existing subject field.
* Deprecate IGNORE_UNKNOWN_MEDIATYPES
* Cleanup