Fix PROJQUAY-6932: Add /logarchive endpoint to nginx config
The /logarchive endpoint was missing from the nginx location regex,
causing 404 errors when the new UI tries to retrieve archived build
logs with FEATURE_PROXY_STORAGE: false.
This fix adds /logarchive to the list of endpoints that are proxied
to the web_app_server, allowing archived build logs to be properly
retrieved through Quay's proxy.
Add UI components for managing immutability policies at both organization
and repository levels. Features include:
- Unified table displaying namespace and repository policies with scope
- Inline editing for policies with pattern validation
- "Add Policy" button positioned next to title header
- Inherited namespace policies shown in repository settings
- Comprehensive Playwright e2e tests
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
Add REST API for managing immutability policies at organization and
repository levels. Integrate policy evaluation into tag creation.
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
Add database models, migration, and CRUD functions for namespace and
repository immutability policies. Policies define regex patterns that
automatically mark matching tags as immutable when created.
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
* feat(mirror): add architecture-filtered mirroring support (PROJQUAY-10257)
When architecture_filter is set on a mirror config, copy only the
specified architectures instead of using the --all flag. This preserves
the original manifest list digest for OpenShift compatibility by pushing
the original manifest bytes directly after copying the filtered
architecture manifests.
Key changes:
- Add inspect_raw() and copy_by_digest() methods to SkopeoMirror
- Create manifest_utils.py for manifest list parsing and filtering
- Modify perform_mirror() to use architecture filtering when configured
- Add comprehensive unit tests for the new functionality
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(mirror): default media_type to OCI index when None (PROJQUAY-10257)
Prevent InvalidHeader error when get_manifest_media_type() returns None
by defaulting to OCI_IMAGE_INDEX_CONTENT_TYPE in the Content-Type header
of the manifest push request.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
the failure logic was incorrect for the setup-quay action, since it is
composite it only ran those steps on failure _inside_ of the action.
This adds a new action and calls it on failure
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Add label handler for quay.immutable manifest label that automatically
marks associated tags as immutable when images are pushed with
LABEL quay.immutable=true in their Dockerfile. Only "true" value
(case-insensitive) triggers immutability; other values are ignored.
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
Extend the mirror configuration API to accept and return architecture_filter
settings, allowing users to configure which architectures should be mirrored
from multi-architecture images via the REST API.
Changes:
- Add architecture_filter to API schema and GET response
- Handle architecture_filter in POST (create) and PUT (update) methods
- Validate architecture values against allowed set (amd64, arm64, ppc64le, s390x)
- Add comprehensive API tests for the new field
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* mirror: Add FEATURE_ORG_MIRROR feature flag (PROJQUAY-1266)
Add organization-level repository mirroring feature flag to enable
the new org mirroring functionality. Feature is disabled by default.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* mirror: Add GET endpoint for org mirror config (PROJQUAY-1266)
Implements the GET /v1/organization/<org>/mirror endpoint to retrieve
organization-level mirror configuration. Includes business logic layer
with get_org_mirror_config() and comprehensive unit tests.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* mirror: Add POST endpoint for org mirror config (PROJQUAY-1266)
Add create endpoint for organization-level mirror configuration:
- POST /v1/organization/<orgname>/mirror creates new config
- Validates robot account ownership and credentials
- Returns 201 on success, 409 if config already exists
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* mirror: Add DELETE endpoint for org mirror config (PROJQUAY-1266)
Add delete endpoint for organization-level mirror configuration:
- DELETE /v1/organization/<orgname>/mirror removes config
- Also deletes all associated discovered repositories
- Returns 204 on success, 404 if config doesn't exist
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* mirror: Add PUT endpoint for org mirror config (PROJQUAY-1266)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix test failure
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Implement React/PatternFly UI for tag immutability features:
- Lock icon display for immutable tags with tooltip
- Make immutable action in kebab menu
- Remove immutability action for superusers
- Confirmation modal for toggling immutability
- Disable delete/expiration actions for immutable tags
- Bulk actions: make immutable, skip immutable on delete
- All UI gated behind IMMUTABLE_TAGS feature flag
- Playwright e2e tests for all functionality
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Eliminate N+1 lazy-load queries by accepting user IDs instead of User objects.
## Problem
When checking organization membership for permissions, the old code triggered
a lazy-load query for EACH permission just to extract the user ID:
```python
# Old caller pattern - triggers N lazy-loads!
users_filter = {perm.user for perm in repo_perms}
org_members = get_organization_member_set(org, users_filter=users_filter)
```
For an endpoint returning 50 permissions, this caused 50 extra SELECT queries.
## Solution
Accept user IDs directly via `user_ids_filter` parameter:
```python
# New pattern - no lazy-loads!
user_ids_filter = {perm.user_id for perm in repo_perms}
org_members = get_organization_member_set(org, user_ids_filter=user_ids_filter)
```
The `user_id` foreign key field is already populated on the model - accessing
it doesn't require a database query.
## Changes
- Renamed `users_filter` → `user_ids_filter` parameter
- Accept set of integer IDs instead of User objects
- Updated 6 call sites in permission_models_pre_oci.py and prototype.py
- Added comprehensive test coverage
## Performance Impact
For get_repo_permissions_by_user with 50 permissions:
- Before: 50 lazy-load queries
- After: 0 queries
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add _autoSkipByContainer auto-fixture that automatically skips tests
tagged with @container when no container runtime (podman/docker) is
available. This follows the existing pattern used by _autoSkipByFeature
and _autoSkipByAuth.
Changes:
- Add cachedContainerAvailable worker fixture (checked once per worker)
- Add containerAvailable test fixture for manual access
- Add _autoSkipByContainer auto-fixture for @container tag
- Update notification-drawer, breadcrumbs, and tag-details-layers tests
to use the new auto-skip instead of manual test.skip() calls
- Document @container tag usage in MIGRATION.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
When a manifest list was pushed with multiple tags, only the first tag
got the expiration from child manifest labels. Subsequent tags showed
"Never" because list_manifest_labels() only checked labels directly on
the manifest list, not on child manifests.
Added _get_expiry_label_for_manifest() helper that properly queries
child manifest labels for manifest lists, matching the intersection
logic used during initial manifest creation.
Co-authored-by: Claude <noreply@anthropic.com>
Add new endpoint for clients to query registry sparse manifest support:
- GET /api/v1/registry/capabilities returns JSON with sparse_manifests
capability info (supported, required_architectures, optional allowed)
- V2 base endpoint now includes X-Sparse-Manifest-Support and
X-Required-Architectures headers for OCI compliance
- Endpoint accessible without authentication for client discovery
This enables oc-mirror and skopeo to detect sparse manifest support
before attempting filtered multi-architecture mirroring.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Replace custom connect() wrapper with peewee's built-in pragmas
parameter to fix SQLite connection failure after OMR upgrade.
The previous implementation called execute_sql() inside connect(),
which triggered retry logic on failure, causing infinite recursion
and connection state corruption. Using peewee's native mechanism
applies PRAGMAs via the raw cursor before connect() returns.
Co-authored-by: Claude <noreply@anthropic.com>
Add database schema for organization-level repository mirroring feature that enables syncing all repositories from a source namespace into a target Quay organization.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Expose tag immutability through the existing tag REST API endpoint.
This adds:
- immutable field to PUT /api/v1/repository/{repo}/tag/{tag}
- TagImmutable 409 exception for blocked operations
- immutable field in tag list responses
- Exception handling for DELETE and PUT on immutable tags
Write permission required to lock, admin required to unlock.
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
* test(web): delete migrated cypress tests
Signed-off-by: Brady Pratt <bpratt@redhat.com>
* test(web): migrate org-settings.cy.ts to Playwright
Migrate organization settings e2e tests from Cypress to Playwright
following the MIGRATION.md patterns. This removes all mocks/intercepts
and uses real API interactions with automatic cleanup via the api fixture.
Tests migrated:
- General settings: validates email format and saves org settings
- Billing information: validates invoice email and receipt checkbox
- CLI token visibility: verifies CLI tab hidden for organizations
The tag expiration picker test was not migrated as it was incorrectly
testing a user account (/organization/user1) rather than an organization.
This functionality is already covered in account-settings.spec.ts.
Consolidation: 4 Cypress tests → 3 Playwright tests
Co-authored-by: Claude <noreply@anthropic.com>
---------
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
Add mediaType field to the metadata logged for manifest push and pull
operations. This provides visibility into what manifest format was used
when pulling or pushing images (e.g., Docker v2, OCI v1).
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
fix(endpoints): route /health endpoint to web app server (PROJQUAY-10155)
The nginx regex pattern /health/(.*) required at least one character
after /health/, causing bare /health requests to return 404 by falling
through to static file handling. Changed to /health(/.*)? to make the
trailing path optional.
Co-authored-by: Claude <noreply@anthropic.com>
* mirror: Add architecture filter to RepoMirrorConfig (PROJQUAY-10255)
Adds architecture_filter field to filter multi-arch images during mirroring.
Supports amd64, arm64, ppc64le, s390x, 386, and riscv64 architectures.
Empty/null value mirrors all architectures (backwards compatible).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* shrink valid arches for repo mirroring to only the necessary ones
* run formatter on file
* fix unit test
* validate arch before setting
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Migrate web/cypress/e2e/usage-logs.cy.ts to Playwright, converting
13 Cypress tests to 10 consolidated Playwright tests across two files:
- playwright/e2e/usage-logs.spec.ts (6 tests): Organization and
repository usage logs including chart toggle, log export, email
validation, filtering, and Splunk error handling
- playwright/e2e/superuser/usage-logs.spec.ts (4 tests): Superuser
usage logs page with columns, chart toggle, filtering, and Splunk
error handling
Key changes:
- Add data-testid attributes to UsageLogsExportModal (export button,
confirm button, email input), UsageLogsTable (filter input), and
both UsageLogs components (chart toggle button)
- Use real API data instead of mocking (except Splunk 501 errors)
- Use getByPlaceholder for SearchInput since PatternFly wraps the
actual input element
- Handle duplicate error messages with .first() selector
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit implements the core enforcement layer for tag immutability,
which prevents immutable tags from being deleted, overwritten, or
permanently removed from the time machine.
Changes:
- Add ImmutableTagException class with tag_name, operation, and
repository_id fields for detailed error reporting
- Enforce immutability in delete_tag() - raises exception for immutable tags
- Enforce immutability in retarget_tag() - prevents overwriting immutable
tags, respects raise_on_error parameter
- Enforce immutability in remove_tag_from_timemachine() - blocks permanent
deletion for both alive and expired immutable tags
- Add is_tag_immutable() - returns True/False/None for tag lookup
- Add set_tag_immutable() - updates immutability with optimistic locking
The immutable column, indexes, and log entry kind were previously added
in migration 5b8dc452f5c3. This commit adds the enforcement logic and
utility functions that use those database structures.
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
* feat: Add FEATURE_SPARSE_INDEX config for sparse manifest index support
When enabled, manifests in an index that cannot be loaded will be
skipped if their architecture is not in the SPARSE_INDEX_REQUIRED_ARCHS
list. This allows for sparse manifest indexes where not all architectures
are required to be present.
New config options:
- FEATURE_SPARSE_INDEX: Enable sparse manifest index support (default: False)
- SPARSE_INDEX_REQUIRED_ARCHS: List of architectures that must be present
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test(web): @auth:X auto-skip tag pattern
Add a new auto-fixture `_autoSkipByAuth` that automatically skips tests
based on @auth:X tags when the auth type doesn't match. This mirrors the
existing @feature:X pattern for feature flags.
Changes:
- Add _autoSkipByAuth fixture to TestFixtures type
- Implement auto-fixture that extracts @auth:X tags and calls
skipUnlessAuthType automatically
- Migrate account-settings.spec.ts to use @auth:Database tags on
describe blocks instead of manual test.skip() calls
- Remove 6 manual skipUnlessAuthType calls and unused imports
This allows tests to declare auth requirements declaratively via tags
rather than imperatively in each test body.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Brady Pratt <bpratt@redhat.com>
* test(web): fix matching multiple elements
Signed-off-by: Brady Pratt <bpratt@redhat.com>
---------
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Migrate organization proxy cache configuration tests following
the MIGRATION.md patterns. Consolidated 4 Cypress tests into 3
Playwright tests covering:
- Anonymous proxy cache lifecycle (create, verify, delete)
- Form validation with invalid credentials
- Tab visibility for user namespaces
Adds ProxyCacheConfig interface and API methods to the Playwright
API client for proxy cache operations.
🤖 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(web): hide robot creation when ROBOTS_DISALLOW is enabled (PROJQUAY-7313)
When ROBOTS_DISALLOW is enabled, robot creation UI elements are now
hidden instead of allowing users to click them and receive an error.
This provides better UX by preventing actions that cannot succeed.
Changes:
- Expose ROBOTS_DISALLOW to frontend via CLIENT_WHITELIST
- Hide "Create robot account" option in team wizard dropdown
- Hide "Create robot account" button in Robot Accounts tab
- Add defensive error handling in AddTeamMember.tsx
Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Brady Pratt <bpratt@redhat.com>
* fix(web): use exact match for heading locator in superuser test (PROJQUAY-7313)
The Messages page heading locator was matching both "Messages" and
"No Messages" headings, causing a strict mode violation. Adding
exact: true ensures only the exact heading text is matched.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
Remove the config-tool editor UI while preserving the validation CLI
functionality. The editor UI is no longer needed as configuration is now
managed through other means.
Changes:
- Delete pkg/lib/editor/ directory with all Angular UI components
- Delete editor command and related Go code
- Remove config-editor from supervisord and deployment configs
- Simplify Dockerfile without JS build stage
- Remove Cypress E2E tests from GitHub workflow
- Clean up unused dependencies
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* test(web): migrate superuser-org-actions.cy.ts to Playwright
Migrate Cypress E2E tests for superuser organization actions to Playwright
following the project's MIGRATION.md guidelines.
Changes:
- Add new test file: playwright/e2e/superuser/org-actions.spec.ts
- Consolidate 12 Cypress tests into 5 focused Playwright tests
- Use real API data instead of mocked fixtures
- Auto-cleanup via TestApi fixture
Test coverage:
- Superuser sees actions column and options menu for organizations
- Regular user does not see organization options menu
- Superuser can rename organization
- Superuser can delete organization
- Superuser can take ownership of organization
Skipped from migration:
- Quota menu tests (already covered by quota.spec.ts)
- Fresh login requirement tests (low value, complex to mock)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test(web): set superuser feature tag
Signed-off-by: Brady Pratt <bpratt@redhat.com>
* test(web): migrate superuser-messages.cy.ts to Playwright
Migrate superuser messages tests from Cypress to Playwright, consolidating
14 original tests into 6 focused, value-add tests.
Tests cover:
- Non-superuser redirect to organization page
- Full CRUD flow: create, view, and delete messages via UI
- Error state when API fails to load messages
- Loading spinner during message fetch
- Read-only superuser can access and view messages
- Read-only superuser sees disabled create/delete actions
Infrastructure additions:
- Add message() method to TestApi with auto-cleanup
- Add CreatedMessage interface for type safety
- Add SUPERUSERS_FULL_ACCESS feature tag
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test(web): migrate superuser-user-management.cy.ts to Playwright
Consolidates 29 Cypress tests into 11 Playwright tests covering
superuser user management functionality.
Changes:
- Add CreatedUser interface and user() method to TestApi for
user creation with auto-cleanup
- Add createUserAsSuperuser() to API client using superuser endpoint
- Add QuayAuthType and skipUnlessAuthType() helper for auth-type
conditional tests
- Create user-management.spec.ts with consolidated tests
Tests cover:
- Create user via UI (Database/AppToken auth only)
- User access control based on user type
- Change email and password (Database auth only)
- Toggle user status (disable/enable)
- Delete user
- Take ownership (convert user to org)
- Fresh login error handling with mocked responses
- Send recovery email (MAILING feature)
- Auth type visibility
Key patterns:
- Uses search to find users in paginated list
- page.route() only for error scenarios per MIGRATION.md
- skipUnlessAuthType() for auth-dependent tests
- @feature:SUPERUSERS_FULL_ACCESS tag for all tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(web): delete more migrated cypress tests
Signed-off-by: Brady Pratt <bpratt@redhat.com>
* test(web): migrate superuser-framework Cypress test to Playwright
Consolidates 7 Cypress tests into 4 Playwright tests covering:
- Superuser navigation to all superuser pages
- Navigation section visibility and expansion
- Organizations table Settings column and actions menu
- Regular user restrictions and redirects
Uses real superuserPage/authenticatedPage fixtures instead of mocking.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(web): migrate superuser-service-keys Cypress test to Playwright
Consolidates 17 Cypress tests into 5 Playwright tests:
- non-superuser redirect to organization page
- superuser CRUD lifecycle (create, view, search, update, delete)
- error handling when create fails
- read-only superuser permission restrictions
- bulk select and delete operations
Adds service key API methods to Playwright test utilities:
- getServiceKeys, createServiceKey, updateServiceKey, deleteServiceKey
- TestApi.serviceKey() with auto-cleanup support
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test(web): migrate superuser-change-log Cypress test to Playwright
Migrate superuser-change-log.cy.ts to Playwright with test consolidation:
- 7 original tests reduced to 2 focused tests
- Access control tests already covered by framework.spec.ts
- Loading spinner and empty state tests skipped (low value)
- Uses real API calls except for error state (acceptable mock)
- No PatternFly class dependencies, uses role-based selectors
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test(web): migrate superuser-usage-logs Cypress test to Playwright
- Consolidate 7 Cypress tests into 2 Playwright tests
- Access control tests already covered by framework.spec.ts
- Add data-testid="usage-logs-table" to UsageLogsTable component
- Tests verify: page header, date pickers, chart toggle, table loading,
and filter functionality
- Use structural assertions for parallel test safety
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Brady Pratt <bpratt@redhat.com>
* test(web): remove unneeded comments
Signed-off-by: Brady Pratt <bpratt@redhat.com>
---------
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>