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>
When a cherry-pick PR merges to a redhat-* branch, this workflow
labels the original PR with backported/<branch> to track which
releases contain the fix.
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
The settings page showed "Organization" labels and helper text even
when viewing a user namespace. Changed to conditionally display
"Username" for users and "Organization" for organizations.
Co-authored-by: Claude <noreply@anthropic.com>
Normal users couldn't see their own namespace quota in the Organizations
list Size column. The backend already returns quota_report in /api/v1/user/
but the frontend wasn't using it. Added fallback to use current user's
quota_report when superuser data isn't available.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
Previously, all errors on the Organizations page showed "Org deletion failed"
as the modal title, even for unrelated operations like registry size
calculation. This was confusing for Global Readonly Superusers who saw
"Org deletion failed" when trying to calculate registry size.
Changes:
- Separated error states in OrganizationsList.tsx (deletionErr, registryCalcErr)
- Added separate ErrorModal for registry calculation with correct title
- Fixed RepositoriesList.tsx ErrorModal title to "Repository deletion failed"
- Added Cypress test to verify correct error modal title
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
The UI was showing the "Enable OIDC Team Sync" button even when
FEATURE_TEAM_SYNCING was disabled in the config. Added check for
config?.features?.TEAM_SYNCING before displaying the team sync button.
🤖 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(ui): ensure logout redirects to signin on network error (PROJQUAY-9792)
When the logout API call fails due to network error, the UI now properly
redirects to the signin page and clears the client-side session. Previously,
the user would be stuck on the current page with an error modal.
Changes:
- Move redirect and cleanup to finally block in logout handler
- Add optional chaining to user.username to prevent undefined errors
- Remove unused addDisplayError import
- Add comprehensive Cypress e2e tests for logout functionality
The finally block ensures client-side logout always succeeds, even when
the server is unreachable, improving security and user experience.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
Refactor PR auto-labeling using two-workflow pattern to handle fork PRs
securely. The label-status job is replaced with capture-pr-data (read-only)
and a new pr-status-labeler workflow that runs with write permissions via
workflow_run trigger.
Fixes 403 errors when labeling PRs from forks.
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
Stripe and StatusPage scripts were hardcoded in index.html, causing
85-second delays in air-gapped/restricted networks as browsers waited
for connection timeouts.
Created useExternalScripts hook to dynamically load scripts only when
BILLING feature is enabled. Scripts load asynchronously to prevent
blocking page render. On-premise deployments (BILLING=false) no longer
make external requests.
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>
Implement GitHub Actions workflow to automatically label pull requests
based on changed files, PR status, and target branch.
Features:
- Area labels (area/api, area/web-ui, etc.) based on file paths
- Status labels (needs-rebase, approved) based on PR state and reviews
- Backport labels (backport/redhat-3.x) for PRs targeting release branches
- Works with PRs from forks using pull_request_target trigger
The workflow uses actions/labeler for path-based labeling and
actions/github-script for dynamic status detection.
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Previously only organizations and the logged-in user showed avatars.
Now all users and superusers display avatars by passing avatar data
from the API response through component props.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
Organization and user quota settings pages are view-only, but were
displaying an empty "Add Limit" form row with disabled controls.
This creates visual clutter and implies users can add limits when
they cannot.
Conditionally render the "Add Limit" card only when !isReadOnly to
match the behavior of the old Angular UI. Update Cypress tests to
verify the form does not exist (not just disabled) in view-only mode.
fix(web): prevent redirect to signin after OIDC username confirmation (PROJQUAY-9835)
When users authenticated via OIDC and confirmed their username, they were
incorrectly redirected back to the signin page instead of the home page.
This occurred because the OAuth flow stored the signin page URL in localStorage
as the redirect target. After username confirmation, the app would read this
stored URL and redirect back to signin, creating a loop.
The fix checks if the stored redirect URL contains '/signin' and navigates to
the home page instead.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
* fix(web): validate quota value input accepts only numbers (PROJQUAY-9837)
Changed Storage Quota input from type="text" to type="number" to prevent
non-numeric characters from being entered. Also enhanced validation to
catch edge cases where parseFloat could incorrectly parse mixed values
like "300xxxx" as 300.
Co-authored-by: Claude <noreply@anthropic.com>
* chore: move quota test seeding
locally the test goes from 8 minutes to 55 seconds :)
Signed-off-by: Brady Pratt <bpratt@redhat.com>
---------
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
When FEATURE_SUPERUSERS_FULL_ACCESS=false, regular superusers could
create/update/delete quotas for other users' organizations (returning 201/200),
but couldn't view them (returning 403). This was a security bug - both read
and write operations should require FULL_ACCESS permission to access other
organizations' quotas.
Root cause: Organization quota write endpoints used SuperUserPermission().can()
instead of allow_if_superuser_with_full_access(), allowing any superuser to
modify other orgs' quotas regardless of the FULL_ACCESS setting.
Changes:
- endpoints/api/namespacequota.py: Replace SuperUserPermission().can() with
allow_if_superuser_with_full_access() in all quota write operations:
* OrganizationQuotaList.post() - create quota
* OrganizationQuota.put() - update quota
* OrganizationQuota.delete() - delete quota
* OrganizationQuotaLimitList.post() - create quota limit
* OrganizationQuotaLimit.put() - update quota limit
* OrganizationQuotaLimit.delete() - delete quota limit
- endpoints/api/test/test_superuser_full_access.py: Add comprehensive tests
for quota operations with and without FULL_ACCESS enabled (6 new tests)
Note: Superuser panel endpoints (/v1/superuser/users/<namespace>/quota)
were intentionally NOT changed - these are admin panel functions that should
work with basic superuser permission, consistent with other panel operations.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
`logger.exception` prints the stacktrace. However in this case there is
no stacktrace to output, as we are not inside an exception. This results
in log lines where the stack trace (`NoneType: None`) is confusing:
```
securityworker stdout | 2025-11-17 08:59:21,431 [102] [ERROR] [util.secscan.v4.api] Security scanner endpoint responded with non-200 HTTP status code: 500
securityworker stdout | NoneType: None
```
This commit fixes that
Signed-off-by: Frank Villaro-Dixon <frank@villaro-dixon.eu>
* fix(test): prevent MySQL deadlocks in parallel proxy model tests (PROJQUAY-0000)
Mark all registry proxy model test classes to run serially using
pytest-xdist group markers. These tests all use the same "quayio-cache"
organization and were causing MySQL deadlocks when run in parallel
across multiple workers with pytest -n auto.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(test): resolve Flask app naming conflict in quotaregistrysizeworker tests (PROJQUAY-0000)
Import Flask app with alias to avoid conflict with pytest 'app' fixture.
The test was using 'app.config' but 'app' resolved to a pytest fixture
definition instead of the Flask application object.
Follows the same pattern as test_securityscanningnotificationworker.py.
🤖 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 service account annotations to the ROSA template
This is required for IRSA auth, where we will replace that empty value with eks.amazonaws.com/role-arn = "foo"
When updating mirroring configuration fields like tag patterns, credentials
were being cleared because the password field is empty by default for security.
Modified UseMirroringConfig to conditionally exclude credentials from the
update payload when the password field is empty and updating existing config.
This matches the Angular UI behavior where only changed fields are sent.
Added Cypress tests to verify credentials are preserved when updating other
fields without changing the password, and that credentials are included when
explicitly updated.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
* ui: redirect new UI super user for fresh login when authentication type is OIDC (PROJQUAY-9748)
* test(ui): Fix Cypress tests for fresh login OIDC flow (PROJQUAY-9748)
- Fixed incorrect API endpoint (/api/v1/superuser/logs* instead of /api/v1/superuserlogs**)
- Fixed incorrect route (/usage-logs instead of /superuser/usagelogs)
- Added proper authentication setup using cy.loginByCSRF
- Used fixtures (config.json, superuser.json) following existing test patterns
- Simplified tests to 3 critical cases: OIDC redirect, query param preservation, Database modal
---------
Co-authored-by: harishsurf <hgovinda@redhat.com>
adds two new static information pages to the React UI:
- /about page with company info cards and bill-of-materials table
- /security page with security practices and features documentation
implementation includes:
- PatternFly components for consistent UI design
- sortable/filterable packages table with pagination
- actual CoreOS and Red Hat logos
- nginx routing configuration for new paths
- webpack config updates to handle image assets from src/assets
Signed-off-by: Brady Pratt <bpratt@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>