Implement OpenShift OAuth as an authentication provider for Quay,
enabling users to login via OpenShift and sync groups to teams.
- Add OpenShiftOAuthService with RFC 8414 discovery and User API
- Add opaque token validation for non-JWT OpenShift tokens
- Add OpenShiftUsers class with group iteration for team sync
- Add OPENSHIFT_LOGIN_CONFIG schema and "OpenShift" auth type
- Extend team sync to support "openshift" and "oidc" services
🤖 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>
Replace hardcoded expiration date '2025-12-31T23:59' with dynamically
generated future date. The tests were failing with "Expiration date
must be in the future" validation error since it's now 2026.
Added getFutureExpirationDate() helper that returns a date 1 year
from now in the required datetime-local format.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* test(web): migrate logout Cypress test to Playwright
Uses unique temporary users per test to avoid session invalidation
conflicts when running in parallel. Quay's signout endpoint invalidates
all sessions for a user, which would break parallel tests sharing users.
Also documents the session-destructive test pattern in MIGRATION.md.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(web): migrate mirroring Cypress test to Playwright
Migrates web/cypress/e2e/mirroring.cy.ts to Playwright following the
MIGRATION.md guide. Consolidates 18 Cypress tests into 5 Playwright
tests using real API calls instead of mocks.
Changes:
- Add mirroring API utilities to client.ts (changeRepositoryState,
createMirrorConfig, getMirrorConfig, updateMirrorConfig,
triggerMirrorSync, cancelMirrorSync)
- Create mirroring.spec.ts with 5 consolidated tests covering:
- State warning and form visibility
- New mirror configuration lifecycle
- Existing mirror configuration management
- Sync operations
- Error handling (only mock used for 400 error scenario)
- Update MIGRATION.md checklist (8/54, 15%)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(web): add TestApi fixture with auto-cleanup for Playwright tests
Introduce a TestApi class that wraps ApiClient and automatically tracks
created resources for cleanup after each test. This eliminates the need
for manual beforeEach/afterEach cleanup patterns and ensures resources
are always cleaned up even when tests fail.
Changes:
- Add TestApi class to fixtures.ts with methods for creating orgs,
repos, teams, robots, and prototypes with auto-cleanup
- Add api and superuserApi fixtures that provide TestApi instances
- Migrate all committed Playwright tests to use the new api fixture
- Update MIGRATION.md with documentation for the new pattern
The api fixture provides:
- api.organization(prefix?) - creates org with unique name
- api.repository(namespace?, prefix?, visibility?) - creates repo
- api.team(orgName, prefix?, role?) - creates team
- api.robot(orgName, prefix?, description?) - creates robot
- api.prototype(orgName, role, delegate, activatingUser?) - creates default permission
- api.setMirrorState(namespace, repoName) - sets repo to MIRROR state
- api.raw - access underlying ApiClient for non-tracked operations
Resources are cleaned up in reverse order (LIFO) after each test.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(web): remove migrated tests
Signed-off-by: Brady Pratt <bpratt@redhat.com>
* test(web): auto-skip Playwright tests based on @feature: tags
Adds an auto-fixture to fixtures.ts that automatically skips tests
when their @feature:X tags reference disabled Quay features. This
eliminates duplication between tags and manual test.skip() calls.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(web): set axios baseURL at module level for all routes (PROJQUAY-0000)
Previously axios baseURL was only set inside StandaloneMain component,
causing requests from /signin and other auth routes to go to the wrong
URL (localhost:9000 instead of localhost:8080).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(web): use cy.session() for Cypress authentication
Replace manual CSRF token + loginByCSRF pattern with cy.session()
for proper session handling. Fixes race condition where React app
made API calls before Cypress login completed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(web): fix notification drawer test flakiness with toPass polling
Use Playwright's toPass to poll for notification appearance instead of
a single assertion. The backend may take time to process push
notifications, so reload and retry until the notification is visible.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
* chore(pre-commit): match black version with requirements-dev
* run `make black` against repo
* ci: switch to black 24.4.2
* fix: py312
* fix: flake8 errors
* fix: flake8 conflicts
* chore: add git blame ignore revs file
* chore: update Makefile DOCKER variable and pre-commit version (PROJQUAY-10071)
Replace hardcoded docker command with $(DOCKER) variable and update
pre-commit installation to version 4.5.0 in Makefile and documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Enable GitHub Actions cache for Docker builds to speed up Playwright
E2E test runs. Uses mode=max to cache all intermediate layers from
the multi-stage Dockerfile.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
* test(web): migrate notification-drawer Cypress test to Playwright
Convert the notification-drawer.cy.ts test from mocked API responses to
real API interactions. The test now creates a repository, configures a
quay_notification for repo_push events, pushes an image to trigger the
notification, then validates the drawer UI behavior (open, read, delete).
Adds createRepositoryNotification method to the Playwright API client.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(web): migrate default-permissions Cypress test to Playwright
- Add robot and prototype API methods to test client
- Fix undefined allMembers bug in CreateTeamWizard.tsx
- Fix missing return value in AddTeamMember.tsx setDeletedTeamMembers
- Tests run in parallel with isolated state per test
Co-authored-by: Claude <noreply@anthropic.com>
* test(web): migrate external-scripts Cypress test to Playwright
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* test(web): consolidate Playwright API utils into ApiClient class
Migrate from individual function-based API utilities to a unified
ApiClient class with CSRF token caching. This eliminates redundant
token requests when tests make multiple API calls.
Key changes:
- Create ApiClient class with cached CSRF token
- Add signIn() method for authentication flows
- Update all test files to use ApiClient instances
- Remove individual api/csrf.ts, organization.ts, repository.ts,
team.ts, user.ts files in favor of single client.ts
- Update fixtures.ts to use ApiClient for login
🤖 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): run playwright on small machine for chrome only
while we are migrating, swap things around to save time and money
Signed-off-by: Brady Pratt <bpratt@redhat.com>
---------
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
* test(web): migrate theme-switcher tests from Cypress to Playwright
Replace Cypress theme-switcher.cy.ts with Playwright equivalent.
Uses real API calls instead of mocked intercepts per migration guide.
Tests theme toggle visibility, persistence, and browser color scheme
detection via Playwright's emulateMedia API.
- Add data-testid to user-menu-toggle for stable selector
- Create playwright/e2e/ui/theme-switcher.spec.ts with 3 test cases
- Update MIGRATION.md checklist (2/54 migrated)
- Delete original Cypress test file
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(web): migrate breadcrumbs tests from Cypress to Playwright
Add organization, team, and container API utilities to support the
breadcrumbs test migration. Tests cover:
- List pages (no breadcrumbs)
- Organization, repository, tag, and team page breadcrumbs
- Edge cases with same-name org/repo/team combinations
The container utility supports both podman and docker for pushing
test images when testing tag breadcrumbs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test(web): migrate overview tests from Cypress to Playwright
Migrates web/cypress/e2e/overview.cy.ts to Playwright with 4 tests:
- Expandable dropdowns show content
- External links navigate correctly
- Tabs switch content correctly
- Purchase plans dropdown shows pricing options
Uses getByRole for tab selection instead of PatternFly-generated IDs.
🤖 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(ci): ignore test files for web preview
no need in deploying the web preview if only tests or docs are modified
Signed-off-by: Brady Pratt <bpratt@redhat.com>
---------
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
Each LDAP user search was creating two connections: one just to verify
admin credentials worked, then another for the actual search. This
doubled the load on LDAP servers. Consolidated into a single connection
block with proper error handling for INVALID_CREDENTIALS.
Affected methods:
- _ldap_user_search(): Core search used by most LDAP operations
- at_least_one_user_exists(): User existence checks
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
* test(ci,web): add Playwright report deployment to Surge.sh
- Switch Playwright workflow to use large self-hosted runner
(quay-001-large-ubuntu-24-x64) for faster execution
- Add new workflow to deploy HTML reports to Surge.sh
- Post PR comments with test status and link to full report
- Report accessible at quay-playwright-pr-{PR_NUMBER}.surge.sh
- Add cleanup workflow to teardown report on PR close
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore(ci): drop gha caching
it is slow and no tworking
Signed-off-by: Brady Pratt <bpratt@redhat.com>
* test(ci,web): cache Playwright browser binaries
Cache ~/.cache/ms-playwright between CI runs to avoid re-downloading
browsers on every workflow run. Cache key is based on Playwright
version from package-lock.json and auto-invalidates on version bumps.
On cache hit, only OS dependencies are installed (~45s).
On cache miss, full browser + deps install occurs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Brady Pratt <bpratt@redhat.com>
---------
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
* chore: add Playwright e2e test infrastructure
Add Playwright test framework with custom fixtures for authenticated
contexts, API utilities for test data management, and repository
delete test as initial migration from Cypress.
Key additions:
- global-setup.ts: Creates admin, testuser, readonly test users
- fixtures.ts: Pre-authenticated page/request fixtures by role
- utils/api.ts: CRUD utilities for repositories
- MIGRATION.md: Guide for migrating Cypress tests to Playwright
- repository-delete.spec.ts: First migrated test with full cleanup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Brady Pratt <bpratt@redhat.com>
* chore: update web/.dockerignore
exclude tests from being included in the intermediate build - this
should improve caching when only tests change
Signed-off-by: Brady Pratt <bpratt@redhat.com>
* chore: add pre-commit check to block new cypress tests
Signed-off-by: Brady Pratt <bpratt@redhat.com>
---------
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
The download button on the Build Logs page in the new React UI was
returning 404 because /buildlogs/<build_uuid> requests were not being
proxied to the Flask backend. This adds /buildlogs to the nginx proxy
pass regex pattern so the endpoint is accessible when using React UI.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
This commit adds a cyan "Global Readonly Superuser" label to identify
global readonly superusers in the Organizations list, making it easier
for administrators to distinguish them from regular superusers.
Backend change: Updated User.to_dict() to include global_readonly_super_user
property in the /api/v1/superuser/users/ API response.
Frontend changes: Propagated the property through the data flow and added
label rendering with cyan color to visually distinguish from regular
superusers (blue).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Build IDs are UUIDs displayed as hex strings. The previous localeCompare
sorting treated them lexicographically, causing incorrect sort order.
Now detects hex/UUID patterns and sorts by parsing the first 8 hex
digits numerically.
Co-authored-by: Claude <noreply@anthropic.com>
ClipboardCopy children were passed as JSX expressions which creates an
array of React nodes. PatternFly's ClipboardCopy may join array children
with commas when extracting text, causing pull commands like:
"docker pull ,hostname,/,org,/,repo,:,tag"
Using template literals ensures a single string child is passed,
preventing the comma issue.
Co-authored-by: Claude <noreply@anthropic.com>
Use mutateAsync instead of mutate so Promise errors propagate to the
calling code. Previously, mutate() was fire-and-forget, causing success
notifications even when the API returned 400 errors.
Remove duplicate alert notification - error is shown inline in the modal.
Co-authored-by: Claude <noreply@anthropic.com>
Remove reCAPTCHA integration from the password recovery flow
as the feature has been deprecated.
Changes:
- Delete ReCaptcha component
- Remove recaptcha token handling from Signin page
- Simplify UsePasswordRecovery hook
- Remove react-google-recaptcha dependencies
- Clean up test fixtures and CSS
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
The formatSize() function used a falsy check which treated 0 as invalid,
returning "N/A" instead of formatting it. Now 0 displays as "0.00 KiB"
matching the legacy UI behavior.
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
when using OIDC authentication and the user has no password set, display
an info alert with a "Set password" button to guide users through setting
up their CLI password
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
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(web): enable user self-service email changes when FEATURE_MAILING enabled (PROJQUAY-9879)
This commit fixes the issue where users received 401 Unauthorized errors
when attempting to update their email address in the new React UI when
FEATURE_MAILING is enabled.
Root cause: ChangeEmailModal was using the superuser-only endpoint
/api/v1/superuser/users/{username}, which regular users cannot access.
Changes:
- Added useChangeEmail hook in UseCurrentUser.ts that calls the correct
user self-service endpoint /api/v1/user/ for email updates
- Modified ChangeEmailModal to support dual modes (superuser vs user)
with isSuperuserMode prop for backward compatibility
- Updated GeneralSettings to display email as clickable link when
FEATURE_MAILING is enabled, opening the modal for email changes
- Pre-fill modal with current email address for better UX
- Added validation to prevent submitting the same email address
- Added 8 comprehensive Cypress e2e tests covering email change flows
The fix implements the proper email verification workflow where users
receive a verification email and must confirm before the change is applied.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fixing tests
* resolving coderabbit suggestion
---------
Co-authored-by: Claude <noreply@anthropic.com>
When images are pulled by digest only (not by tag), the API endpoint
was returning 0 for manifest_pull_count because it ignored manifest_stats
when tag_stats was None.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
Global readonly superusers could click Create Message and Service Key
buttons which then failed with 403 errors. These buttons are now disabled
using the existing useSuperuserPermissions hook's canModify flag.
Co-authored-by: Claude <noreply@anthropic.com>