diff --git a/web/cypress/e2e/account-settings.cy.ts b/web/cypress/e2e/account-settings.cy.ts index 99fc3f4fa..03b9ec3ec 100644 --- a/web/cypress/e2e/account-settings.cy.ts +++ b/web/cypress/e2e/account-settings.cy.ts @@ -1090,6 +1090,50 @@ describe('Account Settings Page', () => { cy.url().should('include', 'tab=Settings'); }); + it('CLI Configuration - Password Not Set Alert (PROJQUAY-9898)', () => { + // Mock config with OIDC and Database authentication + cy.fixture('config.json').then((config) => { + config.config.AUTHENTICATION_TYPE = 'Database'; + config.external_login = [ + { + id: 'oidc', + title: 'OIDC Login', + icon: 'oidc-icon', + }, + ]; + cy.intercept('GET', '/config', config).as('getConfigWithOIDC'); + }); + + // Mock user with has_password_set: false (simulates OIDC user without password) + cy.intercept('GET', '/api/v1/user', (req) => { + req.continue((res) => { + res.body.has_password_set = false; + }); + }).as('getUserNoPassword'); + + cy.visit('/organization/user1?tab=Settings'); + cy.wait('@getConfigWithOIDC'); + cy.wait('@getUserNoPassword'); + + // Navigate to CLI configuration tab + cy.contains('CLI configuration').click(); + + // Verify info alert is displayed + cy.contains('Password not set').should('exist'); + cy.contains('A password must be set on your account').should('exist'); + + // Verify "Set password" button exists and works + cy.get('[data-testid="set-password-button"]').should('exist').click(); + + // Verify modal opens + cy.get('[data-testid="change-password-modal"]').should('be.visible'); + cy.contains('Change Password').should('exist'); + + // Close modal + cy.contains('button', 'Cancel').click(); + cy.get('[data-testid="change-password-modal"]').should('not.exist'); + }); + it('normalizes lowercase "settings" to correct tab', () => { cy.visit('/user/user1?tab=settings'); cy.wait('@getConfig'); diff --git a/web/src/routes/OrganizationsList/Organization/Tabs/Settings/CLIConfiguration.tsx b/web/src/routes/OrganizationsList/Organization/Tabs/Settings/CLIConfiguration.tsx index f44b125ca..5324d647c 100644 --- a/web/src/routes/OrganizationsList/Organization/Tabs/Settings/CLIConfiguration.tsx +++ b/web/src/routes/OrganizationsList/Organization/Tabs/Settings/CLIConfiguration.tsx @@ -24,6 +24,7 @@ import {GenerateEncryptedPassword} from 'src/components/modals/GenerateEncrypted import CreateApplicationTokenModal from 'src/components/modals/CreateApplicationTokenModal'; import RevokeTokenModal from 'src/components/modals/RevokeTokenModal'; import CredentialsModal from 'src/components/modals/CredentialsModal'; +import ChangePasswordModal from 'src/components/modals/ChangePasswordModal'; import { useFetchApplicationTokens, useApplicationToken, @@ -41,6 +42,7 @@ export const CliConfiguration = () => { const {user} = useCurrentUser(); const [encryptedPasswordModalOpen, toggleEncryptedPasswordModal] = useState(false); + const [changePasswordModalOpen, setChangePasswordModalOpen] = useState(false); const [createTokenModalOpen, setCreateTokenModalOpen] = useState(false); const [revokeTokenModalOpen, setRevokeTokenModalOpen] = useState(false); const [tokenToRevoke, setTokenToRevoke] = useState( @@ -114,6 +116,12 @@ export const CliConfiguration = () => { const showAppTokens = quayConfig?.features?.APP_SPECIFIC_TOKENS === true; const requireEncryptedAuth = quayConfig?.features?.REQUIRE_ENCRYPTED_BASIC_AUTH === true; + const hasOIDC = + quayConfig?.external_login && quayConfig.external_login.length > 0; + const isAuthTypeDatabase = + quayConfig?.config?.AUTHENTICATION_TYPE === 'Database'; + const shouldShowPasswordPrompt = + !user?.has_password_set && hasOIDC && isAuthTypeDatabase; return (
@@ -146,7 +154,7 @@ export const CliConfiguration = () => { - {user?.has_password_set ? ( + {!shouldShowPasswordPrompt ? ( )} @@ -358,6 +374,11 @@ export const CliConfiguration = () => { token={tokenToRevoke} /> + setChangePasswordModalOpen(false)} + /> + {/* View Token Credentials Modal */} {viewTokenModalOpen && ( <>